Added --copy-unsafe-links option which is like --copy-links except it is
authorDavid Dykstra <dwd@samba.org>
Wed, 17 Feb 1999 19:34:40 +0000 (19:34 +0000)
committerDavid Dykstra <dwd@samba.org>
Wed, 17 Feb 1999 19:34:40 +0000 (19:34 +0000)
only for symlinks that point outside the source tree.  Suggested by Charles
Hines <chuck_hines@VNET.IBM.COM> in PR#1376.  Also apply the option to any
symbolic links in the source portion of a path when --relative is used,
as suggested by Francis Montagnac <Francis.Montagnac@sophia.inria.fr> on
the rsync mailing list in a message titled "New option: --copy-parent-links".

README
flist.c
options.c
rsync.yo

diff --git a/README b/README
index 5dac7ce2a20f5c9addcbb01260908ef7965fe809..4c5de88886faf1f774a64f91ff302f3554340864 100644 (file)
--- a/README
+++ b/README
@@ -44,6 +44,7 @@ Options
  -u, --update                update only (don't overwrite newer files)
  -l, --links                 preserve soft links
  -L, --copy-links            treat soft links like regular files
+     --copy-unsafe-links     copy links outside the source tree
      --safe-links            ignore links outside the destination tree
  -H, --hard-links            preserve hard links
  -p, --perms                 preserve permissions
diff --git a/flist.c b/flist.c
index e7b1f139a6a48a366507a3746bec3f94f4635fb8..2ec04c884ed147178ff96c65af290fc8f045a6f0 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -44,9 +44,12 @@ extern int preserve_gid;
 extern int preserve_times;
 extern int relative_paths;
 extern int copy_links;
+extern int copy_unsafe_links;
 extern int remote_version;
 extern int io_error;
 
+static char topsrcname[MAXPATHLEN];
+
 static struct exclude_struct **local_exclude_list;
 
 static void clean_flist(struct file_list *flist, int strip_root);
@@ -85,6 +88,32 @@ static void list_file_entry(struct file_struct *f)
 }
 
 
+int readlink_stat(const char *Path, STRUCT_STAT *Buffer, char *Linkbuf) 
+{
+#if SUPPORT_LINKS
+       if (copy_links) {
+               return do_stat(Path, Buffer);
+       }
+       if (do_lstat(Path, Buffer) == -1) {
+               return -1;
+       }
+       if (S_ISLNK(Buffer->st_mode)) {
+               int l;
+               if ((l = readlink(Path,Linkbuf,MAXPATHLEN-1)) == -1) {
+                       return -1;
+               }
+               Linkbuf[l] = 0;
+               if (copy_unsafe_links && (topsrcname[0] != '\0') &&
+                                   unsafe_symlink(Linkbuf, topsrcname)) {
+                       return do_stat(Path, Buffer);
+               }
+       }
+       return 0;
+#else
+       return do_stat(Path, Buffer);
+#endif
+}
+
 int link_stat(const char *Path, STRUCT_STAT *Buffer) 
 {
 #if SUPPORT_LINKS
@@ -373,6 +402,7 @@ static struct file_struct *make_file(char *fname)
        char sum[SUM_LENGTH];
        char *p;
        char cleaned_name[MAXPATHLEN];
+       char linkbuf[MAXPATHLEN];
 
        strlcpy(cleaned_name, fname, MAXPATHLEN);
        cleaned_name[MAXPATHLEN-1] = 0;
@@ -381,7 +411,7 @@ static struct file_struct *make_file(char *fname)
 
        memset(sum,0,SUM_LENGTH);
 
-       if (link_stat(fname,&st) != 0) {
+       if (readlink_stat(fname,&st,linkbuf) != 0) {
                io_error = 1;
                rprintf(FERROR,"%s: %s\n",
                        fname,strerror(errno));
@@ -437,16 +467,7 @@ static struct file_struct *make_file(char *fname)
 
 #if SUPPORT_LINKS
        if (S_ISLNK(st.st_mode)) {
-               int l;
-               char lnk[MAXPATHLEN];
-               if ((l=readlink(fname,lnk,MAXPATHLEN-1)) == -1) {
-                       io_error=1;
-                       rprintf(FERROR,"readlink %s : %s\n",
-                               fname,strerror(errno));
-                       return NULL;
-               }
-               lnk[l] = 0;
-               file->link = strdup(lnk);
+               file->link = strdup(linkbuf);
        }
 #endif
 
@@ -609,8 +630,7 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
        }
 
        for (i=0;i<argc;i++) {
-               char fname2[MAXPATHLEN];
-               char *fname = fname2;
+               char *fname = topsrcname;
 
                strlcpy(fname,argv[i],MAXPATHLEN);
 
@@ -653,7 +673,7 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
                                for (p=fname+1; (p=strchr(p,'/')); p++) {
                                        int copy_links_saved = copy_links;
                                        *p = 0;
-                                       copy_links = 0;
+                                       copy_links = copy_unsafe_links;
                                        send_file_name(f, flist, fname, 0, 0);
                                        copy_links = copy_links_saved;
                                        *p = '/';
@@ -695,6 +715,8 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
                }
        }
 
+       topsrcname[0] = '\0';
+
        if (f != -1) {
                send_file_entry(NULL,f,0);
        }
index ed01a6730466008d2a02883ba2ad77a4d53ffba0..6757144a9717f40131a1d4b21a22eced64775f64 100644 (file)
--- a/options.c
+++ b/options.c
@@ -59,6 +59,7 @@ int do_stats=0;
 int do_progress=0;
 int keep_partial=0;
 int safe_symlinks=0;
+int copy_unsafe_links=0;
 int block_size=BLOCK_SIZE;
 
 char *backup_suffix = BACKUP_SUFFIX;
@@ -104,6 +105,7 @@ void usage(int F)
   rprintf(F," -u, --update                update only (don't overwrite newer files)\n");
   rprintf(F," -l, --links                 preserve soft links\n");
   rprintf(F," -L, --copy-links            treat soft links like regular files\n");
+  rprintf(F,"     --copy-unsafe-links     copy links outside the source tree\n");
   rprintf(F,"     --safe-links            ignore links outside the destination tree\n");
   rprintf(F," -H, --hard-links            preserve hard links\n");
   rprintf(F," -p, --perms                 preserve permissions\n");
@@ -152,7 +154,8 @@ enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
       OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH,
       OPT_FORCE,OPT_TIMEOUT,OPT_DAEMON,OPT_CONFIG,OPT_PORT,
       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_STATS, OPT_PARTIAL, OPT_PROGRESS,
-      OPT_SAFE_LINKS, OPT_COMPARE_DEST, OPT_LOG_FORMAT,OPT_PASSWORD_FILE};
+      OPT_COPY_UNSAFE_LINKS, OPT_SAFE_LINKS, OPT_COMPARE_DEST,
+      OPT_LOG_FORMAT, OPT_PASSWORD_FILE};
 
 static char *short_options = "oblLWHpguDCtcahvqrRIxnSe:B:T:z";
 
