home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 May / W2KPRK.iso / apps / posix / source / PAX / NAMELIST.C < prev    next >
Encoding:
C/C++ Source or Header  |  1999-11-17  |  13.8 KB  |  563 lines

  1. /* $Source: /u/mark/src/pax/RCS/namelist.c,v $
  2.  *
  3.  * $Revision: 1.6 $
  4.  *
  5.  * namelist.c - track filenames given as arguments to tar/cpio/pax
  6.  *
  7.  * DESCRIPTION
  8.  *
  9.  *    Arguments may be regular expressions, therefore all agurments will
  10.  *    be treated as if they were regular expressions, even if they are
  11.  *    not.
  12.  *
  13.  * AUTHOR
  14.  *
  15.  *    Mark H. Colburn, NAPS International (mark@jhereg.mn.org)
  16.  *
  17.  * Sponsored by The USENIX Association for public distribution. 
  18.  *
  19.  * Copyright (c) 1989 Mark H. Colburn.
  20.  * All rights reserved.
  21.  *
  22.  * Redistribution and use in source and binary forms are permitted
  23.  * provided that the above copyright notice is duplicated in all such 
  24.  * forms and that any documentation, advertising materials, and other 
  25.  * materials related to such distribution and use acknowledge that the 
  26.  * software was developed by Mark H. Colburn and sponsored by The 
  27.  * USENIX Association. 
  28.  *
  29.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  30.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  31.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  32.  *
  33.  * $Log:    namelist.c,v $
  34.  * Revision 1.6  89/02/13  09:14:48  mark
  35.  * Fixed problem with directory errors
  36.  * 
  37.  * Revision 1.5  89/02/12  12:14:00  mark
  38.  * Fixed misspellings
  39.  * 
  40.  * Revision 1.4  89/02/12  11:25:19  mark
  41.  * Modifications to compile and link cleanly under USG
  42.  * 
  43.  * Revision 1.3  89/02/12  10:40:23  mark
  44.  * Fixed casting problems
  45.  * 
  46.  * Revision 1.2  89/02/12  10:04:57  mark
  47.  * 1.2 release fixes
  48.  * 
  49.  * Revision 1.1  88/12/23  18:02:17  mark
  50.  * Initial revision
  51.  * 
  52.  */
  53.  
  54. #ifndef lint
  55. static char *ident = "$Id: namelist.c,v 1.6 89/02/13 09:14:48 mark Exp $";
  56. static char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n";
  57. #endif /* ! lint */
  58.  
  59.  
  60. /* Headers */
  61.  
  62. #include "pax.h"
  63.  
  64.  
  65. /* Type Definitions */
  66.  
  67. /*
  68.  * Structure for keeping track of filenames and lists thereof. 
  69.  */
  70. struct nm_list {
  71.     struct nm_list *next;
  72.     short           length;    /* cached strlen(name) */
  73.     char            found;    /* A matching file has been found */
  74.     char            firstch;    /* First char is literally matched */
  75.     char            regexp;    /* regexp pattern for item */
  76.     char            name[1];    /* name of file or rexexp */
  77. };
  78.  
  79. struct dirinfo {
  80.     char            dirname[PATH_MAX + 1];    /* name of directory */
  81.     OFFSET        where;    /* current location in directory */
  82.     struct dirinfo *next;
  83. };
  84.  
  85.  
  86. /* Static Variables */
  87.  
  88. static struct dirinfo *stack_head = (struct dirinfo *)NULL;
  89.  
  90.  
  91. /* Function Prototypes */
  92.  
  93. #ifndef __STDC__
  94.  
  95. static void pushdir();
  96. static struct dirinfo *popdir();
  97.  
  98. #else
  99.  
  100. static void pushdir(struct dirinfo *info);
  101. static struct dirinfo *popdir(void);
  102.  
  103. #endif
  104.  
  105.  
  106. /* Internal Identifiers */
  107.  
  108. static struct nm_list *namelast = NULL;    /* Points to last name in list */  /* Xn */
  109. static struct nm_list *namelist = NULL;    /* Points to first name in list */  /* Xn */
  110.  
  111.  
  112. /* addname -  add a name to the namelist. 
  113.  *
  114.  * DESCRIPTION
  115.  *
  116.  *    Addname adds the name given to the name list.  Memory for the
  117.  *    namelist structure is dynamically allocated.  If the space for 
  118.  *    the structure cannot be allocated, then the program will exit
  119.  *    the an out of memory error message and a non-zero return code
  120.  *    will be returned to the caller.
  121.  *
  122.  * PARAMETERS
  123.  *
  124.  *    char *name    - A pointer to the name to add to the list
  125.  */
  126.  
  127. #ifdef __STDC__
  128.  
  129. void add_name(char *name)
  130.  
  131. #else
  132.     
  133. void add_name(name)
  134. char           *name;        /* pointer to name */
  135.  
  136. #endif
  137. {
  138.     int             i;        /* Length of string */
  139.     struct nm_list *p;        /* Current struct pointer */
  140.  
  141. #ifdef DF_TRACE_DEBUG
  142. printf("DF_TRACE_DEBUG: void add_name() in namelist.c\n");
  143. #endif
  144.     i = strlen(name);
  145.     p = (struct nm_list *) malloc((unsigned) (i + sizeof(struct nm_list)));
  146.     if (!p) {
  147.     fatal("cannot allocate memory for namelist entry\n");
  148.     }
  149.     p->next = (struct nm_list *)NULL;
  150.     p->length = (short)i;  /* Xn */
  151.     strncpy(p->name, name, i);
  152.     p->name[i] = '\0';        /* Null term */
  153.     p->found = 0;
  154.     p->firstch = (char)isalpha(name[0]);  /* Xn */
  155.     if (strchr(name, '*') || strchr(name, '[') || strchr(name, '?')) {
  156.         p->regexp = 1;
  157.     }
  158.     if (namelast) {
  159.     namelast->next = p;
  160.     }
  161.     namelast = p;
  162.     if (!namelist) {
  163.     namelist = p;
  164.     }
  165. }
  166.  
  167.  
  168. /* name_match - match a name from an archive with a name from the namelist 
  169.  *
  170.  * DESCRIPTION
  171.  *
  172.  *    Name_match attempts to find a name pointed at by p in the namelist.
  173.  *    If no namelist is available, then all filenames passed in are
  174.  *    assumed to match the filename criteria.  Name_match knows how to
  175.  *    match names with regular expressions, etc.
  176.  *
  177.  * PARAMETERS
  178.  *
  179.  *    char    *p    - the name to match
  180.  *
  181.  * RETURNS
  182.  *
  183.  *    Returns 1 if the name is in the namelist, or no name list is
  184.  *    available, otherwise returns 0
  185.  *
  186.  */
  187.  
  188. #ifdef __STDC__
  189.  
  190. int name_match(char *p)
  191.  
  192. #else
  193.     
  194. int name_match(p)
  195. char           *p;
  196.  
  197. #endif
  198. {
  199.     struct nm_list *nlp;
  200.     int             len;
  201.  
  202. #ifdef DF_TRACE_DEBUG
  203. printf("DF_TRACE_DEBUG: int name_match() in namelist.c\n");
  204. #endif
  205.     if ((nlp = namelist) == 0) {/* Empty namelist is easy */
  206.     return (1);
  207.     }
  208.     len = strlen(p);
  209.     for (; nlp != 0; nlp = nlp->next) {
  210.     /* If first chars don't match, quick skip */
  211.     if (nlp->firstch && nlp->name[0] != p[0]) {
  212.         continue;
  213.     }
  214.     /* Regular expressions */
  215.     if (nlp->regexp) {
  216.         if (wildmat(nlp->name, p)) {
  217.         nlp->found = 1;    /* Remember it matched */
  218.         return (1);    /* We got a match */
  219.         }
  220.         continue;
  221.     }
  222.     /* Plain Old Strings */
  223.     if (nlp->length <= len    /* Archive len >= specified */
  224.         && (p[nlp->length] == '\0' || p[nlp->length] == '/')
  225.         && strncmp(p, nlp->name, nlp->length) == 0) {
  226.         /* Name compare */
  227.         nlp->found = 1;    /* Remember it matched */
  228.         return (1);        /* We got a match */
  229.     }
  230.     }
  231.     return (0);
  232. }
  233.  
  234.  
  235. /* names_notfound - print names of files in namelist that were not found 
  236.  *
  237.  * DESCRIPTION
  238.  *
  239.  *    Names_notfound scans through the namelist for any files which were
  240.  *    named, but for which a matching file was not processed by the
  241.  *    archive.  Each of the files is listed on the standard error.
  242.  *
  243.  */
  244.  
  245. #ifdef __STDC__
  246.  
  247. void names_notfound(void)
  248.  
  249. #else
  250.     
  251. void names_notfound()
  252.  
  253. #endif
  254. {
  255.     struct nm_list *nlp;
  256.  
  257. #ifdef DF_TRACE_DEBUG
  258. printf("DF_TRACE_DEBUG: void names_notfound() in namelist.c\n");
  259. #endif
  260.     for (nlp = namelist; nlp != 0; nlp = nlp->next) {
  261.     if (!nlp->found) {
  262.         fprintf(stderr, "%s: %s not found in archive\n",
  263.                 myname, nlp->name);
  264.     }
  265.     free(nlp);
  266.     }
  267.     namelist = (struct nm_list *)NULL;
  268.     namelast = (struct nm_list *)NULL;
  269. }
  270.  
  271.  
  272. /* name_init - set up to gather file names 
  273.  *
  274.  * DESCRIPTION
  275.  *
  276.  *    Name_init sets up the namelist pointers so that we may access the
  277.  *    command line arguments.  At least the first item of the command
  278.  *    line (argv[0]) is assumed to be stripped off, prior to the
  279.  *    name_init call.
  280.  *
  281.  * PARAMETERS
  282.  *
  283.  *    int    argc    - number of items in argc
  284.  *    char    **argv    - pointer to the command line arguments
  285.  */
  286.  
  287. #ifdef __STDC__
  288.  
  289. void name_init(int argc, char **argv)
  290.  
  291. #else
  292.     
  293. void name_init(argc, argv)
  294. int             argc;
  295. char          **argv;
  296.  
  297. #endif
  298. {
  299.     /* Get file names from argv, after options. */
  300. #ifdef DF_TRACE_DEBUG
  301. printf("DF_TRACE_DEBUG: void name_init() in namelist.c\n");
  302. #endif
  303.     n_argc = argc;
  304.     n_argv = argv;
  305. }
  306.  
  307.  
  308. /* name_next - get the next name from argv or the name file. 
  309.  *
  310.  * DESCRIPTION
  311.  *
  312.  *    Name next finds the next name which is to be processed in the
  313.  *    archive.  If the named file is a directory, then the directory
  314.  *    is recursively traversed for additional file names.  Directory
  315.  *    names and locations within the directory are kept track of by
  316.  *    using a directory stack.  See the pushdir/popdir function for
  317.  *    more details.
  318.  *
  319.  *     The names come from argv, after options or from the standard input.  
  320.  *
  321.  * PARAMETERS
  322.  *
  323.  *    name - a pointer to a buffer of at least MAX_PATH + 1 bytes long;
  324.  *    statbuf - a pointer to a stat structure
  325.  *
  326.  * RETURNS
  327.  *
  328.  *    Returns -1 if there are no names left, (e.g. EOF), otherwise returns 
  329.  *    0 
  330.  */
  331.  
  332. #ifdef __STDC__
  333.  
  334. int name_next(char *name, Stat *statbuf)
  335.  
  336. #else
  337.     
  338. int name_next(name, statbuf)
  339. char           *name;
  340. Stat           *statbuf;
  341.  
  342. #endif
  343. {
  344.     int                     err = -1;  /* Xn */
  345.     static int              in_subdir = 0;  /* Xn */
  346.     static DIR             *dirp = NULL;  /* Xn */
  347.     struct dirent          *d;  /* Xn */
  348.     static struct dirinfo  *curr_dir = NULL;  /* Xn */
  349.     int                     len;  /* Xn */
  350.  
  351.     do {
  352. #ifdef DF_TRACE_DEBUG
  353. printf("DF_TRACE_DEBUG: int name_next() in namelist.c\n");
  354. #endif
  355.     if (names_from_stdin) {
  356.         if (lineget(stdin, name) < 0) {
  357.         return (-1);
  358.         }
  359.         if (nameopt(name) < 0) {
  360.         continue;
  361.         }
  362.     } else {
  363.         if (in_subdir) {
  364.         if ((d = readdir(dirp)) != (struct dirent *)NULL) {
  365.             /* Skip . and .. */
  366.             if (strcmp(d->d_name, ".") == 0 ||
  367.                 strcmp(d->d_name, "..") == 0) {
  368.                 continue;
  369.             }
  370. #ifdef DF_TRACE_DEBUG
  371. printf("DF_TRACE_DEBUG:                 strcmp() in namelist.c\n");
  372. #endif
  373.             if (strlen(d->d_name) + 
  374.             strlen(curr_dir->dirname) >= PATH_MAX) {
  375. #ifdef DF_TRACE_DEBUG
  376. printf("DF_TRACE_DEBUG:             strlen() in namelist.c\n");
  377. #endif
  378.             warn("name too long", d->d_name);
  379.             continue;
  380.             }
  381.             strcpy(name, curr_dir->dirname);
  382.             strcat(name, d->d_name);
  383.         } else {
  384.             closedir(dirp);
  385.             in_subdir--;
  386.             curr_dir = popdir();
  387.             if (in_subdir) {
  388.             errno = 0;
  389.             if ((dirp=opendir(curr_dir->dirname)) == (DIR *)NULL) {
  390.                 warn(curr_dir->dirname, "error opening directory (1)");
  391.                 in_subdir--;
  392.             }
  393.             seekdir(dirp, curr_dir->where);
  394.             }
  395.             continue;
  396.         }
  397.         } else if (optind >= n_argc) {
  398.         return (-1);
  399.         } else {
  400.         strcpy(name, n_argv[optind++]);
  401.         }
  402.     }
  403.     if ((err = LSTAT(name, statbuf)) < 0) {
  404.         warn(name, strerror(errno));  /* Xn */
  405.         continue;
  406.     }
  407. #if 0
  408.     (void) fprintf(stderr, "namelist.c/name_next - name: \"%s\"; statbuf->sb_stat.st_uid: %lu; statbuf->sb_stat.st_gid: %lu\n",
  409.         name, (unsigned long) statbuf->sb_stat.st_uid, (unsigned long) statbuf->sb_stat.st_gid);
  410.     (void) fflush(stderr);
  411. #endif /* Xn 1993-06-23 */
  412.     if (!names_from_stdin && (statbuf->sb_mode & S_IFMT) == S_IFDIR) {
  413.         if (in_subdir) {
  414.         curr_dir->where = telldir(dirp);
  415.         pushdir(curr_dir);
  416.         closedir(dirp);
  417.         } 
  418.         in_subdir++;
  419.  
  420.         /* Build new prototype name */
  421.         if ((curr_dir = (struct dirinfo *) mem_get(sizeof(struct dirinfo))) 
  422.               == (struct dirinfo *)NULL) {
  423. #if 1 && WIN_NT
  424.         if (ppid == (pid_t) 1 && globulation == 0)
  425.             deglobulate();
  426. #endif
  427.         exit(2);
  428.         }
  429.         strcpy(curr_dir->dirname, name);
  430.         len = strlen(curr_dir->dirname);
  431.         while (len >= 1 && curr_dir->dirname[len - 1] == '/') {
  432.         len--;        /* Delete trailing slashes */
  433.         }
  434.         curr_dir->dirname[len++] = '/';    /* Now add exactly one back */
  435.         curr_dir->dirname[len] = '\0';/* Make sure null-terminated */
  436.             curr_dir->where = 0;
  437.            
  438.             errno = 0;
  439.             do {
  440.                 if ((dirp = opendir(curr_dir->dirname)) == (DIR *)NULL) {
  441.                      warn(curr_dir->dirname, "error opening directory (2)");
  442.                      if (in_subdir > 1) {
  443.                           curr_dir = popdir();
  444.                      }
  445.                      in_subdir--;
  446.                      err = -1;
  447.                      continue;
  448.                 } else {
  449.                      seekdir(dirp, curr_dir->where);
  450.         }
  451.         } while (in_subdir && (! dirp));
  452.     }
  453.     } while (err < 0);
  454.     return (0);
  455. }
  456.  
  457.  
  458. /* name_gather - gather names in a list for scanning. 
  459.  *
  460.  * DESCRIPTION
  461.  *
  462.  *    Name_gather takes names from the command line and adds them to
  463.  *    the name list.
  464.  *
  465.  * FIXME
  466.  *
  467.  *     We could hash the names if we really care about speed here.
  468.  */
  469.  
  470. #ifdef __STDC__
  471.  
  472. void name_gather(void)
  473.  
  474. #else
  475.     
  476. void name_gather()
  477.  
  478. #endif
  479. {
  480. #ifdef DF_TRACE_DEBUG
  481. printf("DF_TRACE_DEBUG: void name_gather() in namelist.c\n");
  482. #endif
  483.      while (optind < n_argc) { 
  484.      add_name(n_argv[optind++]); 
  485.      } 
  486. }
  487.  
  488.  
  489. /* pushdir - pushes a directory name on the directory stack
  490.  *
  491.  * DESCRIPTION
  492.  *
  493.  *    The pushdir function puses the directory structure which is pointed
  494.  *    to by "info" onto a stack for later processing.  The information
  495.  *    may be retrieved later with a call to popdir().
  496.  *
  497.  * PARAMETERS
  498.  *
  499.  *    dirinfo    *info    - pointer to directory structure to save
  500.  */
  501.  
  502. #ifdef __STDC__
  503.  
  504. static void pushdir(struct dirinfo *info)
  505.  
  506. #else
  507.     
  508. static void pushdir(info)
  509. struct dirinfo    *info;
  510.  
  511. #endif
  512. {
  513. #ifdef DF_TRACE_DEBUG
  514. printf("DF_TRACE_DEBUG: static void pushdir() in namelist.c\n");
  515. #endif
  516.     if  (stack_head == (struct dirinfo *)NULL) {
  517.     stack_head = info;
  518.     stack_head->next = (struct dirinfo *)NULL;
  519.     } else {
  520.     info->next = stack_head;
  521.     stack_head = info;
  522.     } 
  523. }
  524.  
  525.  
  526. /* popdir - pop a directory structure off the directory stack.
  527.  *
  528.  * DESCRIPTION
  529.  *
  530.  *    The popdir function pops the most recently pushed directory
  531.  *    structure off of the directory stack and returns it to the calling
  532.  *    function.
  533.  *
  534.  * RETURNS
  535.  *
  536.  *    Returns a pointer to the most recently pushed directory structure
  537.  *    or NULL if the stack is empty.
  538.  */
  539.  
  540. #ifdef __STDC__
  541.  
  542. static struct dirinfo *popdir(void)
  543.  
  544. #else
  545.     
  546. static struct dirinfo *popdir()
  547.  
  548. #endif
  549. {
  550.     struct dirinfo    *tmp;
  551.  
  552. #ifdef DF_TRACE_DEBUG
  553. printf("DF_TRACE_DEBUG: static struct dirinfo *popdir() in namelist.c\n");
  554. #endif
  555.     if (stack_head == (struct dirinfo *)NULL) {
  556.     return((struct dirinfo *)NULL);
  557.     } else {
  558.     tmp = stack_head;
  559.     stack_head = stack_head->next;
  560.     }
  561.     return(tmp);
  562. }
  563.