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;