/* * 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. * * * 2011: getsdir() has been simplified wrt memory management by * Adam Lackorzynski */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #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 int g_sortflags; /* sort flags */ /* sort compare routines */ /* * 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 */ /* * name: getsdir * * purpose: To return a directory listing - possibly sorted * * synopsis: #include * * 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[NAME_MAX + 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 = 0; /* 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 cmprstat; g_sortflags = sortflags; /* for sort funcs */ *len = 0; /* longest name */ /* open the specified directory */ if ((dirp = opendir(dirpath)) == NULL) return -1; while ((dp = readdir(dirp))) { if (!strcmp(dp->d_name, ".")) continue; if ((sortflags & GETSDIR_PARNT) && !strcmp(dp->d_name, "..")) cmprstat = 1; else if (pattern && *pattern) cmprstat = wildmat(dp->d_name, pattern); else cmprstat = 1; if (cmprstat) { /* matching name? */ *datptr = realloc(*datptr, sizeof(**datptr) * (cnt + 1)); if (!*datptr) { free(*datptr); closedir(dirp); return -1; } /* copy the filename */ strncpy((*datptr)[cnt].fname, dp->d_name, NAME_MAX + 1); /* get information about the directory entry */ snprintf(fpath, sizeof(fpath), "%s/%s", dirpath, dp->d_name); if (stat(fpath, &statbuf)) /* if error getting stat... */ continue; if (modemask && !(S_IFMT & modemask & statbuf.st_mode)) continue; int l; if ((l = strlen(dp->d_name)) > *len) *len = l; (*datptr)[cnt].time = statbuf.st_mtime; (*datptr)[cnt].mode = statbuf.st_mode; (*datptr)[cnt].cflags = 0; cnt++; } } closedir(dirp); /* close file pointer */ /* 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 */ #ifdef GETSDIR_STANDALONE_TEST /* * debug for getsdir() * * usage: getsdir * */ 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 \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