From 6574b4f7d938a90a158ba31c03942f8170452df4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 15 Dec 1997 14:43:27 +0000 Subject: [PATCH] added a --relative (== -R) option. This is what Anthony Thyssen 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 | 21 +++++++++++++-------- main.c | 25 +++++++++++++++++-------- rsync.c | 15 +++++++++++++-- util.c | 25 +++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 18 deletions(-) diff --git a/flist.c b/flist.c index b3aaff14..2ec8318a 100644 --- 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 936fdb97..09e0ef33 100644 --- 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 77ad9d7c..790631fe 100644 --- 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 3ecd8120..e53d02a0 100644 --- 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; +} -- 2.34.1