Updated to apply cleanly.
[rsync/rsync-patches.git] / unique-dirs.diff
CommitLineData
3848d3f0
WD
1This tries to keep symlink loops from happening when using
2the --copy-links option (on the sender) and when using the
3--keep-dirlinks option with --delete (on the receiver). It
4would be nice to improve this so that duplicates get turned
5back into symlinks, but the code needs to know which one is
6the real dir (if it is present in the list) because that one
7entry can't be turned into a symlink.
8
a6587818
WD
9--- orig/flist.c 2004-09-21 09:40:27
10+++ flist.c 2004-08-31 20:44:33
11@@ -726,6 +726,43 @@ void receive_file_entry(struct file_stru
3848d3f0
WD
12 }
13
14
15+static BOOL saw_dir(dev_t dev, ino_t ino)
16+{
17+ static struct dirinfo { dev_t dev; ino_t ino; } *dirarray;
18+ static int dirarray_cnt, dirarray_size;
19+ int low, high;
20+
21+ if (dirarray_cnt == dirarray_size) {
22+ dirarray = realloc_array(dirarray, struct dirinfo,
23+ dirarray_size += 4096);
24+ }
25+
26+ for (low = 0, high = dirarray_cnt - 1; low <= high; ) {
27+ int mid = (low + high) / 2;
28+ if (ino == dirarray[mid].ino) {
29+ if (dev == dirarray[mid].dev)
30+ return True;
31+ if (dev > dirarray[mid].dev)
32+ low = mid + 1;
33+ else
34+ high = mid - 1;
35+ } else if (ino > dirarray[mid].ino)
36+ low = mid + 1;
37+ else
38+ high = mid - 1;
39+ }
40+
41+ if (low < dirarray_cnt) {
42+ memmove(dirarray + low + 1, dirarray + low,
43+ (dirarray_cnt - low) * sizeof dirarray[0]);
44+ }
45+ dirarray[low].dev = dev;
46+ dirarray[low].ino = ino;
47+ dirarray_cnt++;
48+
49+ return False;
50+}
51+
52 /**
53 * Create a file_struct for a named file by reading its stat()
54 * information and performing extensive checks against global
a6587818 55@@ -804,9 +841,17 @@ struct file_struct *make_file(char *fnam
3848d3f0
WD
56 if (exclude_level == NO_EXCLUDES)
57 goto skip_excludes;
58
59- if (S_ISDIR(st.st_mode) && !recurse && !files_from) {
60- rprintf(FINFO, "skipping directory %s\n", thisname);
61- return NULL;
62+ if (S_ISDIR(st.st_mode)) {
63+ if (!recurse && !files_from) {
64+ rprintf(FINFO, "skipping directory %s\n", thisname);
65+ return NULL;
66+ }
67+ if ((keep_dirlinks || copy_links)
68+ && saw_dir(st.st_dev, st.st_ino)) {
69+ rprintf(FINFO, "skipping duplicate directory %s\n",
70+ thisname);
71+ return NULL;
72+ }
73 }
74
75 /* We only care about directories because we need to avoid recursing