121357Sdist /* 221357Sdist * Copyright (c) 1983 Regents of the University of California. 334790Sbostic * All rights reserved. 434790Sbostic * 542626Sbostic * %sccs.include.redist.c% 621357Sdist */ 721357Sdist 826582Sdonn #if defined(LIBC_SCCS) && !defined(lint) 9*43609Sbostic static char sccsid[] = "@(#)scandir.c 5.9 (Berkeley) 06/24/90"; 1034790Sbostic #endif /* LIBC_SCCS and not lint */ 1113582Ssam 129609Sralph /* 139609Sralph * Scan the directory dirname calling select to make a list of selected 149609Sralph * directory entries then sort using qsort and compare routine dcomp. 159609Sralph * Returns the number of entries and a pointer to a list of pointers to 1636545Smckusick * struct dirent (through namelist). Returns -1 if there were any errors. 179609Sralph */ 189609Sralph 199609Sralph #include <sys/types.h> 209609Sralph #include <sys/stat.h> 2136545Smckusick #include <dirent.h> 229609Sralph 2336558Smckusick /* 2436558Smckusick * The DIRSIZ macro gives the minimum record length which will hold 2536558Smckusick * the directory entry. This requires the amount of space in struct dirent 2636558Smckusick * without the d_name field, plus enough space for the name with a terminating 2736558Smckusick * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. 2836558Smckusick */ 2936558Smckusick #undef DIRSIZ 3036558Smckusick #define DIRSIZ(dp) \ 3136558Smckusick ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) 3236558Smckusick 339609Sralph scandir(dirname, namelist, select, dcomp) 349609Sralph char *dirname; 3543534Sbostic struct dirent ***namelist; 369609Sralph int (*select)(), (*dcomp)(); 379609Sralph { 3836545Smckusick register struct dirent *d, *p, **names; 399609Sralph register int nitems; 409609Sralph struct stat stb; 419609Sralph long arraysz; 429609Sralph DIR *dirp; 439609Sralph 449609Sralph if ((dirp = opendir(dirname)) == NULL) 459609Sralph return(-1); 469609Sralph if (fstat(dirp->dd_fd, &stb) < 0) 479609Sralph return(-1); 489609Sralph 499609Sralph /* 509609Sralph * estimate the array size by taking the size of the directory file 519609Sralph * and dividing it by a multiple of the minimum size entry. 529609Sralph */ 539609Sralph arraysz = (stb.st_size / 24); 5436545Smckusick names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *)); 559609Sralph if (names == NULL) 569609Sralph return(-1); 579609Sralph 589609Sralph nitems = 0; 599609Sralph while ((d = readdir(dirp)) != NULL) { 609609Sralph if (select != NULL && !(*select)(d)) 619609Sralph continue; /* just selected names */ 629609Sralph /* 639609Sralph * Make a minimum size copy of the data 649609Sralph */ 6536545Smckusick p = (struct dirent *)malloc(DIRSIZ(d)); 669609Sralph if (p == NULL) 679609Sralph return(-1); 689609Sralph p->d_ino = d->d_ino; 699609Sralph p->d_reclen = d->d_reclen; 709609Sralph p->d_namlen = d->d_namlen; 7136681Sbostic bcopy(d->d_name, p->d_name, p->d_namlen + 1); 729609Sralph /* 739609Sralph * Check to make sure the array has space left and 749609Sralph * realloc the maximum size. 759609Sralph */ 769609Sralph if (++nitems >= arraysz) { 7715661Sralph if (fstat(dirp->dd_fd, &stb) < 0) 7815661Sralph return(-1); /* just might have grown */ 7915661Sralph arraysz = stb.st_size / 12; 8036545Smckusick names = (struct dirent **)realloc((char *)names, 8136545Smckusick arraysz * sizeof(struct dirent *)); 829609Sralph if (names == NULL) 839609Sralph return(-1); 849609Sralph } 859609Sralph names[nitems-1] = p; 869609Sralph } 879609Sralph closedir(dirp); 889609Sralph if (nitems && dcomp != NULL) 8936545Smckusick qsort(names, nitems, sizeof(struct dirent *), dcomp); 909609Sralph *namelist = names; 919609Sralph return(nitems); 929609Sralph } 939609Sralph 949609Sralph /* 959609Sralph * Alphabetic order comparison routine for those who want it. 969609Sralph */ 979609Sralph alphasort(d1, d2) 98*43609Sbostic void *d1, *d2; 999609Sralph { 100*43609Sbostic return(strcmp((*(struct dirent **)d1)->d_name, 101*43609Sbostic (*(struct dirent **)d2)->d_name)); 1029609Sralph } 103