added a --relative (== -R) option. This is what Anthony Thyssen
authorAndrew Tridgell <tridge@samba.org>
Mon, 15 Dec 1997 14:43:27 +0000 (14:43 +0000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 15 Dec 1997 14:43:27 +0000 (14:43 +0000)
suggested on the list recently. See the man page entry for details but
basically it changes the behaviour so that paths are not stripped,
thus allowing you to specify a single rsync command to sync lots of
directories/files while preserving the full path name of each file.
also fixed a bug in the handling of umasks when both the source and
destination machines are local. We need to reset the umask before the
exec to ensure that the child gets a correct umask.

flist.c
main.c
rsync.c
util.c

diff --git a/flist.c b/flist.c
index b3aaff147627e2f439d588aed96541d6dc62d8c6..2ec8318a317f5f02e646d69e46305d3a01f6692e 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -41,6 +41,7 @@ extern int preserve_devices;
 extern int preserve_uid;
 extern int preserve_gid;
 extern int preserve_times;
+extern int relative_paths;
 
 static char **local_exclude_list = NULL;
 
@@ -421,15 +422,19 @@ struct file_list *send_file_list(int f,int argc,char *argv[])
     }
 
     dir = NULL;
-    p = strrchr(fname,'/');
-    if (p) {
-      *p = 0;
-      if (p == fname) 
-       dir = "/";
-      else
-       dir = fname;      
-      fname = p+1;      
+
+    if (!relative_paths) {
+           p = strrchr(fname,'/');
+           if (p) {
+                   *p = 0;
+                   if (p == fname) 
+                           dir = "/";
+                   else
+                           dir = fname;      
+                   fname = p+1;      
+           }
     }
+
     if (!*fname)
       fname = ".";
 
diff --git a/main.c b/main.c
index 936fdb973ebd0dadd123fc40d66feb1250d7e326..09e0ef3391c934019035453e350b909f038d53a4 100644 (file)
--- a/main.c
+++ b/main.c
@@ -49,6 +49,7 @@ int sparse_files=0;
 int do_compression=0;
 int am_root=0;
 int orig_umask=0;
+int relative_paths=0;
 
 extern int csum_length;
 
@@ -134,6 +135,8 @@ static void server_options(char **args,int *argc)
     argstr[x++] = 'C';
   if (ignore_times)
     argstr[x++] = 'I';
+  if (relative_paths)
+    argstr[x++] = 'R';
   if (one_file_system)
     argstr[x++] = 'x';
   if (sparse_files)
@@ -199,7 +202,7 @@ int do_cmd(char *cmd,char *machine,char *user,char *path,int *f_in,int *f_out)
   if (path && *path) {
     char *dir = strdup(path);
     p = strrchr(dir,'/');
-    if (p) {
+    if (p && !relative_paths) {
       *p = 0;
       if (!dir[0])
        args[argc++] = "/";
@@ -240,7 +243,7 @@ static char *get_local_name(struct file_list *flist,char *name)
   if (stat(name,&st) == 0) {
     if (S_ISDIR(st.st_mode)) {
       if (chdir(name) != 0) {
-       fprintf(FERROR,"chdir %s : %s\n",name,strerror(errno));
+       fprintf(FERROR,"chdir %s : %s (1)\n",name,strerror(errno));
        exit_cleanup(1);
       }
       return NULL;
@@ -259,14 +262,14 @@ static char *get_local_name(struct file_list *flist,char *name)
     return NULL;
 
   if (mkdir(name,0777 & ~orig_umask) != 0) {
-    fprintf(FERROR,"mkdir %s : %s\n",name,strerror(errno));
+    fprintf(FERROR,"mkdir %s : %s (1)\n",name,strerror(errno));
     exit_cleanup(1);
   } else {
     fprintf(FINFO,"created directory %s\n",name);
   }
 
   if (chdir(name) != 0) {
-    fprintf(FERROR,"chdir %s : %s\n",name,strerror(errno));
+    fprintf(FERROR,"chdir %s : %s (2)\n",name,strerror(errno));
     exit_cleanup(1);
   }
 
@@ -285,8 +288,8 @@ void do_server_sender(int argc,char *argv[])
   if (verbose > 2)
     fprintf(FERROR,"server_sender starting pid=%d\n",(int)getpid());
   
-  if (chdir(dir) != 0) {
-    fprintf(FERROR,"chdir %s: %s\n",dir,strerror(errno));
+  if (!relative_paths && chdir(dir) != 0) {
+    fprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno));
     exit_cleanup(1);
   }
   argc--;
@@ -361,7 +364,7 @@ void do_server_recv(int argc,char *argv[])
     argc--;
     argv++;
     if (chdir(dir) != 0) {
-      fprintf(FERROR,"chdir %s : %s\n",dir,strerror(errno));
+      fprintf(FERROR,"chdir %s : %s (4)\n",dir,strerror(errno));
       exit_cleanup(1);
     }    
   }
@@ -399,6 +402,7 @@ static void usage(FILE *f)
   fprintf(f,"-c, --checksum           always checksum\n");
   fprintf(f,"-a, --archive            archive mode (same as -rlptDog)\n");
   fprintf(f,"-r, --recursive          recurse into directories\n");
+  fprintf(f,"-R, --relative           use relative path names\n");
   fprintf(f,"-b, --backup             make backups (default ~ extension)\n");
   fprintf(f,"-u, --update             update only (don't overwrite newer files)\n");
   fprintf(f,"-l, --links              preserve soft links\n");
@@ -431,7 +435,7 @@ static void usage(FILE *f)
 enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
       OPT_EXCLUDE_FROM,OPT_DELETE,OPT_RSYNC_PATH};
 
-static char *short_options = "oblHpguDCtcahvrIxnSe:B:z";
+static char *short_options = "oblHpguDCtcahvrRIxnSe:B:z";
 
 static struct option long_options[] = {
   {"version",     0,     0,    OPT_VERSION},
@@ -453,6 +457,7 @@ static struct option long_options[] = {
   {"update",      0,     0,    'u'},
   {"verbose",     0,     0,    'v'},
   {"recursive",   0,     0,    'r'},
+  {"relative",    0,     0,    'R'},
   {"devices",     0,     0,    'D'},
   {"perms",       0,     0,    'p'},
   {"links",       0,     0,    'l'},
@@ -619,6 +624,10 @@ int main(int argc,char *argv[])
          recurse = 1;
          break;
 
+       case 'R':
+         relative_paths = 1;
+         break;
+
        case 'e':
          shell_cmd = optarg;
          break;
diff --git a/rsync.c b/rsync.c
index 77ad9d7ca416d056e6e8c02d77f192b0e8994117..790631fe2e6617be1b1c387e7097f8962720a502 100644 (file)
--- a/rsync.c
+++ b/rsync.c
@@ -46,6 +46,7 @@ extern int recurse;
 extern int delete_mode;
 extern int cvs_exclude;
 extern int am_root;
+extern int relative_paths;
 
 /*
   free a sums struct
@@ -277,8 +278,14 @@ void recv_generator(char *fname,struct file_list *flist,int i,int f_out)
       }
       statret = -1;
     }
-    if (statret != 0 && mkdir(fname,file->mode) != 0 && errno != EEXIST)
-      fprintf(FERROR,"mkdir %s : %s\n",fname,strerror(errno));
+    if (statret != 0 && mkdir(fname,file->mode) != 0 && errno != EEXIST) {
+           if (!(relative_paths && errno==ENOENT && 
+                 create_directory_path(fname)==0 && 
+                 mkdir(fname,file->mode)==0)) {
+                   fprintf(FERROR,"mkdir %s : %s (2)\n",
+                           fname,strerror(errno));
+           }
+    }
     if (set_perms(fname,file,NULL,0) && verbose) 
       fprintf(FINFO,"%s/\n",fname);
     return;
@@ -644,6 +651,10 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
        continue;
       }
       fd2 = open(fnametmp,O_WRONLY|O_CREAT,file->mode);
+      if (relative_paths && errno == ENOENT && 
+         create_directory_path(fnametmp) == 0) {
+             fd2 = open(fnametmp,O_WRONLY|O_CREAT,file->mode);
+      }
       if (fd2 == -1) {
        fprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno));
        receive_data(f_in,buf,-1,NULL);
diff --git a/util.c b/util.c
index 3ecd8120d29d6a2909cdc9b08104fafe17c0599c..e53d02a0e7f90c5974f629df3694573c463fa8c3 100644 (file)
--- a/util.c
+++ b/util.c
@@ -127,6 +127,7 @@ int piped_child(char **command,int *f_in,int *f_out)
 
   if (pid == 0)
     {
+      extern int orig_umask;
       if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 ||
          close(to_child_pipe[1]) < 0 ||
          close(from_child_pipe[0]) < 0 ||
@@ -136,6 +137,7 @@ int piped_child(char **command,int *f_in,int *f_out)
       }
       if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]);
       if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]);
+      umask(orig_umask);
       execvp(command[0], command);
       fprintf(FERROR,"Failed to exec %s : %s\n",
              command[0],strerror(errno));
@@ -226,3 +228,26 @@ int set_blocking(int fd, int set)
   return fcntl( fd, F_SETFL, val);
 #undef FLAG_TO_SET
 }
+
+/****************************************************************************
+create any necessary directories in fname. Unfortunately we don't know
+what perms to give the directory when this is called so we need to rely
+on the umask
+****************************************************************************/
+int create_directory_path(char *fname)
+{
+       extern int orig_umask;
+       char *p;
+
+       while (*fname == '/') fname++;
+       while (strncmp(fname,"./",2)==0) fname += 2;
+
+       p = fname;
+       while ((p=strchr(p,'/'))) {
+               *p = 0;
+               mkdir(fname,0777 & ~orig_umask); 
+               *p = '/';
+               p++;
+       }
+       return 0;
+}