This statement in the man page has bothered me for some time:

| -H, --hard-links
| ...
| This option can be quite slow, so only  use  it  if you need it.

Taking a look at the code, it's clear that every single file is checked to
see if it's a hard link to an existing file.  In particular, the stat field
nlink is never even looked at.

I've patched the program to only run the expensive hard-link check on files
where stat returns nlink > 1.  This keeps the same behavior and
significantly reduces memory usage (down from 30MB to 20MB for copying my
/usr partition).

- James Gritton
  [EMAIL PROTECTED]


--- rsync.h.orig        Sat Aug 19 07:10:39 2000
+++ rsync.h     Thu Sep  7 13:27:30 2000
@@ -297,6 +297,7 @@
        dev_t rdev;
        uid_t uid;
        gid_t gid;
+       nlink_t nlink;
        char *basename;
        char *dirname;
        char *basedir;
@@ -317,6 +318,7 @@
 struct file_list {
        int count;
        int malloced;
+       int hlink_count;
        struct file_struct **files;
        struct string_area *string_area;
 };
--- flist.c.orig        Sat Aug 19 07:10:39 2000
+++ flist.c     Thu Sep  7 14:10:29 2000
@@ -299,8 +299,8 @@
 
 #if SUPPORT_HARD_LINKS
        if (preserve_hard_links && S_ISREG(file->mode)) {
-               write_int(f,(int)file->dev);
-               write_int(f,(int)file->inode);
+               write_int(f,file->nlink > 1 ? (int)file->dev : 0);
+               write_int(f,file->nlink > 1 ? (int)file->inode : 0);
        }
 #endif
 
@@ -554,6 +554,10 @@
 #ifdef HAVE_ST_RDEV
        file->rdev = st.st_rdev;
 #endif
+#if SUPPORT_HARD_LINKS
+       if (preserve_hard_links && S_ISREG(st.st_mode))
+               file->nlink = st.st_nlink;
+#endif
 
 #if SUPPORT_LINKS
        if (S_ISLNK(st.st_mode)) {
@@ -870,6 +874,9 @@
 
   flist->count=0;
   flist->malloced=1000;
+#if SUPPORT_HARD_LINKS
+  flist->hlink_count=0;
+#endif
   flist->files = (struct file_struct **)malloc(sizeof(flist->files[0])*
                                               flist->malloced);
   if (!flist->files)
@@ -893,8 +900,13 @@
 
     receive_file_entry(&flist->files[i],flags,f);
 
-    if (S_ISREG(flist->files[i]->mode))
+    if (S_ISREG(flist->files[i]->mode)) {
            stats.total_size += flist->files[i]->length;
+#if SUPPORT_HARD_LINKS
+           if (preserve_hard_links && flist->files[i]->inode)
+                   flist->hlink_count++;
+#endif
+    }
 
     flist->count++;
 
--- hlink.c.orig        Mon Mar 15 14:23:11 1999
+++ hlink.c     Thu Sep  7 14:10:19 2000
@@ -46,23 +46,26 @@
 void init_hard_links(struct file_list *flist)
 {
 #if SUPPORT_HARD_LINKS
-       int i;
-       if (flist->count < 2) return;
+       int i, j;
+       if (flist->hlink_count < 2) return;
 
        if (hlink_list) free(hlink_list);
     
        if (!(hlink_list = 
-             (struct file_struct *)malloc(sizeof(hlink_list[0])*flist->count)))
+             (struct file_struct *)malloc(sizeof(hlink_list[0])*flist->hlink_count)))
                out_of_memory("init_hard_links");
 
-       for (i = 0; i < flist->count; i++)
-               memcpy(&hlink_list[i], flist->files[i], sizeof(hlink_list[0]));
+       for (i = j = 0; i < flist->count; i++) {
+               if (S_ISREG(flist->files[i]->mode) && flist->files[i]->inode)
+                       memcpy(&hlink_list[j++], flist->files[i],
+                              sizeof(hlink_list[0]));
+       }
 
-       qsort(hlink_list,flist->count,
+       qsort(hlink_list,flist->hlink_count,
              sizeof(hlink_list[0]),
              (int (*)())hlink_compare);
 
-       hlink_count=flist->count;
+       hlink_count=flist->hlink_count;
 #endif
 }
 
@@ -74,7 +77,7 @@
   int low=0,high=hlink_count-1;
   int ret=0;
 
-  if (!hlink_list || !S_ISREG(file->mode)) return 0;
+  if (!hlink_list || !S_ISREG(file->mode) || !file->inode) return 0;
 
   while (low != high) {
     int mid = (low+high)/2;

Reply via email to