Date: Thu, 07 May 2009 20:07:46 -0700 From: Tim Kientzle <kientzle@freebsd.org> To: "'freebsd-hackers@freebsd.org'" <freebsd-hackers@freebsd.org> Subject: fdescfs brokenness Message-ID: <4A03A202.2050101@freebsd.org>
next in thread | raw e-mail | index | archive | help
Colin Percival recently pointed out some issues with tar and fdescfs. Part of the problem here is tar; I need to rethink some of the traversal logic. But fdescfs is really wonky: * This is a nit, but: ls /dev/fd/18 should not return EBADF; it should return ENOENT, just like any other reference to a non-existent filename. (Just because a filename reflects a file descriptor does not mean it is a file descriptor.) * The fairly routine recursive directory walker below gets hung in fdescfs. It appears that the two opendir() invocations active at the same time interfere with each other. * A similar chdir()-based version of the directory walker below breaks badly; you can chdir() into a directory under /dev/fd, but you can't chdir("..") to get back out of it. (This is the particular problem that tar is running afoul of.) * Running "find /dev/fd" generates bogus ENOENT errors because you can opendir() a directory inside of /dev/fd, and read the entries, but you can't access those entries because path searches don't work through fdescfs. I think the right solution here is to add a VOP_ACCESS handler to fdescfs that bars all access to directory nodes under /dev/fd. Basically, if your program has a directory open, that should be reflected as a directory node that you can't do anything with. The current implementation allows you to chdir(), opendir(), etc, those directory nodes, but the machinery to fully support those operations is missing so they just screw things up. I have a candidate vop_access handler partly written, but I'm a little new to filesystem work, so it will take me a little while to satisfy myself that it works. /* * Non-chdir directory walker. */ #include <sys/stat.h> #include <sys/types.h> #include <dirent.h> #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> static char curpath[512]; void visit(char *f, int depth) { DIR *d; struct dirent *dp; size_t l = strlen(curpath); strcat(curpath, "/"); strcat(curpath, f); printf("%3d: %s\n", depth, curpath); d = opendir(curpath); if (d != NULL) { while ((dp = readdir(d)) != NULL) { if (dp->d_name[0] == '.') continue; visit(dp->d_name, depth + 1); } closedir(d); } curpath[l] = '\0'; } int main(int argc, char **argv) { visit("/dev/fd", 0); exit(0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?4A03A202.2050101>