fdescfs brokenness
Tim Kientzle
kientzle at freebsd.org
Fri May 8 03:07:48 UTC 2009
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);
}
More information about the freebsd-hackers
mailing list