freshen to upstream CVS head
[debian/pax] / ftree.c
diff --git a/ftree.c b/ftree.c
index f95dd8d03b8b58f681ed8532231563c953f6f815..1ca2a7a1d6315cb07e6ea4043ddb3b83b9d0c271 100644 (file)
--- a/ftree.c
+++ b/ftree.c
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ftree.c,v 1.9 1998/06/09 07:28:41 deraadt Exp $       */
+/*     $OpenBSD: ftree.c,v 1.28 2008/05/06 06:54:28 henning Exp $      */
 /*     $NetBSD: ftree.c,v 1.4 1995/03/21 09:07:21 cgd Exp $    */
 
 /*-
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
+ * 3. Neither the name of the University nor the names of its contributors
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
@@ -40,9 +36,9 @@
 
 #ifndef lint
 #if 0
-static char sccsid[] = "@(#)ftree.c    8.2 (Berkeley) 4/18/94";
+static const char sccsid[] = "@(#)ftree.c      8.2 (Berkeley) 4/18/94";
 #else
-static char rcsid[] = "$OpenBSD: ftree.c,v 1.9 1998/06/09 07:28:41 deraadt Exp $";
+static const char rcsid[] = "$OpenBSD: ftree.c,v 1.28 2008/05/06 06:54:28 henning Exp $";
 #endif
 #endif /* not lint */
 
@@ -74,7 +70,7 @@ static char rcsid[] = "$OpenBSD: ftree.c,v 1.9 1998/06/09 07:28:41 deraadt Exp $
  * pax, they are read from stdin
  */
 
-static FTS *ftsp = NULL;               /* curent FTS handle */
+static FTS *ftsp = NULL;               /* current FTS handle */
 static int ftsopts;                    /* options to be used on fts_open */
 static char *farray[2];                        /* array for passing each arg to fts */
 static FTREE *fthead = NULL;           /* head of linked list of file args */
@@ -83,7 +79,8 @@ static FTREE *ftcur = NULL;           /* current file arg being processed */
 static FTSENT *ftent = NULL;           /* current file tree entry */
 static int ftree_skip;                 /* when set skip to next file arg */
 
-static int ftree_arg __P((void));
+static int ftree_arg(void);
+static char *getpathname(char *, int);
 
 /*
  * ftree_start()
@@ -95,13 +92,8 @@ static int ftree_arg __P((void));
  *     0 if there is at least one valid file arg to process, -1 otherwise
  */
 
-#ifdef __STDC__
 int
 ftree_start(void)
