hush: replace flag bytes in struct o_string with bit flags
[oweals/busybox.git] / editors / diff.c
index 8d91b83bfc8a448779008c5d88125852ab3f465d..83de5275302d2f29e6e0010294fbc7e4513ec736 100644 (file)
@@ -10,7 +10,7 @@
  * Agency (DARPA) and Air Force Research Laboratory, Air Force
  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
  *
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 
 /*
@@ -121,6 +121,7 @@ typedef struct FILE_and_pos_t {
 struct globals {
        smallint exit_status;
        int opt_U_context;
+       const char *other_dir;
        char *label[2];
        struct stat stb[2];
 };
@@ -478,7 +479,7 @@ start:
        for (; suff < nlen[0] - pref && suff < nlen[1] - pref &&
               nfile[0][nlen[0] - suff].value == nfile[1][nlen[1] - suff].value;
               suff++);
-       /* Arrays are pruned by the suffix and prefix lenght,
+       /* Arrays are pruned by the suffix and prefix length,
         * the result being sorted and stored in sfile[fileno],
         * and their sizes are stored in slen[fileno]
         */
@@ -761,9 +762,9 @@ static int FAST_FUNC add_to_dirlist(const char *filename,
 {
        struct dlist *const l = userdata;
        const char *file = filename + l->len;
-       l->dl = xrealloc_vector(l->dl, 6, l->e);
-       while(*file == '/')
+       while (*file == '/')
                file++;
+       l->dl = xrealloc_vector(l->dl, 6, l->e);
        l->dl[l->e] = xstrdup(file);
        l->e++;
        return TRUE;
@@ -780,6 +781,25 @@ static int FAST_FUNC skip_dir(const char *filename,
                add_to_dirlist(filename, sb, userdata, depth);
                return SKIP;
        }
+       if (!(option_mask32 & FLAG(N))) {
+               /* -r without -N: no need to recurse into dirs
+                * which do not exist on the "other side".
+                * Testcase: diff -r /tmp /
+                * (it would recurse deep into /proc without this code) */
+               struct dlist *const l = userdata;
+               filename += l->len;
+               if (filename[0]) {
+                       struct stat osb;
+                       char *othername = concat_path_file(G.other_dir, filename);
+                       int r = stat(othername, &osb);
+                       free(othername);
+                       if (r != 0 || !S_ISDIR(osb.st_mode)) {
+                               /* other dir doesn't have similarly named
+                                * directory, don't recurse */
+                               return SKIP;
+                       }
+               }
+       }
        return TRUE;
 }
 
@@ -793,6 +813,7 @@ static void diffdir(char *p[2], const char *s_start)
                /*list[i].s = list[i].e = 0; - memset did it */
                /*list[i].dl = NULL; */
 
+               G.other_dir = p[1 - i];
                /* We need to trim root directory prefix.
                 * Using list.len to specify its length,
                 * add_to_dirlist will remove it. */