@@ -187,6 +190,7 @@ static struct option long_options[] = {
   {"perms",       0,     0,    'p'},
   {"links",       0,     0,    'l'},
   {"copy-links",  0,     0,    'L'},
+  {"copy-unsafe-links", 0, 0,  OPT_COPY_UNSAFE_LINKS},
   {"safe-links",  0,     0,    OPT_SAFE_LINKS},
   {"whole-file",  0,     0,    'W'},
   {"hard-links",  0,     0,    'H'},
@@ -321,6 +325,10 @@ int parse_arguments(int argc, char *argv[], int frommain)
                        add_exclude_file(optarg,1, 1);
                        break;
 
+               case OPT_COPY_UNSAFE_LINKS:
+                       copy_unsafe_links=1;
+                       break;
+
                case OPT_SAFE_LINKS:
                        safe_symlinks=1;
                        break;
@@ -584,6 +592,9 @@ void server_options(char **args,int *argc)
        if (force_delete)
                args[ac++] = "--force";
 
+       if (copy_unsafe_links)
+               args[ac++] = "--copy-unsafe-links";
+
        if (safe_symlinks)
                args[ac++] = "--safe-links";
 
index 00671eb9b58db17dcccc2c7707107ef3ce658c8c..1c946dd576e08ac38c5a95e84d44dba24ed6bf4d 100644 (file)
--- a/rsync.yo
+++ b/rsync.yo
@@ -1,5 +1,5 @@
 mailto(rsync-bugs@samba.org)
-manpage(rsync)(1)(15 Feb 1999)()()
+manpage(rsync)(1)(17 Feb 1999)()()
 manpagename(rsync)(faster, flexible replacement for rcp)
 manpagesynopsis()
 
@@ -233,6 +233,7 @@ Options
  -u, --update                update only (don't overwrite newer files)
  -l, --links                 preserve soft links
  -L, --copy-links            treat soft links like regular files
+     --copy-unsafe-links     copy links outside the source tree
      --safe-links            ignore links outside the destination tree
  -H, --hard-links            preserve hard links
  -p, --perms                 preserve permissions
@@ -349,7 +350,12 @@ remote system  to  be the same as the local system. Without this
 option, all symbolic links are skipped.
 
 dit(bf(-L, --copy-links)) This tells rsync to treat symbolic links just
-like  ordinary files.
+like ordinary files.
+
+dit(bf(--copy-unsafe-links)) This tells rsync to treat symbolic links that
+point outside the source tree like ordinary files.  Absolute symlinks are
+also treated like ordinary files, and so are any symlinks in the source
+path itself when --relative is used.
 
 dit(bf(--safe-links)) This tells rsync to ignore any symbolic links
 which point outside the destination tree. All absolute symlinks are