]> git.saurik.com Git - apple/file_cmds.git/blobdiff - mtree/spec.c
file_cmds-321.100.10.0.1.tar.gz
[apple/file_cmds.git] / mtree / spec.c
index 88045eea5e12644d9a24040524957c19365dea41..4119124f13bacc80654e2da567545cc56f325aca 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: spec.c,v 1.12 1998/09/23 19:46:00 itohy Exp $  */
-
 /*-
  * Copyright (c) 1989, 1993
  *     The Regents of the University of California.  All rights reserved.
  * 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.
  *
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
-#ifndef lint
 #if 0
-static char sccsid[] = "@(#)spec.c     8.2 (Berkeley) 4/28/95";
-#else
-__RCSID("$NetBSD: spec.c,v 1.12 1998/09/23 19:46:00 itohy Exp $");
-#endif
+#ifndef lint
+static char sccsid[] = "@(#)spec.c     8.1 (Berkeley) 6/6/93";
 #endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/spec.c,v 1.22 2005/03/29 11:44:17 tobez Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <ctype.h>
+#include <err.h>
 #include <errno.h>
 #include <fts.h>
 #include <grp.h>
 #include <pwd.h>
 #include <stdio.h>
-#include <string.h>
+#include <stdint.h>
 #include <unistd.h>
-
+#include <vis.h>
+#include "metrics.h"
 #include "mtree.h"
 #include "extern.h"
 
 int lineno;                            /* Current spec line number. */
 
-static void     set __P((char *, NODE *));
-static void     unset __P((char *, NODE *));
+static void     set(char *, NODE *);
+static void     unset(char *, NODE *);
 
 NODE *
