chris@umcp-cs.UUCP (07/20/86)
I cannot help with your `bizarre' (sic: it may help to think of a `bizarre bazzar') modem problem, but this one is not hard: In article <1530@cwruecmp.UUCP> rynes@cwruecmp.UUCP (Edward M. Rynes Esq.) writes: >The following program fragment is supposed to remake directories >that have many unused entries in them. (uucp/news spool directories) >The first pass apears to run fine. But in the second pass all of the >`stat's fail (bad address). Something in the first pass appears to >be screwing up the directory. Am I missing something? > <path is the original directory> > <ptmp is a newly created temp directory> > <dp = opendir(path)> > > /* First pass -- copy all non-empty files */ > > for(dent=readdir(dp); dent; dent=readdir(dp)){ why not `while ((dent = readdir(dp)) != NULL)'? [no occurrences of `stat'; much deleted] > closedir(dp); > > unlink(path); Ai! You do NOT want to `unlink' a directory. Use `rmdir'! > if(rename(ptmp, path)){ > fprintf(stderr,"Can't rename directory!\n"); > exit(-1); > } > > /* Second pass -- trim sub directories */ > > if((dp=opendir(path)) == NULL){ > fprintf(stderr, "Can't access `%s'!\n", path); > exit(3); > } > > for(dent=readdir(dp); dent; dent=readdir(dp)){ Again, one `while' would certainly be simpler. Ah well. > if(!strcmp(dent->d_name, ".") || ! strcmp(dent->d_name, "..")) > continue; `!strcmp()' is, in my opinion, bad style: it implies strcmp() is a boolean function, when in fact it is a ternary function. Again: ah well. > sprintf(pent, "%s/%s", path, dent->d_name); > > if(stat(pent, buf)) > perror("trimdirs"); This *call* is fine: it passes a `char *' and a `struct stat *'. But to what `struct stat' does `buf' point? Given the error you got, it clearly points to no `struct stat' at all. It is probably either `(struct stat *)NULL' or rubbish. You need to create one somewhere (global, on the stack, or even on the heap if you wish) and make `buf' point to it. > if(buf && buf->st_mode & S_IFDIR) The test on `buf' is redundant; this is equivalent to /* excessively parenthesised, for demonstration purposes only: */ if ((buf != NULL) && ((buf->st_mode & S_IFDIR) != 0)) If buf is equal to NULL (0), the stat will have failed, and you will not reach this statement. > trimdir(path, dent->d_name); > } > > closedir(dp); There are some non-trivial problems for a good general purpose directory squeezer. It is difficult (to say the least) to squeeze the top level directory of a mounted file system. Care must be taken during a recursive squeeze not to cross mount points. More care should be taken to avoid running out of file descriptors in mid-squeeze; and the program should be prepared to recover from an error during squeezing a directory (it should put all the names back, if possible). On the other hand, you can simply write something that returns a success/failure exit code, and let the operator deal with any catastrophes. . . . -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu