/* * UNFS3 brute force file search * (C) 2004, Pascal Schmidt * see file LICENSE for license details */ #include "config.h" #include #include #include #include #include #include #include #include #ifdef HAVE_MNTENT_H #include #endif #ifdef HAVE_SYS_MNTTAB_H #include #endif #include "nfs.h" #include "fh.h" #include "daemon.h" /* * these are the brute-force file searching routines that are used * when both the filehandle cache and the hashed path inside the * filehandle are unable to locate the file * * this can only happen if a file was rename(3)'d across directories * * these routines are slow, but better than returning ESTALE to * clients */ #if HAVE_MNTENT_H == 1 || HAVE_SYS_MNTTAB_H == 1 /* * locate file given prefix, device, and inode number */ static int locate_pfx(const char *pfx, uint32 dev, uint64 ino, char *result) { char path[NFS_MAXPATHLEN]; backend_dirstream *search; struct dirent *ent; backend_statstruct buf; int res; search = opendir(pfx); if (!search) return FALSE; while ((ent = readdir(search))) { if (strlen(pfx) + strlen(ent->d_name) + 2 >= NFS_MAXPATHLEN) continue; sprintf(path, "%s/%s", pfx, ent->d_name); res = backend_lstat(path, &buf); if (res != 0) continue; /* check for matching object */ if (buf.st_dev == dev && buf.st_ino == ino) { strcpy(result, path); st_cache = buf; st_cache_valid = TRUE; closedir(search); return TRUE; } /* descend into directories with same dev */ if (buf.st_dev == dev && S_ISDIR(buf.st_mode) && strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { res = locate_pfx(path, dev, ino, result); if (res == TRUE) { closedir(search); return TRUE; } } } closedir(search); return FALSE; } #endif /* * locate file given device and inode number * * slow fallback in case other filehandle resolution functions fail */ char *locate_file(U(uint32 dev), U(uint64 ino)) { #if HAVE_MNTENT_H == 1 || HAVE_SYS_MNTTAB_H == 1 static char path[NFS_MAXPATHLEN]; FILE *mtab; struct stat buf; int res; #endif #ifdef HAVE_MNTENT_H struct mntent *ent; #endif #ifdef HAVE_SYS_MNTTAB_H struct mnttab ent; int found = FALSE; #endif if (!opt_brute_force) return NULL; #ifdef HAVE_MNTENT_H mtab = setmntent("/etc/mtab", "r"); if (!mtab) return NULL; /* * look for mtab entry with matching device */ while ((ent = getmntent(mtab))) { res = lstat(ent->mnt_dir, &buf); if (res == 0 && buf.st_dev == dev) break; } endmntent(mtab); /* found matching entry? */ if (ent) { res = locate_pfx(ent->mnt_dir, dev, ino, path); if (res == TRUE) return path; } #endif #ifdef HAVE_SYS_MNTTAB_H mtab = fopen("/etc/mnttab", "r"); if (!mtab) return NULL; /* * look for mnttab entry with matching device */ while (getmntent(mtab, &ent) == 0) { res = lstat(ent.mnt_mountp, &buf); if (res == 0 && buf.st_dev == dev) { found = TRUE; break; } } fclose(mtab); /* found matching entry? */ if (found) { res = locate_pfx(ent.mnt_mountp, dev, ino, path); if (res == TRUE) return path; } #endif return NULL; }