The attached patch gives the user ability to define how many symbolic links rsync should follow before actually adding it to the file list. The patch has been heavily modified from its original form to work with the latest codebase, but even in its original form it didn't handle relative symlinks properly, and that has not yet been fixed in this modified version. --- orig/flist.c 2004-08-12 18:34:38 +++ flist.c 2004-07-16 16:58:04 @@ -49,6 +49,7 @@ extern int filesfrom_fd; extern int one_file_system; extern int keep_dirlinks; extern int preserve_links; +extern int follow_links_depth; extern int preserve_hard_links; extern int preserve_perms; extern int preserve_devices; @@ -724,6 +725,30 @@ void receive_file_entry(struct file_stru } +#if SUPPORT_LINKS +static int links_depth(char *linkname, STRUCT_STAT *st_ptr) +{ + char buf[MAXPATHLEN]; + STRUCT_STAT st; + int i; + + for (i = 0; i < follow_links_depth; i++) { + /* XXX This doesn't handle relative symlinks! */ + if (readlink_stat(linkname, &st, buf) != 0) + break; + *st_ptr = st; + if (!S_ISLNK(st.st_mode)) + return 1; + strlcpy(linkname, buf, MAXPATHLEN); +#if 0 + fprintf(stderr, "\n%s:%i [#%i] %s -> %s\n", __FILE__, __LINE__, i, file->u.link, linkname); +#endif + } + + return 0; +} +#endif + /** * Create a file_struct for a named file by reading its stat() * information and performing extensive checks against global @@ -843,7 +868,13 @@ skip_excludes: basename_len = strlen(basename) + 1; /* count the '\0' */ #if SUPPORT_LINKS - linkname_len = S_ISLNK(st.st_mode) ? strlen(linkname) + 1 : 0; + if (S_ISLNK(st.st_mode)) { + if (follow_links_depth && links_depth(linkname, &st)) + linkname_len = 0; + else + linkname_len = strlen(linkname) + 1; + } else + linkname_len = 0; #else linkname_len = 0; #endif --- orig/options.c 2004-08-12 18:34:38 +++ options.c 2004-07-16 16:12:29 @@ -42,6 +42,7 @@ int archive_mode = 0; int keep_dirlinks = 0; int copy_links = 0; int preserve_links = 0; +int follow_links_depth = 0; int preserve_hard_links = 0; int preserve_perms = 0; int preserve_devices = 0; @@ -244,6 +245,7 @@ void usage(enum logcode F) rprintf(F," --inplace update destination files inplace (SEE MAN PAGE)\n"); rprintf(F," -K, --keep-dirlinks treat symlinked dir on receiver as dir\n"); rprintf(F," -l, --links copy symlinks as symlinks\n"); + rprintf(F," --links-depth=NUM follow symlinks up to NUM depth\n"); rprintf(F," -L, --copy-links copy the referent of all symlinks\n"); rprintf(F," --copy-unsafe-links copy the referent of \"unsafe\" symlinks\n"); rprintf(F," --safe-links ignore \"unsafe\" symlinks\n"); @@ -353,6 +355,7 @@ static struct poptOption long_options[] {"inplace", 0, POPT_ARG_NONE, &inplace, 0, 0, 0 }, {"keep-dirlinks", 'K', POPT_ARG_NONE, &keep_dirlinks, 0, 0, 0 }, {"links", 'l', POPT_ARG_NONE, &preserve_links, 0, 0, 0 }, + {"links-depth", 0, POPT_ARG_INT, &follow_links_depth , 0, 0, 0 }, {"copy-links", 'L', POPT_ARG_NONE, ©_links, 0, 0, 0 }, {"whole-file", 'W', POPT_ARG_VAL, &whole_file, 1, 0, 0 }, {"no-whole-file", 0, POPT_ARG_VAL, &whole_file, 0, 0, 0 },