-spec()
+mtree_readspec(FILE *fi)
 {
        NODE *centry, *last;
        char *p;
@@ -70,19 +65,20 @@ spec()
        int c_cur, c_next;
        char buf[2048];
 
-       root = NULL;
-       centry = last = NULL;
-       memset(&ginfo, 0, sizeof(ginfo));
+       centry = last = root = NULL;
+       bzero(&ginfo, sizeof(ginfo));
        c_cur = c_next = 0;
-       for (lineno = 1; fgets(buf, sizeof(buf), stdin);
+       for (lineno = 1; fgets(buf, sizeof(buf), fi);
            ++lineno, c_cur = c_next, c_next = 0) {
                /* Skip empty lines. */
                if (buf[0] == '\n')
                        continue;
 
                /* Find end of line. */
-               if ((p = strchr(buf, '\n')) == NULL)
-                       mtree_err("line %d too long", lineno);
+               if ((p = index(buf, '\n')) == NULL) {
+                       RECORD_FAILURE(21, ERANGE);
+                       errx(1, "line %d too long", lineno);
+               }
 
                /* See if next line is continuation line. */
                if (p[-1] == '\\') {
@@ -107,10 +103,12 @@ spec()
                        set(p, centry);
                        continue;
                }
-                       
+
                /* Grab file name, "$", "set", or "unset". */
-               if ((p = strtok(p, "\n\t ")) == NULL)
-                       mtree_err("missing field");
+               if ((p = strtok(p, "\n\t ")) == NULL) {
+                       RECORD_FAILURE(22, EINVAL);
+                       errx(1, "line %d: missing field", lineno);
+               }
 
                if (p[0] == '/')
                        switch(p[1]) {
@@ -126,8 +124,11 @@ spec()
                                continue;
                        }
 
-               if (strchr(p, '/'))
-                       mtree_err("slash character in file name");
+               if (index(p, '/')) {
+                       RECORD_FAILURE(23, EINVAL);
+                       errx(1, "line %d: slash character in file name",
+                       lineno);
+               }
 
                if (!strcmp(p, "..")) {
                        /* Don't go up, if haven't gone down. */
@@ -141,16 +142,22 @@ spec()
                        last->flags |= F_DONE;
                        continue;
 
-noparent:              mtree_err("no parent node");
+noparent:              RECORD_FAILURE(24, EINVAL);
+                       errx(1, "line %d: no parent node", lineno);
                }
 
-               if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL)
-                       mtree_err("%s", strerror(errno));
+               if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) {
+                       RECORD_FAILURE(25, ENOMEM);
+                       errx(1, "calloc");
+               }
                *centry = ginfo;
-               (void)strcpy(centry->name, p);
 #define        MAGIC   "?*["
                if (strpbrk(p, MAGIC))
                        centry->flags |= F_MAGIC;
+               if (strunvis(centry->name, p) == -1) {
+                       RECORD_FAILURE(26, EILSEQ);
+                       errx(1, "filename %s is ill-encoded", p);
+               }
                set(NULL, centry);
 
                if (!root) {
@@ -169,125 +176,301 @@ noparent:               mtree_err("no parent node");
 }
 
 static void
-set(t, ip)
-       char *t;
-       NODE *ip;
+set(char *t, NODE *ip)
 {
+       int error = 0;
        int type;
-       char *kw, *val;
+       char *kw, *val = NULL;
        struct group *gr;
        struct passwd *pw;
        mode_t *m;
        int value;
        char *ep;
+       char *l;
 
-       val = NULL;
-       for (; (kw = strtok(t, "= \t\n")) != NULL; t = NULL) {
+       for (; (kw = strtok(t, "= \t\n")); t = NULL) {
                ip->flags |= type = parsekey(kw, &value);
-               if (value && (val = strtok(NULL, " \t\n")) == NULL)
-                       mtree_err("missing value");
+               if ((value == 0) || (val = strtok(NULL, " \t\n")) == NULL) {
+                       RECORD_FAILURE(27, EINVAL);
+                       errx(1, "line %d: missing value", lineno);
+               }
                switch(type) {
-               case F_CKSUM:
-                       ip->cksum = strtoul(val, &ep, 10);
-                       if (*ep)
-                               mtree_err("invalid checksum %s", val);
-                       break;
-               case F_GID:
-                       ip->st_gid = (gid_t)strtoul(val, &ep, 10);
-                       if (*ep)
-                               mtree_err("invalid gid %s", val);
-                       break;
-               case F_GNAME:
-                       if ((gr = getgrnam(val)) == NULL)
-                           mtree_err("unknown group %s", val);
-                       ip->st_gid = gr->gr_gid;
-                       break;
-               case F_IGN:
-                       /* just set flag bit */
-                       break;
-               case F_MODE:
-                       if ((m = setmode(val)) == NULL)
-                               mtree_err("invalid file mode %s", val);
-                       ip->st_mode = getmode(m, 0);
-                       free(m);
-                       break;
-               case F_NLINK:
-                       ip->st_nlink = (nlink_t)strtoul(val, &ep, 10);
-                       if (*ep)
-                               mtree_err("invalid link count %s", val);
-                       break;
-               case F_SIZE:
-                       ip->st_size = (off_t)strtoq(val, &ep, 10);
-                       if (*ep)
-                               mtree_err("invalid size %s", val);
-                       break;
-               case F_SLINK:
-                       if ((ip->slink = strdup(val)) == NULL)
-                               mtree_err("%s", strerror(errno));
-                       break;
-               case F_TIME:
-                       ip->st_mtimespec.tv_sec =
-                           (time_t)strtoul(val, &ep, 10);
-                       if (*ep != '.')
-                               mtree_err("invalid time %s", val);
-                       val = ep + 1;
-                       ip->st_mtimespec.tv_nsec = strtol(val, &ep, 10);
-                       if (*ep)
-                               mtree_err("invalid time %s", val);
-                       break;
-               case F_TYPE:
-                       switch(*val) {
-                       case 'b':
-                               if (!strcmp(val, "block"))
-                                       ip->type = F_BLOCK;
+                       case F_CKSUM:
+                               ip->cksum = strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(28, EINVAL);
+                                       errx(1, "line %d: invalid checksum %s",
+                                            lineno, val);
+                               }
                                break;
-                       case 'c':
-                               if (!strcmp(val, "char"))
-                                       ip->type = F_CHAR;
+                       case F_MD5:
+                               ip->md5digest = strdup(val);
+                               if (!ip->md5digest) {
+                                       RECORD_FAILURE(29, ENOMEM);
+                                       errx(1, "strdup");
+                               }
                                break;
-                       case 'd':
-                               if (!strcmp(val, "dir"))
-                                       ip->type = F_DIR;
+                       case F_SHA1:
+                               ip->sha1digest = strdup(val);
+                               if (!ip->sha1digest) {
+                                       RECORD_FAILURE(30, ENOMEM);
+                                       errx(1, "strdup");
+                               }
                                break;
-                       case 'f':
-                               if (!strcmp(val, "file"))
-                                       ip->type = F_FILE;
-                               if (!strcmp(val, "fifo"))
-                                       ip->type = F_FIFO;
+                       case F_SHA256:
+                               ip->sha256digest = strdup(val);
+                               if (!ip->sha256digest) {
+                                       RECORD_FAILURE(31, ENOMEM);
+                                       errx(1, "strdup");
+                               }
                                break;
-                       case 'l':
-                               if (!strcmp(val, "link"))
-                                       ip->type = F_LINK;
+                       case F_RMD160:
+                               ip->rmd160digest = strdup(val);
+                               if (!ip->rmd160digest) {
+                                       RECORD_FAILURE(32, ENOMEM);
+                                       errx(1, "strdup");
+                               }
                                break;
-                       case 's':
-                               if (!strcmp(val, "socket"))
-                                       ip->type = F_SOCK;
+                       case F_FLAGS:
+                               if (strcmp("none", val) == 0) {
+                                       ip->st_flags = 0;
+                               } else if (strtofflags(&val, &ip->st_flags, NULL) != 0) {
+                                       RECORD_FAILURE(33, EINVAL);
+                                       errx(1, "line %d: invalid flag %s",lineno, val);
+                               }
                                break;
-                       default:
-                               mtree_err("unknown file type %s", val);
-                       }
-                       break;
-               case F_UID:
-                       ip->st_uid = (uid_t)strtoul(val, &ep, 10);
-                       if (*ep)
-                               mtree_err("invalid uid %s", val);
-                       break;
-               case F_UNAME:
-                       if ((pw = getpwnam(val)) == NULL)
-                           mtree_err("unknown user %s", val);
-                       ip->st_uid = pw->pw_uid;
-                       break;
+                       case F_GID:
+                               ip->st_gid = (gid_t)strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(34, EINVAL);
+                                       errx(1, "line %d: invalid gid %s", lineno, val);
+                               }
+                               break;
+                       case F_GNAME:
+                               if ((gr = getgrnam(val)) == NULL) {
+                                       RECORD_FAILURE(35, EINVAL);
+                                       errx(1, "line %d: unknown group %s", lineno, val);
+                               }
+                               ip->st_gid = gr->gr_gid;
+                               break;
+                       case F_IGN:
+                               /* just set flag bit */
+                               break;
+                       case F_MODE:
+                               if ((m = setmode(val)) == NULL) {
+                                       RECORD_FAILURE(36, EINVAL);
+                                       errx(1, "line %d: invalid file mode %s",
+                                            lineno, val);
+                               }
+                               ip->st_mode = getmode(m, 0);
+                               free(m);
+                               break;
+                       case F_NLINK:
+                               ip->st_nlink = strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(37, EINVAL);
+                                       errx(1, "line %d: invalid link count %s",
+                                            lineno,  val);
+                               }
+                               break;
+                       case F_SIZE:
+                               ip->st_size = strtoq(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(38, EINVAL);
+                                       errx(1, "line %d: invalid size %s",
+                                            lineno, val);
+                               }
+                               break;
+                       case F_SLINK:
+                               ip->slink = malloc(strlen(val) + 1);
+                               if (ip->slink == NULL) {
+                                       RECORD_FAILURE(39, ENOMEM);
+                                       errx(1, "malloc");
+                               }
+                               if (strunvis(ip->slink, val) == -1) {
+                                       RECORD_FAILURE(40, EILSEQ);
+                                       errx(1, "symlink %s is ill-encoded", val);
+                               }
+                               break;
+                       case F_TIME:
+                               ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(41, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               val = ep + 1;
+                               ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(42, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               break;
+                       case F_TYPE:
+                               switch(*val) {
+                                       case 'b':
+                                               if (!strcmp(val, "block"))
+                                                       ip->type = F_BLOCK;
+                                               break;
+                                       case 'c':
+                                               if (!strcmp(val, "char"))
+                                                       ip->type = F_CHAR;
+                                               break;
+                                       case 'd':
+                                               if (!strcmp(val, "dir"))
+                                                       ip->type = F_DIR;
+                                               break;
+                                       case 'f':
+                                               if (!strcmp(val, "file"))
+                                                       ip->type = F_FILE;
+                                               if (!strcmp(val, "fifo"))
+                                                       ip->type = F_FIFO;
+                                               break;
+                                       case 'l':
+                                               if (!strcmp(val, "link"))
+                                                       ip->type = F_LINK;
+                                               break;
+                                       case 's':
+                                               if (!strcmp(val, "socket"))
+                                                       ip->type = F_SOCK;
+                                               break;
+                                       default:
+                                               RECORD_FAILURE(43, EINVAL);
+                                               errx(1, "line %d: unknown file type %s",
+                                                    lineno, val);
+                               }
+                               break;
+                       case F_UID:
+                               ip->st_uid = (uid_t)strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(44, EINVAL);
+                                       errx(1, "line %d: invalid uid %s", lineno, val);
+                               }
+                               break;
+                       case F_UNAME:
+                               if ((pw = getpwnam(val)) == NULL) {
+                                       RECORD_FAILURE(45, EINVAL);
+                                       errx(1, "line %d: unknown user %s", lineno, val);
+                               }
+                               ip->st_uid = pw->pw_uid;
+                               break;
+                       case F_BTIME:
+                               ip->st_birthtimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(46, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               val = ep + 1;
+                               ip->st_birthtimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(47, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               break;
+                       case F_ATIME:
+                               ip->st_atimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(48, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               val = ep + 1;
+                               ip->st_atimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(49, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               break;
+                       case F_CTIME:
+                               ip->st_ctimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(50, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               val = ep + 1;
+                               ip->st_ctimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(51, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               break;
+                       case F_PTIME:
+                               ip->st_ptimespec.tv_sec = strtoul(val, &ep, 10);
+                               if (*ep != '.') {
+                                       RECORD_FAILURE(52, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               val = ep + 1;
+                               ip->st_ptimespec.tv_nsec = strtoul(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(53, EINVAL);
+                                       errx(1, "line %d: invalid time %s",
+                                            lineno, val);
+                               }
+                               break;
+                       case F_XATTRS:
+                               /*
+                                * Note this is nested inside an strtok loop,
+                                * strtok_r must be used to preserve the strtok context
+                                * of the loop.
+                                */
+                               ep = strtok_r(val,".", &l);
+                               ip->xattrsdigest = strdup(ep);
+                               if (!ip->xattrsdigest) {
+                                       error = errno;
+                                       RECORD_FAILURE(54, error);
+                                       errc(1, error, "strdup");
+                               }
+                               val = strtok_r(NULL,".", &l);
+                               if (val) {
+                                       ip->xdstream_priv_id = strtoull(val, &ep, 10);
+                                       if (*ep) {
+                                               RECORD_FAILURE(55, EINVAL);
+                                               errx(1, "line %d: invalid private id %s",
+                                                    lineno, val);
+                                       }
+                               } else {
+                                       ip->xdstream_priv_id = 0;
+                               }
+                               break;
+                       case F_INODE:
+                               ip->st_ino = (ino_t)strtoull(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(56, EINVAL);
+                                       errx(1, "line %d: invalid inode %s",
+                                            lineno, val);
+                               }
+                               break;
+                       case F_ACL:
+                               ip->acldigest = strdup(val);
+                               if (!ip->acldigest) {
+                                       error = errno;
+                                       RECORD_FAILURE(57, error);
+                                       errc(1, error, "strdup");
+                               }
+                               break;
+                       case F_SIBLINGID:
+                               ip->sibling_id = (quad_t)strtoull(val, &ep, 10);
+                               if (*ep) {
+                                       RECORD_FAILURE(58, EINVAL);
+                                       errx(1, "line %d: invalid sibling id %s", lineno, val);
+                               }
                }
        }
 }
 
 static void
-unset(t, ip)
-       char *t;
-       NODE *ip;
+unset(char *t, NODE *ip)
 {
        char *p;
 
-       while ((p = strtok(t, "\n\t ")) != NULL)
+       while ((p = strtok(t, "\n\t ")))
                ip->flags &= ~parsekey(p, NULL);
 }