Add DIRTREE_SHUTUP to disable dirtree warnings if file vanishes out from
authorRob Landley <rob@landley.net>
Sat, 9 May 2015 23:11:22 +0000 (18:11 -0500)
committerRob Landley <rob@landley.net>
Sat, 9 May 2015 23:11:22 +0000 (18:11 -0500)
under traversal. Pass through full flag set in dirtree_add_node(), add
dirtree_start() wrapper to provide symlink-only behavior (avoiding a lot
of DIRTREE_SYMFOLLOW*!!(logic) repeated in callers).

lib/dirtree.c
lib/lib.h
toys/pending/diff.c
toys/pending/tar.c
toys/posix/chgrp.c
toys/posix/cp.c
toys/posix/du.c
toys/posix/find.c
toys/posix/ls.c

index 60ce56b..1e89816 100644 (file)
@@ -24,22 +24,21 @@ int dirtree_notdotdot(struct dirtree *catch)
 // (This doesn't open directory filehandles yet so as not to exhaust the
 // filehandle space on large trees, dirtree_handle_callback() does that.)
 
-struct dirtree *dirtree_add_node(struct dirtree *parent, char *name,
-  int symfollow)
+struct dirtree *dirtree_add_node(struct dirtree *parent, char *name, int flags)
 {
   struct dirtree *dt = NULL;
   struct stat st;
-  char buf[4096];
   int len = 0, linklen = 0;
 
   if (name) {
     // open code this because haven't got node to call dirtree_parentfd() on yet
     int fd = parent ? parent->data : AT_FDCWD;
 
-    if (fstatat(fd, name, &st, symfollow ? 0 : AT_SYMLINK_NOFOLLOW)) goto error;
+    if (fstatat(fd, name, &st, AT_SYMLINK_NOFOLLOW*!(flags&DIRTREE_SYMFOLLOW)))
+      goto error;
     if (S_ISLNK(st.st_mode)) {
-      if (0>(linklen = readlinkat(fd, name, buf, 4095))) goto error;
-      buf[linklen++]=0;
+      if (0>(linklen = readlinkat(fd, name, libbuf, 4095))) goto error;
+      libbuf[linklen++]=0;
     }
     len = strlen(name);
   }
@@ -50,7 +49,7 @@ struct dirtree *dirtree_add_node(struct dirtree *parent, char *name,
     strcpy(dt->name, name);
 
     if (linklen) {
-      dt->symlink = memcpy(len+(char *)dt, buf, linklen);
+      dt->symlink = memcpy(len+(char *)dt, libbuf, linklen);
       dt->data = --linklen;
     }
   }
@@ -58,7 +57,7 @@ struct dirtree *dirtree_add_node(struct dirtree *parent, char *name,
   return dt;
 
 error:
-  if (notdotdot(name)) {
+  if (!(flags&DIRTREE_SHUTUP) && notdotdot(name)) {
     char *path = parent ? dirtree_path(parent, 0) : "";
 
     perror_msg("%s%s%s", path, parent ? "/" : "", name);
@@ -111,13 +110,13 @@ int dirtree_parentfd(struct dirtree *node)
 struct dirtree *dirtree_handle_callback(struct dirtree *new,
           int (*callback)(struct dirtree *node))
 {
-  int flags, dir = S_ISDIR(new->st.st_mode);
+  int flags;
 
+  if (!new) return 0;
   if (!callback) callback = dirtree_notdotdot;
-
   flags = callback(new);
 
-  if (dir) {
+  if (S_ISDIR(new->st.st_mode)) {
     if (flags & (DIRTREE_RECURSE|DIRTREE_COMEAGAIN)) {
       new->data = openat(dirtree_parentfd(new), new->name, O_CLOEXEC);
       flags = dirtree_recurse(new, callback, flags);
@@ -144,9 +143,11 @@ int dirtree_recurse(struct dirtree *node,
   DIR *dir;
 
   if (node->data == -1 || !(dir = fdopendir(node->data))) {
-    char *path = dirtree_path(node, 0);
-    perror_msg("No %s", path);
-    free(path);
+    if (!(flags & DIRTREE_SHUTUP)) {
+      char *path = dirtree_path(node, 0);
+      perror_msg("No %s", path);
+      free(path);
+    }
     close(node->data);
 
     return flags;
@@ -157,8 +158,7 @@ int dirtree_recurse(struct dirtree *node,
 
   // The extra parentheses are to shut the stupid compiler up.
   while ((entry = readdir(dir))) {
-    if (!(new = dirtree_add_node(node, entry->d_name, flags&DIRTREE_SYMFOLLOW)))
-      continue;
+    if (!(new = dirtree_add_node(node, entry->d_name, flags))) continue;
     new = dirtree_handle_callback(new, callback);
     if (new == DIRTREE_ABORTVAL) break;
     if (new) {
@@ -179,14 +179,19 @@ int dirtree_recurse(struct dirtree *node,
   return flags;
 }
 
+// Create dirtree root
+struct dirtree *dirtree_start(char *name, int symfollow)
+{
+  return dirtree_add_node(0, name, DIRTREE_SYMFOLLOW*!!symfollow);
+}
+
 // Create dirtree from path, using callback to filter nodes.
 // If callback == NULL allocate a tree of struct dirtree nodes and return
 // pointer to root node.
-// symfollow is just for the top of tree, callback return code controls children
 
 struct dirtree *dirtree_read(char *path, int (*callback)(struct dirtree *node))
 {
-  struct dirtree *root = dirtree_add_node(0, path, 0);
+  struct dirtree *root = dirtree_start(path, 0);
 
   return root ? dirtree_handle_callback(root, callback) : DIRTREE_ABORTVAL;
 }
index be4051e..03a0570 100644 (file)
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -50,6 +50,8 @@ void get_optflags(void);
 #define DIRTREE_COMEAGAIN    4
 // Follow symlinks to directories
 #define DIRTREE_SYMFOLLOW    8
+// Don't warn about failure to stat
+#define DIRTREE_SHUTUP      16
 // Don't look at any more files in this directory.
 #define DIRTREE_ABORT      256
 
@@ -65,7 +67,8 @@ struct dirtree {
   char name[];
 };
 
-struct dirtree *dirtree_add_node(struct dirtree *p, char *name, int symfollow);
+struct dirtree *dirtree_start(char *name, int symfollow);
+struct dirtree *dirtree_add_node(struct dirtree *p, char *name, int flags);
 char *dirtree_path(struct dirtree *node, int *plen);
 int dirtree_notdotdot(struct dirtree *catch);
 int dirtree_parentfd(struct dirtree *node);
index 1b3f80b..8023861 100644 (file)
@@ -768,7 +768,6 @@ void diff_main(void)
   struct stat st[2];
   int j = 0, k = 1, start[2] = {1, 1};
   char *files[2];
-  struct dirtree *root;
 
   for (j = 0; j < 2; j++) {
     files[j] = toys.optargs[j];
@@ -799,8 +798,7 @@ void diff_main(void)
   if (S_ISDIR(st[0].st_mode) && S_ISDIR(st[1].st_mode)) {
     for (j = 0; j < 2; j++) {
       memset(&dir[j], 0, sizeof(dir));
-      root = dirtree_add_node(0, files[j], 1);
-      if (root) dirtree_handle_callback(root, list_dir);
+      dirtree_handle_callback(dirtree_start(files[j], 1), list_dir);
       dir[j].nr_elm = TT.size; //size updated in list_dir
       qsort(&(dir[j].list[1]), (TT.size - 1), sizeof(char*), cmp);
 
index f44465c..c8b6dff 100644 (file)
@@ -788,9 +788,8 @@ void tar_main(void)
     for (tmp = TT.inc; tmp; tmp = tmp->next) {
       TT.handle = tar_hdl;
       //recurse thru dir and add files to archive
-      struct dirtree *root = dirtree_add_node(0,tmp->arg,toys.optflags & FLAG_h);
-
-      if (root) dirtree_handle_callback(root, add_to_tar);
+      dirtree_handle_callback(dirtree_start(tmp->arg, toys.optflags & FLAG_h),
+        add_to_tar);
     }
     memset(toybuf, 0, 1024);
     writeall(tar_hdl->src_fd, toybuf, 1024);
index fb82adb..6b95c6a 100644 (file)
@@ -49,12 +49,11 @@ static int do_chgrp(struct dirtree *node)
   // Depth first search
   if (!dirtree_notdotdot(node)) return 0;
   if ((flags & FLAG_R) && !node->again && S_ISDIR(node->st.st_mode))
-    return DIRTREE_COMEAGAIN|((flags&FLAG_L) ? DIRTREE_SYMFOLLOW : 0);
+    return DIRTREE_COMEAGAIN|(DIRTREE_SYMFOLLOW*!!(flags&FLAG_L));
 
   fd = dirtree_parentfd(node);
   ret = fchownat(fd, node->name, TT.owner, TT.group,
-    (flags&(FLAG_L|FLAG_H)) || !(flags&(FLAG_h|FLAG_R))
-      ? 0 : AT_SYMLINK_NOFOLLOW);
+    AT_SYMLINK_NOFOLLOW*(!(flags&(FLAG_L|FLAG_H)) && (flags&(FLAG_h|FLAG_R))));
 
   if (ret || (flags & FLAG_v)) {
     char *path = dirtree_path(node, 0);
@@ -74,7 +73,7 @@ static int do_chgrp(struct dirtree *node)
 
 void chgrp_main(void)
 {
-  int ischown = toys.which->name[2] == 'o', hl = toys.optflags&(FLAG_H|FLAG_L);
+  int ischown = toys.which->name[2] == 'o';
   char **s, *own;
 
   TT.owner = TT.group = -1;
@@ -94,11 +93,9 @@ void chgrp_main(void)
   if (TT.group_name && *TT.group_name)
     TT.group = xgetgrnamid(TT.group_name)->gr_gid;
 
-  for (s=toys.optargs+1; *s; s++) {
-    struct dirtree *new = dirtree_add_node(0, *s, hl);
-    if (new) dirtree_handle_callback(new, do_chgrp);
-    else toys.exitval = 1;
-  }
+  for (s=toys.optargs+1; *s; s++)
+    dirtree_handle_callback(dirtree_start(*s, toys.optflags&(FLAG_H|FLAG_L)),
+      do_chgrp);;
 
   if (CFG_TOYBOX_FREE && ischown) free(own);
 }
index 2959f67..df8269f 100644 (file)
@@ -340,9 +340,9 @@ void cp_main(void)
 
     // Skip nonexistent sources
     if (rc) {
-      int symfollow = toys.optflags & (FLAG_H|FLAG_L);
+      int symfollow = DIRTREE_SYMFOLLOW*!!(toys.optflags & (FLAG_H|FLAG_L));
 
-      if (errno != EXDEV || !(new = dirtree_add_node(0, src, symfollow)))
+      if (errno != EXDEV || !(new = dirtree_start(src, symfollow)))
           perror_msg("bad '%s'", src);
       else dirtree_handle_callback(new, TT.callback);
     }
index 00a7f68..0dea495 100644 (file)
@@ -104,7 +104,8 @@ static int seen_inode(void **list, struct stat *st)
 // dirtree callback, comput/display size of node
 static int do_du(struct dirtree *node)
 {
-  if (node->parent && !dirtree_notdotdot(node)) return 0;
+  if (!node->parent) TT.st_dev = node->st.st_dev;
+  else if (!dirtree_notdotdot(node)) return 0;
 
   // detect swiching filesystems
   if ((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev))
@@ -146,21 +147,12 @@ static int do_du(struct dirtree *node)
 
 void du_main(void)
 {
-  char *noargs[] = {".", 0};
-  struct dirtree *root;
-
-  if (!toys.optc) toys.optargs = noargs;
+  char *noargs[] = {".", 0}, **args;
 
   // Loop over command line arguments, recursing through children
-  while (*toys.optargs) {
-    root = dirtree_add_node(0, *toys.optargs, toys.optflags & (FLAG_H|FLAG_L));
-
-    if (root) {
-      TT.st_dev = root->st.st_dev;
-      dirtree_handle_callback(root, do_du);
-    }
-    toys.optargs++;
-  }
+  for (args = toys.optc ? toys.optargs : noargs; *args; args++)
+    dirtree_handle_callback(dirtree_start(*args,
+      DIRTREE_SYMFOLLOW*!!(toys.optflags & (FLAG_H|FLAG_L))), do_du);
   if (toys.optflags & FLAG_c) print(TT.total*512, 0);
 
   if (CFG_TOYBOX_FREE) seen_inode(TT.inodes, 0);
index 69e370d..73502b4 100644 (file)
@@ -531,12 +531,9 @@ void find_main(void)
   do_find(0);
 
   // Loop through paths
-  for (i = 0; i < len; i++) {
-    struct dirtree *new;
-
-    new = dirtree_add_node(0, ss[i], toys.optflags&(FLAG_H|FLAG_L));
-    if (new) dirtree_handle_callback(new, do_find);
-  }
+  for (i = 0; i < len; i++)
+    dirtree_handle_callback(dirtree_start(ss[i], toys.optflags&(FLAG_H|FLAG_L)),
+      do_find);
 
   if (CFG_TOYBOX_FREE) {
     close(TT.topdir);
index 5dd6bc5..3e5d391 100644 (file)
@@ -540,10 +540,10 @@ void ls_main(void)
 
   // Iterate through command line arguments, collecting directories and files.
   // Non-absolute paths are relative to current directory.
-  TT.files = dirtree_add_node(0, 0, 0);
+  TT.files = dirtree_start(0, 0);
   for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) {
-    dt = dirtree_add_node(0, *s, !(toys.optflags & (FLAG_l|FLAG_d|FLAG_F))
-      || (toys.optflags & (FLAG_L|FLAG_H)));
+    dt = dirtree_start(*s, !(toys.optflags&(FLAG_l|FLAG_d|FLAG_F)) ||
+                            (toys.optflags&(FLAG_L|FLAG_H)));
 
     if (!dt) {
       toys.exitval = 1;