getsdir.c
上传用户:tianjinjs
上传日期:2007-01-05
资源大小:309k
文件大小:11k
- /*
- * getsdir.c
- *
- * Get and return a sorted directory listing
- *
- * Copyright (c) 1998 by James S. Seymour (jseymour@jimsun.LinxNet.com)
- *
- * This code is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Note: this code uses "wildmat.c", which has different copyright
- * and licensing conditions. See the source, Luke.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include "port.h" /* from minicom: for needed for _PROTO macro only */
- #include "getsdir.h"
- _PROTO(extern int wildmat, (char *, char *)); /* pattern matcher */
- /* locally defined constants */
-
- #define MAX_CNT 100 /* number of entries to hold in holding buf */
- typedef struct dat_buf { /* structure of input buffers */
- struct dat_buf *nxt; /* pointer to next buffer */
- unsigned cnt; /* data count in present buffer */
- GETSDIR_ENTRY data[MAX_CNT]; /* data in present buffer */
- } DAT_BUF;
- static DAT_BUF *datb_frst; /* pointer to first data buffer */
- static DAT_BUF *datb_cur; /* pointer to current data buffer */
- static int g_sortflags; /* sort flags */
- /* sort compare routines */
- _PROTO(static int namecmpr, (GETSDIR_ENTRY *d1, GETSDIR_ENTRY *d2));
- _PROTO(static int timecmpr, (GETSDIR_ENTRY *d1, GETSDIR_ENTRY *d2));
- _PROTO(static void free_up, (void)); /* free-up used memory */
- /*
- * name: getsdir
- *
- * purpose: To return a directory listing - possibly sorted
- *
- * synopsis: #include <dirent.h>
- *
- * int getsdir(dirpath, pattern, sortflags, modemask, datptr, len)
- * char *dirpath;
- * char *pattern;
- * int sortflags;
- * mode_t modemask;
- * GETSDIR_ENTRY **datptr;
- * int *len;
- *
- * input: *dirpath - pointer to path to directory to get list of
- * files from
- * *pattern - pointer to optional wildmat pattern
- * sortflags - specification flags of how to sort the
- * resulting list. See descriptions below.
- * modemask - caller-supplied mode mask. Bits in this will
- * be ANDed against directory entries to determine
- * whether to return them. Ignored if 0.
- * **datptr - pointer to a destination pointer variable.
- * getsdir will allocate the required amount
- * of memory for the results and will return a
- * pointer to the returned data in this variable.
- *
- * The data will be in the form:
- * typedef struct dirEntry {
- * char fname[MAXNAMLEN + 1];
- * time_t time;
- * mode_t mode;
- * } GETSDIR_ENTRY;
- * *len - pointer to int to contain length of longest
- * string in returned array.
- *
- * process: For each 0..MAX_CNT values read from specified directory,
- * allocates a temporary buffer to store the entries into.
- * When end of directory is detected, merges the buffers into
- * a single array of data and sorts into order based on key.
- *
- * output: Count of number of data items pointed to by datptr or
- * -1 if error. errno may or may not be valid, based on
- * type of error encountered.
- *
- * notes: If there is any error, -1 is returned.
- *
- * It is the caller's responsibility to free the memory
- * block pointed to by datptr on return when done with the
- * data, except in case of error return.
- *
- * See also: opendir(3C), readdir(3C), closedir(3C), qsort(3C)
- *
- * The pattern parameter is optional and may be 0-length or
- * a NULL pointer.
- *
- * The sort flags affect the output as follows:
- *
- * GETSDIR_PARNT - include parent dir (..)
- * GETSDIR_NSORT - sort by name
- * GETSDIR_TSORT - sort by time (NSORT wins if both)
- *
- * The following are only meaningful if GETSDIR_NSORT or
- * GETSDIR_TSORT are specified:
- *
- * GETSDIR_DIRSF - dirs first
- * GETSDIR_DIRSL - dirs last
- * GETSDIR_RSORT - reverse sort (does not affect
- * GETSDIR_DIRSF/GETSDIR_DIRSL)
- *
- * So-called "hidden" files (those beginning with a ".") are
- * not returned unless a pattern like ".*" is specified.
- *
- * The present directory (".") is never returned.
- */
- int
- getsdir(dirpath, pattern, sortflags, modemask, datptr, len)
- char *dirpath;
- char *pattern;
- int sortflags;
- mode_t modemask;
- GETSDIR_ENTRY **datptr;
- int *len;
- {
- unsigned cnt; /* data count */
- DIR *dirp; /* point to open dir */
- struct dirent *dp; /* structure of dir as per system */
- struct stat statbuf; /* structure of file stat as per system */
- char fpath[BUFSIZ]; /* filename with dir path prepended */
- int indx; /* g-p array indexer */
- int cmprstat;
- DAT_BUF *datb_sav; /* pointer to previous data buffer */
- g_sortflags = sortflags; /* for sort funcs */
- *len = 0; /* longest name */
- datb_frst = (DAT_BUF *) NULL; /* init pointers to first data buff */
- datb_cur = (DAT_BUF *) NULL;
- /* open the specified directory */
- if ((dirp = opendir(dirpath)) == NULL)
- return(-1);
- /* discard current, and possibly parent, dir entries */
- if(readdir(dirp) == NULL ||
- (!(sortflags & GETSDIR_PARNT) && readdir(dirp) == NULL))
- {
- fprintf(stderr, "DBUG: initial readdir() failed (errno == %d)n",
- errno);
- perror("readdir");
- fflush(stderr);
- }
- for(cnt = 1;; ++cnt) /* for buffer count 1 to whatever... */
- {
- datb_sav = datb_cur; /* save pointer to previous buffer */
- /* get a new buffer */
- if((datb_cur = (DAT_BUF*)calloc(1,sizeof(DAT_BUF))) == (DAT_BUF*)NULL)
- {
- closedir(dirp);
- return(-1);
- }
- /* init new buffer link pointer */
- datb_cur->nxt = (DAT_BUF *) NULL;
- if(datb_frst == (DAT_BUF *) NULL) /* if first buff... */
- datb_frst = datb_cur; /* ...init first buff pointer */
- else /* else... */
- datb_sav->nxt = datb_cur; /* ...link to new */
- /* while the current buffer is not full, get directory entries */
- for(datb_cur->cnt = 0; datb_cur->cnt < MAX_CNT; )
- if((dp = readdir(dirp)) != NULL) /* get next directory entry */
- {
- if((sortflags & GETSDIR_PARNT) &&
- strcmp(dp->d_name, "..") == 0)
- {
- cmprstat = 1;
- }
- else if(pattern && strlen(pattern))
- cmprstat = wildmat(dp->d_name, pattern);
- else
- cmprstat = 1;
- if(cmprstat) /* matching name? */
- {
- int l;
- /* copy the filename */
- strncpy(datb_cur->data[datb_cur->cnt].fname,
- dp->d_name,
- MAXNAMLEN);
- /* get information about the directory entry */
- snprintf(fpath, sizeof(fpath), "%s/%s", dirpath, dp->d_name);
- if(stat(fpath, &statbuf)) /* if error getting stat... */
- {
- #if 0
- free_up(); /* free-up used memory */
- closedir(dirp); /* close file pointer */
- return(-1); /* nobody home */
- #endif
- continue;
- }
- if(modemask && !(S_IFMT & modemask & statbuf.st_mode))
- continue;
- if((l = strlen(dp->d_name)) > *len)
- *len = l;
- datb_cur->data[datb_cur->cnt].time = statbuf.st_mtime;
- datb_cur->data[datb_cur->cnt].mode = statbuf.st_mode;
- ++datb_cur->cnt; /* bump array index / data count */
- }
- }
- else
- break; /* at end of directory */
- if(datb_cur->cnt < MAX_CNT) /* if less than full buffer... */
- break; /* ...all done */
- }
-
- closedir(dirp); /* close file pointer */
- /* get memory for single array */
- if((*datptr = (GETSDIR_ENTRY *) calloc(cnt, sizeof(datb_cur->data)))
- == NULL)
- {
- /* couldn't get space, clear everything up */
- free_up(); /* free-up used memory */
- return(-1); /* error */
- }
- /* copy/concatenate the data */
- cnt = indx = 0; /* init final count and dest index */
- do
- {
- datb_cur = datb_frst;
- /* copy data in one swell foop */
- memcpy(*datptr+indx*MAX_CNT, datb_cur->data, sizeof(datb_cur->data));
- cnt += datb_cur->cnt; /* adjust data count */
- ++indx; /* bump destination index */
- datb_frst = datb_cur->nxt;
- free(datb_cur); /* free no longer needed buffer */
- } while (datb_frst); /* while more to go */
- free_up(); /* free-up used memory */
- /* post-process array by option */
- if(cnt && sortflags) {
- if(sortflags & GETSDIR_NSORT)
- qsort(*datptr, cnt, sizeof(GETSDIR_ENTRY),
- (int (*)(const void *, const void *))namecmpr);
- else if(sortflags & GETSDIR_TSORT)
- qsort(*datptr, cnt, sizeof(GETSDIR_ENTRY),
- (int (*)(const void *, const void *))timecmpr);
- }
- return(cnt);
- } /* getsdir */
- /*
- * name: free_up
- *
- * purpose: free up memory allocated for temporary buffers
- *
- * synopsis: static void freeup()
- *
- * input: none
- *
- * process: as under purpose
- *
- * output: none
- *
- * notes: none
- */
- static void
- free_up()
- {
- if((datb_cur = datb_frst) != (DAT_BUF *) NULL) /* start with first */
- do /* and free 'em all */
- {
- datb_frst = datb_cur->nxt;
- free(datb_cur);
- } while ((datb_cur = datb_frst));
- } /* free_up */
- /*
- * name: namecmpr
- *
- * purpose: return stat to qsort on comparison between name fields in
- * directory entry.
- *
- * synopsis: static in namecmpr(d1, d2)
- * GETSDIR_ENTRY *d1;
- * GETSDIR_ENTRY *d2;
- *
- * input: See explanation of qsort
- *
- * process: See explanation of qsort
- *
- * output: See explanation of qsort
- *
- * notes: See explanation of qsort
- */
- static int
- namecmpr(d1, d2)
- GETSDIR_ENTRY *d1, *d2;
- {
- if(g_sortflags & (GETSDIR_DIRSF | GETSDIR_DIRSL)) {
- if(S_ISDIR((d1->mode)) && ! S_ISDIR((d2->mode)))
- return((g_sortflags & GETSDIR_DIRSF)? -1 : 1);
- else if(S_ISDIR((d2->mode)) && ! S_ISDIR((d1->mode)))
- return((g_sortflags & GETSDIR_DIRSF)? 1 : -1);
- }
- return((g_sortflags & GETSDIR_RSORT)?
- strcmp(d2->fname, d1->fname) : strcmp(d1->fname, d2->fname));
- } /* namecmpr */
- /*
- * name: timecmpr
- *
- * purpose: return stat to qsort on comparison between time fields in
- * directory entry.
- *
- * synopsis: static in timecmpr(d1, d2)
- * GETSDIR_ENTRY *d1;
- * GETSDIR_ENTRY *d2;
- *
- * input: See explanation of qsort
- *
- * process: See explanation of qsort
- *
- * output: See explanation of qsort
- *
- * notes: See explanation of qsort
- */
- static int
- timecmpr(d1, d2)
- GETSDIR_ENTRY *d1, *d2;
- {
- if(g_sortflags & (GETSDIR_DIRSF | GETSDIR_DIRSL)) {
- if(S_ISDIR((d1->mode)) && ! S_ISDIR((d2->mode)))
- return((g_sortflags & GETSDIR_DIRSF)? -1 : 1);
- else if(S_ISDIR((d2->mode)) && ! S_ISDIR((d1->mode)))
- return((g_sortflags & GETSDIR_DIRSF)? 1 : -1);
- }
- return((g_sortflags & GETSDIR_RSORT)?
- (d2->time - d1->time) : (d1->time - d2->time));
- } /* timecmpr */
- #ifdef GETSDIR_STANDALONE_TEST
- /*
- * debug for getsdir()
- *
- * usage: getsdir <dirpath>
- *
- */
- extern char *ctime();
- void
- main(argc, argv)
- int argc;
- char *argv[];
- {
- GETSDIR_ENTRY *dirdat;
- int cnt, index;
- int sortflags = 0;
- mode_t modemask = (mode_t) 0;
- int len;
- if(argc != 4)
- {
- fprintf(stderr,"usage: %s <dirpath> <pattern> <sortflags>n", argv[0]);
- exit(1);
- }
- switch(argv[3][0]) {
- case 'n': sortflags = GETSDIR_NSORT;
- break;
- case 't': sortflags = GETSDIR_TSORT;
- break;
- }
- /* sortflags |= GETSDIR_DIRSL | GETSDIR_RSORT; */
- sortflags |= GETSDIR_DIRSF;
- /* sortflags |= GETSDIR_PARNT; */
- /* modemask = S_IFDIR | S_IFREG; */
- printf("modemask==%xn", modemask);
- if((cnt = getsdir(argv[1], argv[2], sortflags, modemask, &dirdat, &len)) == -1)
- {
- fprintf(stderr, "%s: error getting directoryn", argv[0]);
- exit(1);
- }
- printf(_("%d files:n"), cnt);
- for(index = 1; index <= cnt; ++index, ++dirdat)
- printf("%2d: %-20s%s",
- index, dirdat->fname, ctime(&dirdat->time));
- free(dirdat);
- exit(0);
- }
- #endif