[net.bugs.4bsd] Bizarre Modem Problems

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