Updated to work with latest generator/receiver changes.
[rsync/rsync-patches.git] / unique-dirs.diff
1 This tries to keep symlink loops from happening when using
2 the --copy-links option (on the sender) and when using the
3 --keep-dirlinks option with --delete (on the receiver).  It
4 would be nice to improve this so that duplicates get turned
5 back into symlinks, but the code needs to know which one is
6 the real dir (if it is present in the list) because that one
7 entry can't be turned into a symlink.
8
9 --- flist.c     12 Aug 2004 18:20:07 -0000      1.236
10 +++ flist.c     31 Aug 2004 20:44:33 -0000
11 @@ -724,6 +724,43 @@ void receive_file_entry(struct file_stru
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
55 @@ -802,9 +839,17 @@ struct file_struct *make_file(char *fnam
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