--- generator.c 14 Oct 2005 20:16:09 -0000 1.225 +++ generator.c 17 Oct 2005 23:08:22 -0000 @@ -92,6 +92,8 @@ extern struct file_list *the_file_list; extern struct filter_list_struct server_filter_list; static int deletion_count = 0; /* used to implement --max-delete */ +static int can_link_symlinks = 1; /* start out optimistic */ +static int can_link_devices = 1; static int is_backup_file(char *fn) @@ -585,6 +587,42 @@ void check_for_finished_hlinks(int itemi } } +static int try_link_dest(struct file_struct *file, char *fname, int ndx, + int itemizing, int *possible_ptr) +{ + char fnamebuf[MAXPATHLEN], lnk[MAXPATHLEN]; + STRUCT_STAT st; + int len, i = 0; + + do { + pathjoin(fnamebuf, MAXPATHLEN, basis_dir[i], fname); + if (link_stat(fnamebuf, &st, 0) < 0 || S_ISDIR(st.st_mode) + || !unchanged_attrs(file, &st)) + continue; + if (S_ISLNK(file->mode)) { + if ((len = readlink(fnamebuf, lnk, MAXPATHLEN-1)) <= 0) + continue; + lnk[len] = '\0'; + if (strcmp(lnk, file->u.link) != 0) + continue; + } else { + if (!IS_DEVICE(st.st_mode) || st.st_rdev != file->u.rdev) + continue; + } + if (do_link(fnamebuf, fname) < 0) { + *possible_ptr = 0; /* TODO only do this for some errno values! */ + break; + } + if (itemizing && verbose > 1) { + itemize(file, ndx, -1, NULL, + ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0, ""); + } + return 1; + } while (basis_dir[++i] != NULL); + + return 0; +} + static int phase = 0; /* Acts on the_file_list->file's ndx'th item, whose name is fname. If a dir, @@ -781,6 +819,10 @@ static void recv_generator(char *fname, return; if (!S_ISLNK(st.st_mode)) statret = -1; + } else if (link_dest && can_link_symlinks) { + if (try_link_dest(file, fname, ndx, itemizing, + &can_link_symlinks)) + return; } if (preserve_hard_links && file->link_u.links && hard_link_check(file, ndx, fname, -1, &st, @@ -812,6 +854,11 @@ static void recv_generator(char *fname, } if (am_root && preserve_devices && IS_DEVICE(file->mode)) { + if (statret != 0 && link_dest && can_link_devices) { + if (try_link_dest(file, fname, ndx, itemizing, + &can_link_devices)) + return; + } if (statret != 0 || (st.st_mode & ~CHMOD_BITS) != (file->mode & ~CHMOD_BITS) || st.st_rdev != file->u.rdev) { --- testsuite/itemize.test 24 Jun 2005 02:14:12 -0000 1.9 +++ testsuite/itemize.test 17 Oct 2005 23:08:23 -0000 @@ -170,7 +170,6 @@ cd+++++++ bar/ cd+++++++ bar/baz/ cd+++++++ foo/ hf+++++++ foo/extra => foo/config1 -cL+++++++ foo/sym -> ../bar/baz/rsync EOT diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"