[net.sources.bugs] scandir

chris@umcp-cs.UUCP (Chris Torek) (05/13/86)

In article <218@transys.UUCP>, root@transys.UUCP (The Super User)
supplies a public-domain scandir().  The routine looks workable,
but is sensitive to `active' directories: if the number of directory
entries increases between the two scans, it will probably crash.

The following routines are *not* equivalent, but (assuming readdir()
is properly written) do not suffer from this problem.  In addition,
I think this version is generally more convenient.  It drops the
inode number and the other redundant information in a 4.2 style
directory, and it generates various error messages (both fatal and
non-fatal), but it does what I wanted at the time....

/*
 * Save a string in managed memory.
 */
char *
savestr(s)
	char *s;
{
	char *t, *malloc(), *strcpy();

	if ((t = malloc((unsigned) (strlen(s) + 1))) == 0)
		error(1, errno, "out of memory");
	return (strcpy(t, s));
}

/*
 * For qsort: perform a machine-collating-sequence sort.
 */
machinesort(s1, s2)
	char **s1, **s2;
{
	int i;

	return ((i = **s1 - **s2) ? i : strcmp(*s1, *s2));
}

/*
 * Scan a directory.  Return a sorted list of the names contained therein.
 * The list is dynamically allocated, and can be freed with freeit().
 */
char **
scanit(dname)
	char *dname;
{
	register DIR *d;
	register struct direct *dp;
	register char **names, **np;
	register int nleft;
	int nnames;
	char *malloc(), *realloc();

	if ((d = opendir(dname)) == 0) {
		error(0, errno, "can't read %s", dname);
		return (0);
	}
	nnames = 10;
	names = (char **) malloc((unsigned) (10 * sizeof *names));
	if (names == 0)
		error(1, errno, "out of memory");
	nleft = nnames - 1;	/* start off-by-one for terminator */
	np = names;
	while ((dp = readdir(d)) != 0) {
		if (dp->d_namlen == 1 && dp->d_name[0] == '.')
			continue;
		if (dp->d_namlen == 2 && dp->d_name[0] == '.' &&
		    dp->d_name[1] == '.')
			continue;
		if (--nleft < 0) {
			nleft = nnames - 1;	/* we're about to use one */
			nnames <<= 1;
			names = (char **) realloc((char *) names,
					(unsigned) (nnames * sizeof *names));
			if (names == 0)
				error(1, errno, "out of memory");
			np = names + nleft;
		}
		*np++ = savestr(dp->d_name);
	}
	qsort((char *) names, np - names, sizeof *names, machinesort);
	*np = 0;
	closedir(d);
	return (names);
}

/*
 * Free a directory as returned by scanit().
 */
freeit(p)
	char **p;
{
	register char **q = p;

	while (*q)
		free(*q++);
	free((char *) p);
}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu