📄 getsdir.c
字号:
/* * 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. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Note: this code uses "wildmat.c", which has different copyright * and licensing conditions. See the source, Luke. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "rcsid.h"RCSID("$Id: getsdir.c,v 1.5 2007-10-10 20:18:20 al-guest Exp $")#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <errno.h>#include "getsdir.h"#include "intl.h"#include "minicom.h"/* 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 */static int namecmpr(GETSDIR_ENTRY *d1, GETSDIR_ENTRY *d2);static int timecmpr(GETSDIR_ENTRY *d1, GETSDIR_ENTRY *d2);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) * const char *dirpath; * const 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(const char *dirpath, const 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; 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 = calloc(1, sizeof(DAT_BUF))) == NULL) { closedir(dirp); return -1; } /* init new buffer link pointer */ datb_cur->nxt = NULL; if (datb_frst == 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))) {/* get next directory entry */ if (!strcmp(dp->d_name, ".")) continue; if ((sortflags & GETSDIR_PARNT) && !strcmp(dp->d_name, "..")) 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(void){ if ((datb_cur = datb_frst) != 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(GETSDIR_ENTRY *d1, GETSDIR_ENTRY *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(GETSDIR_ENTRY *d1, GETSDIR_ENTRY *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);void main(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==%x\n", modemask); if ((cnt = getsdir(argv[1], argv[2], sortflags, modemask, &dirdat, &len)) == -1) { fprintf(stderr, "%s: error getting directory\n", 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); return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -