Path: utzoo!attcan!uunet!convex!killer!mit-eddie!bbn!diamond.bbn.com!mlandau From: mlandau@bbn.com (Matt Landau) Newsgroups: comp.unix.wizards Subject: Re: scandir() Summary: bogus info abounds - scandir allocates its own storage! Keywords: scandir catch-22 Message-ID: <11191@jade.BBN.COM> Date: 30 Jun 88 23:43:18 GMT References: <1445@uokmax.UUCP> <799@scubed.UUCP> Reply-To: mlandau@bbn.com (Matt Landau) Organization: BBN Laboratories Incorporated, Cambridge, MA Lines: 60 In comp.unix.wizards, warner@scubed.UUCP (Ken Warner) writes: >In article <1445@uokmax.UUCP> sam@uokmax.UUCP (Sam L Falkner) writes: >> >> Has anyone out there ever used the scandir() function? > >Here is a routine that uses scandir(). This is Sun 3-OS 3.4,5 >specific. The trick to using scandir() is to know how many entries are >in the directory before you make the call to scandir(). scandir() >just stuffs the array full of the entries into the the location pointed >to by the automatic and will blow away the stack if there isn't any >room. Sort of a catch 22. This is completely wrong -- scandir allocates its own storage. Both the 4.3 BSD and SunOS 3.4 manual pages say this quite explicitly. Here's a code fragment that uses scandir() and seems to work correctly. Note the declaration of "struct direct **entries" and the use of &entries as the second argument to scandir(). There's also a lot of ad hoc use of pointers as arrays (and vice versa) in this code, but in this case it seems the clearest way to communicate what's going on. clean_dir(dirname) char *dirname; { extern char *getenv(); extern int needs_cleaning(); extern int is_directory(); static char old_name[MAXNAMLEN], new_name[MAXNAMLEN]; register int e; char *backup; int n_entries; struct direct **entries; /* Figure out where to put things */ if ((backup = getenv("TRASH")) == NULL) backup = "/tmp"; if (!is_directory(backup)) { fprintf(stderr, "clean: trash directory %s not found\n", backup); exit(-1); } /* Scan directory for files that are candidates for cleanup. */ n_entries = scandir(dirname, &entries, needs_cleaning, (int (*)())NULL); /* If no valid entries were found, figure out why not. */ if (n_entries < 0) perror("scandir"); else { for (e = 0; e < n_entries; e++) { sprintf(old_name, "%s/%s", dirname, entries[e]->d_name); sprintf(new_name, "%s/%s", backup, entries[e]->d_name); rename(old_name, new_name); } } }