Blame src/getsdir.c

Packit 15a96c
/*
Packit 15a96c
 * getsdir.c
Packit 15a96c
 *
Packit 15a96c
 *	Get and return a sorted directory listing
Packit 15a96c
 *
Packit 15a96c
 *	Copyright (c) 1998 by James S. Seymour (jseymour@jimsun.LinxNet.com)
Packit 15a96c
 *
Packit 15a96c
 *	This code is free software; you can redistribute it and/or
Packit 15a96c
 *	modify it under the terms of the GNU General Public License
Packit 15a96c
 *	as published by the Free Software Foundation; either version
Packit 15a96c
 *	2 of the License, or (at your option) any later version.
Packit 15a96c
 *
Packit 15a96c
 *  You should have received a copy of the GNU General Public License along
Packit 15a96c
 *  with this program; if not, write to the Free Software Foundation, Inc.,
Packit 15a96c
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 15a96c
 *
Packit 15a96c
 *	Note: this code uses "wildmat.c", which has different copyright
Packit 15a96c
 *	and licensing conditions.  See the source, Luke.
Packit 15a96c
 *
Packit 15a96c
 *
Packit 15a96c
 *  2011: getsdir() has been simplified wrt memory management by
Packit 15a96c
 *        Adam Lackorzynski
Packit 15a96c
 */
Packit 15a96c
#ifdef HAVE_CONFIG_H
Packit 15a96c
#include <config.h>
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
#include <stdio.h>
Packit 15a96c
#include <stdlib.h>
Packit 15a96c
#include <string.h>
Packit 15a96c
#include <sys/types.h>
Packit 15a96c
#include <sys/stat.h>
Packit 15a96c
#include <errno.h>
Packit 15a96c
Packit 15a96c
#include "getsdir.h"
Packit 15a96c
#include "intl.h"
Packit 15a96c
#include "minicom.h"
Packit 15a96c
Packit 15a96c
Packit 15a96c
/* locally defined constants */
Packit 15a96c
Packit 15a96c
#define MAX_CNT 100		/* number of entries to hold in holding buf */
Packit 15a96c
Packit 15a96c
typedef struct dat_buf {		/* structure of input buffers */
Packit 15a96c
  struct dat_buf *nxt;			/* pointer to next buffer */
Packit 15a96c
  unsigned cnt;				/* data count in present buffer */
Packit 15a96c
  GETSDIR_ENTRY data[MAX_CNT];		/* data in present buffer */
Packit 15a96c
} DAT_BUF;
Packit 15a96c
Packit 15a96c
static int g_sortflags;			/* sort flags */
Packit 15a96c
Packit 15a96c
/* sort compare routines */
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * name:	namecmpr
Packit 15a96c
 *
Packit 15a96c
 * purpose:	return stat to qsort on comparison between name fields in
Packit 15a96c
 *		directory entry.
Packit 15a96c
 *
Packit 15a96c
 * synopsis:	static in namecmpr(d1, d2)
Packit 15a96c
 *		GETSDIR_ENTRY *d1;
Packit 15a96c
 *		GETSDIR_ENTRY *d2;
Packit 15a96c
 *
Packit 15a96c
 * input:	See explanation of qsort
Packit 15a96c
 *
Packit 15a96c
 * process:	See explanation of qsort
Packit 15a96c
 *
Packit 15a96c
 * output:	See explanation of qsort
Packit 15a96c
 *
Packit 15a96c
 * notes:	See explanation of qsort
Packit 15a96c
 */
