From 5243c216d6db4c728c7bf0ad7ab769c9bb6a728b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 29 May 1998 14:36:39 +0000 Subject: [PATCH] replaced chdir and getcwd calls with push_dir/pop_dir functions. These are faster and don't cause problems in a chrooted environment on any systems. --- clientserver.c | 5 +++ flist.c | 61 +++++--------------------------- main.c | 17 ++++----- options.c | 2 +- rsync.yo | 5 ++- util.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 121 insertions(+), 63 deletions(-) diff --git a/clientserver.c b/clientserver.c index 63ff4230..92d9b2c0 100644 --- a/clientserver.c +++ b/clientserver.c @@ -362,6 +362,11 @@ int daemon_main(void) { extern char *config_file; + /* this ensures that we don't call getcwd after the chroot, + which doesn't work on platforms that use popen("pwd","r") + for getcwd */ + push_dir("/", 0); + if (is_a_socket(STDIN_FILENO)) { /* we are running via inetd */ return start_daemon(STDIN_FILENO); diff --git a/flist.c b/flist.c index 179e7e7e..138894f7 100644 --- a/flist.c +++ b/flist.c @@ -90,49 +90,6 @@ static void send_directory(int f,struct file_list *flist,char *dir); static char *flist_dir; -static void clean_fname(char *name) -{ - char *p; - int l; - int modified = 1; - - if (!name) return; - - while (modified) { - modified = 0; - - if ((p=strstr(name,"/./"))) { - modified = 1; - while (*p) { - p[0] = p[2]; - p++; - } - } - - if ((p=strstr(name,"//"))) { - modified = 1; - while (*p) { - p[0] = p[1]; - p++; - } - } - - if (strncmp(p=name,"./",2) == 0) { - modified = 1; - do { - p[0] = p[2]; - } while (*p++); - } - - l = strlen(p=name); - if (l > 1 && p[l-1] == '/') { - modified = 1; - p[l-1] = 0; - } - } -} - - void send_file_entry(struct file_struct *file,int f,unsigned base_flags) { @@ -566,7 +523,6 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) int i,l; STRUCT_STAT st; char *p,*dir; - char dbuf[MAXPATHLEN]; char lastpath[MAXPATHLEN]=""; struct file_list *flist; @@ -646,24 +602,23 @@ struct file_list *send_file_list(int f,int argc,char *argv[]) fname = "."; if (dir && *dir) { - if (getcwd(dbuf,MAXPATHLEN-1) == NULL) { - rprintf(FERROR,"getwd : %s\n",strerror(errno)); - exit_cleanup(1); - } - if (chdir(dir) != 0) { + char *olddir = push_dir(dir, 1); + + if (!olddir) { io_error=1; - rprintf(FERROR,"chdir %s : %s\n", + rprintf(FERROR,"push_dir %s : %s\n", dir,strerror(errno)); continue; } + flist_dir = dir; if (one_file_system) set_filesystem(fname); send_file_name(f,flist,fname,recurse,FLAG_DELETE); flist_dir = NULL; - if (chdir(dbuf) != 0) { - rprintf(FERROR,"chdir %s : %s\n", - dbuf,strerror(errno)); + if (pop_dir(olddir) != 0) { + rprintf(FERROR,"pop_dir %s : %s\n", + dir,strerror(errno)); exit_cleanup(1); } continue; diff --git a/main.c b/main.c index 056863ff..fa4fe0f7 100644 --- a/main.c +++ b/main.c @@ -149,8 +149,8 @@ static char *get_local_name(struct file_list *flist,char *name) if (do_stat(name,&st) == 0) { if (S_ISDIR(st.st_mode)) { - if (chdir(name) != 0) { - rprintf(FERROR,"chdir %s : %s (1)\n", + if (!push_dir(name, 0)) { + rprintf(FERROR,"push_dir %s : %s (1)\n", name,strerror(errno)); exit_cleanup(1); } @@ -176,8 +176,9 @@ static char *get_local_name(struct file_list *flist,char *name) rprintf(FINFO,"created directory %s\n",name); } - if (chdir(name) != 0) { - rprintf(FERROR,"chdir %s : %s (2)\n",name,strerror(errno)); + if (!push_dir(name, 0)) { + rprintf(FERROR,"push_dir %s : %s (2)\n", + name,strerror(errno)); exit_cleanup(1); } @@ -198,8 +199,8 @@ static void do_server_sender(int f_in, int f_out, int argc,char *argv[]) if (verbose > 2) rprintf(FINFO,"server_sender starting pid=%d\n",(int)getpid()); - if (!relative_paths && chdir(dir) != 0) { - rprintf(FERROR,"chdir %s: %s (3)\n",dir,strerror(errno)); + if (!relative_paths && !push_dir(dir, 0)) { + rprintf(FERROR,"push_dir %s: %s (3)\n",dir,strerror(errno)); exit_cleanup(1); } argc--; @@ -289,8 +290,8 @@ static void do_server_recv(int f_in, int f_out, int argc,char *argv[]) dir = argv[0]; argc--; argv++; - if (!am_daemon && chdir(dir) != 0) { - rprintf(FERROR,"chdir %s : %s (4)\n", + if (!am_daemon && !push_dir(dir, 0)) { + rprintf(FERROR,"push_dir %s : %s (4)\n", dir,strerror(errno)); exit_cleanup(1); } diff --git a/options.c b/options.c index 09363abf..434defd0 100644 --- a/options.c +++ b/options.c @@ -79,7 +79,7 @@ void usage(int F) rprintf(F,"Options:\n"); rprintf(F,"-v, --verbose increase verbosity\n"); rprintf(F,"-c, --checksum always checksum\n"); - rprintf(F,"-a, --archive archive mode (same as -rlptDog)\n"); + rprintf(F,"-a, --archive archive mode\n"); rprintf(F,"-r, --recursive recurse into directories\n"); rprintf(F,"-R, --relative use relative path names\n"); rprintf(F,"-b, --backup make backups (default ~ extension)\n"); diff --git a/rsync.yo b/rsync.yo index e3f9c5c3..8c2fae45 100644 --- a/rsync.yo +++ b/rsync.yo @@ -217,9 +217,12 @@ explicitly checked on the receiver and any files of the same name which already exist and have the same checksum and size on the receiver are skipped. This option can be quite slow. -dit(bf(-a, --archive)) This is equivalent to -rlptDog. It is a quick way +dit(bf(-a, --archive)) This is equivalent to -rlptDg. It is a quick way of saying I want recursion and want to preserve everything. +Note: if the user launching rsync is root then the -o option (preserve +uid) is also implied. + dit(bf(-r, --recursive)) This tells rsync to copy directories recursively dit(bf(-R, --relative)) Use relative paths. This means that the full path diff --git a/util.c b/util.c index 6470bf97..11e4a9d9 100644 --- a/util.c +++ b/util.c @@ -559,3 +559,97 @@ void *Realloc(void *p, int size) if (!p) return (void *)malloc(size); return (void *)realloc(p, size); } + + +void clean_fname(char *name) +{ + char *p; + int l; + int modified = 1; + + if (!name) return; + + while (modified) { + modified = 0; + + if ((p=strstr(name,"/./"))) { + modified = 1; + while (*p) { + p[0] = p[2]; + p++; + } + } + + if ((p=strstr(name,"//"))) { + modified = 1; + while (*p) { + p[0] = p[1]; + p++; + } + } + + if (strncmp(p=name,"./",2) == 0) { + modified = 1; + do { + p[0] = p[2]; + } while (*p++); + } + + l = strlen(p=name); + if (l > 1 && p[l-1] == '/') { + modified = 1; + p[l-1] = 0; + } + } +} + + +static char curr_dir[MAXPATHLEN]; + +/* like chdir() but can be reversed with pop_dir() if save is set. It + is also much faster as it remembers where we have been */ +char *push_dir(char *dir, int save) +{ + char *ret = curr_dir; + static int initialised; + + if (!initialised) { + initialised = 1; + getcwd(curr_dir, sizeof(curr_dir)-1); + } + + if (chdir(dir)) return NULL; + + if (save) { + ret = strdup(curr_dir); + } + + if (*dir == '/') { + strlcpy(curr_dir, dir, sizeof(curr_dir)-1); + } else { + strlcat(curr_dir,"/", sizeof(curr_dir)-1); + strlcat(curr_dir,dir, sizeof(curr_dir)-1); + } + + clean_fname(curr_dir); + + return ret; +} + +/* reverse a push_dir call */ +int pop_dir(char *dir) +{ + int ret; + + ret = chdir(dir); + if (ret) { + free(dir); + return ret; + } + + strlcpy(curr_dir, dir, sizeof(curr_dir)-1); + + free(dir); + + return 0; +} -- 2.34.1