-#else
-int
-ftree_start()
-#endif
 {
        /*
         * set up the operation mode of fts, open the first file arg. We must
@@ -126,11 +118,7 @@ ftree_start()
        else
                ftsopts |= FTS_PHYSICAL;
        if (Hflag)
-#      ifdef NET2_FTS
-               paxwarn(0, "The -H flag is not supported on this version");
-#      else
                ftsopts |= FTS_COMFOLLOW;
-#      endif
        if (Xflag)
                ftsopts |= FTS_XDEV;
 
@@ -154,24 +142,17 @@ ftree_start()
  *     0 if added to the linked list, -1 if failed
  */
 
-#ifdef __STDC__
-int
-ftree_add(register char *str, int chflg)
-#else
 int
-ftree_add(str, chflg)
-       register char *str;
-       int chflg;
-#endif
+ftree_add(char *str, int chflg)
 {
-       register FTREE *ft;
-       register int len;
+       FTREE *ft;
+       int len;
 
        /*
         * simple check for bad args
         */
        if ((str == NULL) || (*str == '\0')) {
-               paxwarn(0, "Invalid file name arguement");
+               paxwarn(0, "Invalid file name argument");
                return(-1);
        }
 
@@ -189,6 +170,7 @@ ftree_add(str, chflg)
                str[len] = '\0';
        ft->fname = str;
        ft->refcnt = 0;
+       ft->newercnt = 0;
        ft->chflg = chflg;
        ft->fow = NULL;
        if (fthead == NULL) {
@@ -206,14 +188,8 @@ ftree_add(str, chflg)
  *     -n and -d processing.
  */
 
-#ifdef __STDC__
-void
-ftree_sel(register ARCHD *arcn)
-#else
 void
-ftree_sel(arcn)
-       register ARCHD *arcn;
-#endif
+ftree_sel(ARCHD *arcn)
 {
        /*
         * set reference bit for this pattern. This linked list is only used
@@ -239,22 +215,30 @@ ftree_sel(arcn)
                (void)fts_set(ftsp, ftent, FTS_SKIP);
 }
 
+/*
+ * ftree_skipped_newer()
+ *     file has been skipped because a newer file exists and -u/-D given
+ */
+
+void
+ftree_skipped_newer(ARCHD *arcn)
+{
+       /* skipped due to -u/-D, mark accordingly */
+       if (ftcur != NULL)
+               ftcur->newercnt = 1;
+}
+
 /*
  * ftree_chk()
  *     called at end on pax execution. Prints all those file args that did not
  *     have a selected member (reference count still 0)
  */
 
-#ifdef __STDC__
 void
 ftree_chk(void)
-#else
-void
-ftree_chk()
-#endif
 {
-       register FTREE *ft;
-       register int wban = 0;
+       FTREE *ft;
+       int wban = 0;
 
        /*
         * make sure all dir access times were reset.
@@ -267,7 +251,7 @@ ftree_chk()
         * that never had a match
         */
        for (ft = fthead; ft != NULL; ft = ft->fow) {
-               if ((ft->refcnt > 0) || ft->chflg)
+               if ((ft->refcnt > 0) || ft->newercnt > 0 || ft->chflg)
                        continue;
                if (wban == 0) {
                        paxwarn(1,"WARNING! These file names were not selected:");
@@ -287,15 +271,9 @@ ftree_chk()
  *     stdin).
  */
 
-#ifdef __STDC__
 static int
 ftree_arg(void)
-#else
-static int
-ftree_arg()
-#endif
 {
-       register char *pt;
 
        /*
         * close off the current file tree
@@ -309,19 +287,17 @@ ftree_arg()
         * keep looping until we get a valid file tree to process. Stop when we
         * reach the end of the list (or get an eof on stdin)
         */
-       for(;;) {
+       for (;;) {
                if (fthead == NULL) {
                        /*
                         * the user didn't supply any args, get the file trees
-                        * to process from stdin; 
+                        * to process from stdin;
                         */
-                       if (fgets(farray[0], PAXPATHLEN+1, stdin) == NULL)
+                       if (getpathname(farray[0], PAXPATHLEN+1) == NULL)
                                return(-1);
-                       if ((pt = strchr(farray[0], '\n')) != NULL)
-                               *pt = '\0';
                } else {
                        /*
-                        * the user supplied the file args as arguements to pax
+                        * the user supplied the file args as arguments to pax
                         */
                        if (ftcur == NULL)
                                ftcur = fthead;
@@ -348,7 +324,7 @@ ftree_arg()
                 * watch it, fts wants the file arg stored in a array of char
                 * ptrs, with the last one a null. we use a two element array
                 * and set farray[0] to point at the buffer with the file name
-                * in it. We cannnot pass all the file args to fts at one shot
+                * in it. We cannot pass all the file args to fts at one shot
                 * as we need to keep a handle on which file arg generates what
                 * files (the -n and -d flags need this). If the open is
                 * successful, return a 0.
@@ -366,23 +342,17 @@ ftree_arg()
  *     0 when contents of arcn have been set with the next file, -1 when done.
  */
 
-#ifdef __STDC__
-int
-next_file(register ARCHD *arcn)
-#else
 int
-next_file(arcn)
-       register ARCHD *arcn;
-#endif
+next_file(ARCHD *arcn)
 {
-       register int cnt;
+       int cnt;
        time_t atime;
        time_t mtime;
 
        /*
         * ftree_sel() might have set the ftree_skip flag if the user has the
         * -n option and a file was selected from this file arg tree. (-n says
-        * only one member is matched for each pattern) ftree_skip being 1 
+        * only one member is matched for each pattern) ftree_skip being 1
         * forces us to go to the next arg now.
         */
        if (ftree_skip) {
@@ -397,8 +367,10 @@ next_file(arcn)
        /*
         * loop until we get a valid file to process
         */
-       for(;;) {
+       for (;;) {
                if ((ftent = fts_read(ftsp)) == NULL) {
+                       if (errno)
+                               syswarn(1, errno, "next_file");
                        /*
                         * out of files in this tree, go to next arg, if none
                         * we are done
@@ -411,7 +383,7 @@ next_file(arcn)
                /*
                 * handle each type of fts_read() flag
                 */
-               switch(ftent->fts_info) {
+               switch (ftent->fts_info) {
                case FTS_D:
                case FTS_DEFAULT:
                case FTS_F:
@@ -430,13 +402,8 @@ next_file(arcn)
                         * remember to force the time (this is -t on a read
                         * directory, not a created directory).
                         */
-#                      ifdef NET2_FTS
-                       if (!tflag || (get_atdir(ftent->fts_statb.st_dev,
-                           ftent->fts_statb.st_ino, &mtime, &atime) < 0))
-#                      else
                        if (!tflag || (get_atdir(ftent->fts_statp->st_dev,
                            ftent->fts_statp->st_ino, &mtime, &atime) < 0))
-#                      endif
                                continue;
                        set_ftime(ftent->fts_path, mtime, atime, 1);
                        continue;
@@ -447,28 +414,16 @@ next_file(arcn)
                        paxwarn(1,"File system cycle found at %s",ftent->fts_path);
                        continue;
                case FTS_DNR:
-#                      ifdef NET2_FTS
-                       syswarn(1, errno,
-#                      else
                        syswarn(1, ftent->fts_errno,
-#                      endif
                            "Unable to read directory %s", ftent->fts_path);
                        continue;
                case FTS_ERR:
-#                      ifdef NET2_FTS
-                       syswarn(1, errno,
-#                      else
                        syswarn(1, ftent->fts_errno,
-#                      endif
                            "File system traversal error");
                        continue;
                case FTS_NS:
                case FTS_NSOK:
-#                      ifdef NET2_FTS
-                       syswarn(1, errno,
-#                      else
                        syswarn(1, ftent->fts_errno,
-#                      endif
                            "Unable to access %s", ftent->fts_path);
                        continue;
                }
@@ -481,11 +436,7 @@ next_file(arcn)
                arcn->pad = 0;
                arcn->ln_nlen = 0;
                arcn->ln_name[0] = '\0';
-#              ifdef NET2_FTS
-               arcn->sb = ftent->fts_statb;
-#              else
-               arcn->sb = *(ftent->fts_statp);
-#              endif
+               memcpy(&arcn->sb, ftent->fts_statp, sizeof(arcn->sb));
 
                /*
                 * file type based set up and copy into the arcn struct
@@ -497,7 +448,7 @@ next_file(arcn)
                 * end in case we cut short a file tree traversal). However
                 * there is no way to reset access times on symlinks.
                 */
-               switch(S_IFMT & arcn->sb.st_mode) {
+               switch (S_IFMT & arcn->sb.st_mode) {
                case S_IFDIR:
                        arcn->type = PAX_DIR;
                        if (!tflag)
@@ -558,8 +509,57 @@ next_file(arcn)
        /*
         * copy file name, set file name length
         */
-       arcn->nlen = l_strncpy(arcn->name, ftent->fts_path, sizeof(arcn->name) - 1);
-       arcn->name[arcn->nlen] = '\0';
+       arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name));
+       if (arcn->nlen >= sizeof(arcn->name))
+               arcn->nlen = sizeof(arcn->name) - 1; /* XXX truncate? */
        arcn->org_name = ftent->fts_path;
        return(0);
 }
+
+/*
+ * getpathname()
+ *     Reads a pathname from stdin, handling NUL- or newline-termination.
+ * Return:
+ *     NULL at end of file, otherwise the NUL-terminated buffer.
+ */
+
+static char *
+getpathname(char *buf, int buflen)
+{
+       char *bp, *ep;
+       int ch, term;
+
+       if (zeroflag) {
+               /*
+                * Read a NUL-terminated pathname, being especially
+                * paranoid about proper termination and pathname length.
+                */
+               for (bp = buf, ep = buf + buflen; bp < ep; bp++) {
+                       if ((ch = getchar()) == EOF) {
+                               if (bp != buf)
+                                       paxwarn(1, "Ignoring unterminated "
+                                           "pathname at EOF");
+                               return(NULL);
+                       }
+                       if ((*bp = ch) == '\0')
+                               return(buf);
+               }
+               /* Too long - skip this path */
+               *--bp = '\0';
+               term = '\0';
+       } else {
+               if (fgets(buf, buflen, stdin) == NULL)
+                       return(NULL);
+               if ((bp = strchr(buf, '\n')) != NULL || feof(stdin)) {
+                       if (bp != NULL)
+                               *bp = '\0';
+                       return(buf);
+               }
+               /* Too long - skip this path */
+               term = '\n';
+       }
+       while ((ch = getchar()) != term && ch != EOF)
+               ;
+       paxwarn(1, "Ignoring too-long pathname: %s", buf);
+       return(NULL);
+}