Packit 15a96c
static int namecmpr(GETSDIR_ENTRY *d1, GETSDIR_ENTRY *d2)
Packit 15a96c
{
Packit 15a96c
  if (g_sortflags & (GETSDIR_DIRSF | GETSDIR_DIRSL)) {
Packit 15a96c
    if (S_ISDIR((d1->mode)) && !S_ISDIR((d2->mode)))
Packit 15a96c
      return (g_sortflags & GETSDIR_DIRSF) ? -1 : 1;
Packit 15a96c
    else if (S_ISDIR((d2->mode)) && ! S_ISDIR((d1->mode)))
Packit 15a96c
      return (g_sortflags & GETSDIR_DIRSF) ? 1 : -1;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  return (g_sortflags & GETSDIR_RSORT)
Packit 15a96c
          ? strcmp(d2->fname, d1->fname) : strcmp(d1->fname, d2->fname);
Packit 15a96c
Packit 15a96c
} /* namecmpr */
Packit 15a96c
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * name:	timecmpr
Packit 15a96c
 *
Packit 15a96c
 * purpose:	return stat to qsort on comparison between time fields in
Packit 15a96c
 *		directory entry.
Packit 15a96c
 *
Packit 15a96c
 * synopsis:	static in timecmpr(d1, d2)
Packit 15a96c
 *		GETSDIR_ENTRY *d1;
Packit 15a96c
 *		GETSDIR_ENTRY *d2;
Packit 15a96c
 *
Packit 15a96c
 * input:	See explanation of qsort
Packit 15a96c
 *
Packit 15a96c
 * process:	See explanation of qsort
Packit 15a96c
 *
Packit 15a96c
 * output:	See explanation of qsort
Packit 15a96c
 *
Packit 15a96c
 * notes:	See explanation of qsort
Packit 15a96c
 */
Packit 15a96c
static int timecmpr(GETSDIR_ENTRY *d1, GETSDIR_ENTRY *d2)
Packit 15a96c
{
Packit 15a96c
  if (g_sortflags & (GETSDIR_DIRSF | GETSDIR_DIRSL)) {
Packit 15a96c
    if (S_ISDIR((d1->mode)) && !S_ISDIR((d2->mode)))
Packit 15a96c
      return (g_sortflags & GETSDIR_DIRSF) ? -1 : 1;
Packit 15a96c
    else if (S_ISDIR((d2->mode)) && ! S_ISDIR((d1->mode)))
Packit 15a96c
      return (g_sortflags & GETSDIR_DIRSF) ? 1 : -1;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  return (g_sortflags & GETSDIR_RSORT)
Packit 15a96c
         ? (d2->time - d1->time) : (d1->time - d2->time);
Packit 15a96c
} /* timecmpr */
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * name:	getsdir
Packit 15a96c
 *
Packit 15a96c
 * purpose:	To return a directory listing - possibly sorted
Packit 15a96c
 *
Packit 15a96c
 * synopsis:	#include <dirent.h>
Packit 15a96c
 *
Packit 15a96c
 *		int getsdir(dirpath, pattern, sortflags, modemask, datptr, len)
Packit 15a96c
 *		const char *dirpath;
Packit 15a96c
 *		const char *pattern;
Packit 15a96c
 *		int sortflags;
Packit 15a96c
 *		mode_t modemask;
Packit 15a96c
 *		GETSDIR_ENTRY **datptr;
Packit 15a96c
 *		int *len;
Packit 15a96c
 *
Packit 15a96c
 * input:	 *dirpath - pointer to path to directory to get list of
Packit 15a96c
 *			    files from
Packit 15a96c
 *		 *pattern - pointer to optional wildmat pattern
Packit 15a96c
 *		sortflags - specification flags of how to sort the
Packit 15a96c
 *			    resulting list.  See descriptions below.
Packit 15a96c
 *		 modemask - caller-supplied mode mask.  Bits in this will
Packit 15a96c
 *			    be ANDed against directory entries to determine
Packit 15a96c
 *			    whether to return them.  Ignored if 0.
Packit 15a96c
 *		 **datptr - pointer to a destination pointer variable.
Packit 15a96c
 *			    getsdir will allocate the required amount
Packit 15a96c
 *			    of memory for the results and will return a
Packit 15a96c
 *			    pointer to the returned data in this variable.
Packit 15a96c
 *
Packit 15a96c
 *			    The data will be in the form:
Packit 15a96c
 *				typedef struct dirEntry {
Packit 15a96c
 *				    char fname[MAXNAMLEN + 1];
Packit 15a96c
 *				    time_t time;
Packit 15a96c
 *				    mode_t mode;
Packit 15a96c
 *				} GETSDIR_ENTRY;
Packit 15a96c
 *		     *len - pointer to int to contain length of longest
Packit 15a96c
 *			    string in returned array.
Packit 15a96c
 *
Packit 15a96c
 * process:	For each 0..MAX_CNT values read from specified directory,
Packit 15a96c
 *		allocates a temporary buffer to store the entries into.
Packit 15a96c
 *		When end of directory is detected, merges the buffers into
Packit 15a96c
 *		a single array of data and sorts into order based on key.
Packit 15a96c
 *
Packit 15a96c
 * output:	Count of number of data items pointed to by datptr or
Packit 15a96c
 *		-1 if error.  errno may or may not be valid, based on
Packit 15a96c
 *		type of error encountered.
Packit 15a96c
 *
Packit 15a96c
 * notes:	If there is any error, -1 is returned.
Packit 15a96c
 *
Packit 15a96c
 *		It is the caller's responsibility to free the memory
Packit 15a96c
 *		block pointed to by datptr on return when done with the
Packit 15a96c
 *		data, except in case of error return.
Packit 15a96c
 *
Packit 15a96c
 *		See also: opendir(3C), readdir(3C), closedir(3C), qsort(3C)
Packit 15a96c
 *
Packit 15a96c
 *		The pattern parameter is optional and may be 0-length or
Packit 15a96c
 *		a NULL pointer.
Packit 15a96c
 *
Packit 15a96c
 *		The sort flags affect the output as follows:
Packit 15a96c
 *
Packit 15a96c
 *		    GETSDIR_PARNT - include parent dir (..)
Packit 15a96c
 *		    GETSDIR_NSORT - sort by name
Packit 15a96c
 *		    GETSDIR_TSORT - sort by time (NSORT wins if both)
Packit 15a96c
 *
Packit 15a96c
 *		    The following are only meaningful if GETSDIR_NSORT or
Packit 15a96c
 *		    GETSDIR_TSORT are specified:
Packit 15a96c
 *
Packit 15a96c
 *			GETSDIR_DIRSF - dirs first
Packit 15a96c
 *			GETSDIR_DIRSL - dirs last
Packit 15a96c
 *			GETSDIR_RSORT - reverse sort (does not affect
Packit 15a96c
 *					GETSDIR_DIRSF/GETSDIR_DIRSL)
Packit 15a96c
 *
Packit 15a96c
 *		So-called "hidden" files (those beginning with a ".") are
Packit 15a96c
 *		not returned unless a pattern like ".*" is specified.
Packit 15a96c
 *
Packit 15a96c
 *		The present directory (".") is never returned.
Packit 15a96c
 */
Packit 15a96c
Packit 15a96c
int getsdir(const char *dirpath, const char *pattern, int sortflags,
Packit 15a96c
            mode_t modemask, GETSDIR_ENTRY **datptr, int *len)
Packit 15a96c
{
Packit 15a96c
  unsigned cnt = 0;		/* data count */
Packit 15a96c
Packit 15a96c
  DIR *dirp;			/* point to open dir */
Packit 15a96c
  struct dirent *dp;		/* structure of dir as per system */
Packit 15a96c
  struct stat statbuf;		/* structure of file stat as per system */
Packit 15a96c
  char fpath[BUFSIZ];		/* filename with dir path prepended */
Packit 15a96c
  int cmprstat;
Packit 15a96c
Packit 15a96c
  g_sortflags = sortflags;	/* for sort funcs */
Packit 15a96c
  *len = 0;			/* longest name */
Packit 15a96c
Packit 15a96c
  /* open the specified directory */
Packit 15a96c
  if ((dirp = opendir(dirpath)) == NULL)
Packit 15a96c
    return -1;
Packit 15a96c
Packit 15a96c
  while ((dp = readdir(dirp)))
Packit 15a96c
    {
Packit 15a96c
      if (!strcmp(dp->d_name, "."))
Packit 15a96c
        continue;
Packit 15a96c
Packit 15a96c
      if ((sortflags & GETSDIR_PARNT) && !strcmp(dp->d_name, ".."))
Packit 15a96c
        cmprstat = 1;
Packit 15a96c
      else if (pattern && *pattern)
Packit 15a96c
        cmprstat = wildmat(dp->d_name, pattern);
Packit 15a96c
      else
Packit 15a96c
        cmprstat = 1;
Packit 15a96c
Packit 15a96c
      if (cmprstat)
Packit 15a96c
        {			/* matching name? */
Packit 15a96c
          *datptr = realloc(*datptr, sizeof(**datptr) * (cnt + 1));
Packit 15a96c
          if (!*datptr)
Packit 15a96c
            {
Packit 15a96c
              free(*datptr);
rpm-build c7b29f
              closedir(dirp);
Packit 15a96c
              return -1;
Packit 15a96c
            }
Packit 15a96c
Packit 15a96c
          /* copy the filename */
Packit 15a96c
          strncpy((*datptr)[cnt].fname, dp->d_name, MAXNAMLEN);
Packit 15a96c
Packit 15a96c
          /* get information about the directory entry */
Packit 15a96c
          snprintf(fpath, sizeof(fpath), "%s/%s", dirpath, dp->d_name);
Packit 15a96c
          if (stat(fpath, &statbuf))	/* if error getting stat... */
Packit 15a96c
            continue;
Packit 15a96c
Packit 15a96c
          if (modemask && !(S_IFMT & modemask & statbuf.st_mode))
Packit 15a96c
            continue;
Packit 15a96c
Packit 15a96c
          int l;
Packit 15a96c
          if ((l = strlen(dp->d_name)) > *len)
Packit 15a96c
            *len = l;
Packit 15a96c
Packit 15a96c
          (*datptr)[cnt].time   = statbuf.st_mtime;
Packit 15a96c
          (*datptr)[cnt].mode   = statbuf.st_mode;
Packit 15a96c
          (*datptr)[cnt].cflags = 0;
Packit 15a96c
Packit 15a96c
          cnt++;
Packit 15a96c
        }
Packit 15a96c
    }
Packit 15a96c
Packit 15a96c
  closedir(dirp);		/* close file pointer */
Packit 15a96c
Packit 15a96c
  /* post-process array by option */
Packit 15a96c
  if (cnt && sortflags) {
Packit 15a96c
    if (sortflags & GETSDIR_NSORT)
Packit 15a96c
      qsort(*datptr, cnt, sizeof(GETSDIR_ENTRY),
Packit 15a96c
            (int (*)(const void *, const void *))namecmpr);
Packit 15a96c
    else if (sortflags & GETSDIR_TSORT)
Packit 15a96c
      qsort(*datptr, cnt, sizeof(GETSDIR_ENTRY),
Packit 15a96c
            (int (*)(const void *, const void *))timecmpr);
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  return cnt;
Packit 15a96c
} /* getsdir */
Packit 15a96c
Packit 15a96c
Packit 15a96c
Packit 15a96c
#ifdef GETSDIR_STANDALONE_TEST
Packit 15a96c
/*
Packit 15a96c
 * debug for getsdir()
Packit 15a96c
 *
Packit 15a96c
 * usage: getsdir <dirpath>
Packit 15a96c
 *
Packit 15a96c
 */
Packit 15a96c
extern char *ctime(void);
Packit 15a96c
Packit 15a96c
void main(int argc, char **argv)
Packit 15a96c
{
Packit 15a96c
  GETSDIR_ENTRY *dirdat;
Packit 15a96c
  int cnt, index;
Packit 15a96c
  int sortflags = 0;
Packit 15a96c
  mode_t modemask = (mode_t) 0;
Packit 15a96c
  int len;
Packit 15a96c
Packit 15a96c
  if (argc != 4) {
Packit 15a96c
    fprintf(stderr,"usage: %s <dirpath> <pattern> <sortflags>\n", argv[0]);
Packit 15a96c
    exit(1);
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  switch (argv[3][0]) {
Packit 15a96c
    case 'n': sortflags = GETSDIR_NSORT;
Packit 15a96c
              break;
Packit 15a96c
    case 't': sortflags = GETSDIR_TSORT;
Packit 15a96c
              break;
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  /* sortflags |= GETSDIR_DIRSL | GETSDIR_RSORT; */
Packit 15a96c
  sortflags |= GETSDIR_DIRSF;
Packit 15a96c
  /* sortflags |= GETSDIR_PARNT; */
Packit 15a96c
  /* modemask = S_IFDIR | S_IFREG; */
Packit 15a96c
Packit 15a96c
  printf("modemask==%x\n", modemask);
Packit 15a96c
Packit 15a96c
  if ((cnt = getsdir(argv[1], argv[2], sortflags, modemask, &dirdat, &len)) == -1) {
Packit 15a96c
    fprintf(stderr, "%s: error getting directory\n", argv[0]);
Packit 15a96c
    exit(1);
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  printf(_("%d files:\n"), cnt);
Packit 15a96c
  for (index = 1; index <= cnt; ++index, ++dirdat)
Packit 15a96c
    printf("%2d: %-20s%s", index, dirdat->fname, ctime(&dirdat->time));
Packit 15a96c
Packit 15a96c
  free(dirdat);
Packit 15a96c
  return 0;
Packit 15a96c
}
Packit 15a96c
#endif