Subject: None
To: None <netbsd-help@netbsd.org>
From: John Refling <johnr@imageworks.com>
List: netbsd-help
Date: 07/05/2000 18:46:49
I've been using getdents() to scan the directory
structure on my filesystem, and have noticed a few
strange things:
1) getdents() fails when used on /kern, with an errno
of 22, which from the man page indicates that:
"A directory was being read on NFS, but it was
modified on the server while it was being read."
While I can see that it is possible for the /kern
file system to be constantly changing, the find
command works on kern. Note however that "cat /kern"
fails with an "Operation not supported" error,
while other directories can be cat'ed. Why?
2) it appears as though the contents of the directory
file can contain references to deleted files.
When I use getdents(), I will occasionally get
a deleted file name printed out when scanning the
chain of structures. This deleted file entry will
disappear if I touch a new file in that directory
(it seems as though the directory chain is updated
at that point). Out of 65,000 files on my partition,
there were 5 like this. What's going on? Am I
using getdents incorrectly? Is the file system
corrupt? Is getdents broken? Is the file system
broken? Is it required to do a 'stat' on each
directory entry from getdents to ensure that it exists?
???????
Below I show that myfind finds a deleted file in the dir
chain, where find and ls do not. After creating several new
files in that dir, myfind does not find the deleted file
anymore.
> myfind /tmp/nbsd/distfiles | fgrep eso
x /tmp/nbsd/distfiles/esound-0.2.18.tar.gz
> ls /tmp/nbsd/distfiles/esound-0.2.18.tar.gz
ls: /tmp/nbsd/distfiles/esound-0.2.18.tar.gz: No such file or directory
> find /tmp/nbsd/distfiles | fgrep eso
> touch /tmp/nbsd/distfiles/delete{1,2,3,4,5}
> myfind /tmp/nbsd/distfiles | fgrep eso
x /tmp/nbsd/distfiles/esound-0.2.18.tar.gz
> touch /tmp/nbsd/distfiles/delete{6,7,8,9,10,11,12,13,14,15,16,17,18,19}
> myfind /tmp/nbsd/distfiles | fgrep eso
> fsck
** /dev/rsd0a
** Last Mounted on /
** Root file system
** Phase 1 - Check Blocks and Sizes
** Phase 2 - Check Pathnames
** Phase 3 - Check Connectivity
** Phase 4 - Check Reference Counts
** Phase 5 - Check Cyl groups
62748 files, 1279710 used, 2764329 free (11825 frags, 344063 blocks, 0.3% fragmentation)
myfind.c:
#include <dirent.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>
#include <errno.h>
main(int argc, char **argv) {
int i, j, fileno, quant, catpos;
int64_t max;
char pathfilename[MAXPATHLEN];
struct stat statd;
char *cp, *buff;
// prepend the dir path for stat
strcpy(pathfilename, argv[1]);
if (pathfilename[strlen(pathfilename)-1] != '/') strcat(pathfilename, "/");
catpos = strlen(pathfilename);
if (0 > (fileno = open(argv[1], O_RDONLY, 555))) {
printf("no such dir: %s\n", argv[1]);
exit(1);
}
if (0 > fstat(fileno, &statd)) {
printf("stat on %s failed\n", argv[1]);
exit(1);
}
max = statd.st_blocks * 512;
if (NULL == (buff = (char *)malloc((size_t)max))) {
printf("malloc failed\n");
exit(1);
}
if (0 > (quant = getdents(fileno, buff, max)))
printf("getdents errno is %d on %s\n", errno, argv[1]);
close(fileno);
// hop down chain of structures printing out when stat fails
for (i = 0; i < quant; i += *(unsigned short *)&buff[4+i]) {
cp = (char *)&buff[8+i];
strcpy(&pathfilename[catpos], cp);
if (0 > lstat(pathfilename, &statd))
printf("x %s\n", pathfilename);
}
}