diff: make diff -r much less eager to recurse into directories

function                                             old     new   delta
skip_dir                                              44     120     +76
diff_main                                           1175    1185     +10

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2010-07-10 16:25:47 +02:00
parent a48a29f921
commit 75703eb8d5

View File

@ -121,6 +121,7 @@ typedef struct FILE_and_pos_t {
struct globals { struct globals {
smallint exit_status; smallint exit_status;
int opt_U_context; int opt_U_context;
const char *other_dir;
char *label[2]; char *label[2];
struct stat stb[2]; struct stat stb[2];
}; };
@ -761,7 +762,7 @@ static int FAST_FUNC add_to_dirlist(const char *filename,
{ {
struct dlist *const l = userdata; struct dlist *const l = userdata;
const char *file = filename + l->len; const char *file = filename + l->len;
while(*file == '/') while (*file == '/')
file++; file++;
l->dl = xrealloc_vector(l->dl, 6, l->e); l->dl = xrealloc_vector(l->dl, 6, l->e);
l->dl[l->e] = xstrdup(file); l->dl[l->e] = xstrdup(file);
@ -780,6 +781,25 @@ static int FAST_FUNC skip_dir(const char *filename,
add_to_dirlist(filename, sb, userdata, depth); add_to_dirlist(filename, sb, userdata, depth);
return SKIP; 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; 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].s = list[i].e = 0; - memset did it */
/*list[i].dl = NULL; */ /*list[i].dl = NULL; */
G.other_dir = p[1 - i];
/* We need to trim root directory prefix. /* We need to trim root directory prefix.
* Using list.len to specify its length, * Using list.len to specify its length,
* add_to_dirlist will remove it. */ * add_to_dirlist will remove it. */