X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/a5343e765b5652d8e097ea9c398693e60a2d64d2..2f098547ea2415971ac7b38d90246f53116d041f:/util.c diff --git a/util.c b/util.c index 639a4a4f..7be0be30 100644 --- a/util.c +++ b/util.c @@ -98,6 +98,9 @@ int piped_child(char **command,int *f_in,int *f_out) *f_in = from_child_pipe[0]; *f_out = to_child_pipe[1]; + + set_nonblocking(*f_in); + set_nonblocking(*f_out); return pid; } @@ -250,7 +253,7 @@ static int full_write(int desc, char *ptr, int len) for an error. derived from GNU C's cccp.c. */ -int safe_read(int desc, char *ptr, int len) +static int safe_read(int desc, char *ptr, int len) { int n_chars; @@ -291,7 +294,7 @@ int copy_file(char *source, char *dest, mode_t mode) } ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode); - if (ofd < 0) { + if (ofd == -1) { rprintf(FERROR,"open %s: %s\n", dest,strerror(errno)); close(ifd); @@ -407,14 +410,6 @@ int name_to_gid(char *name, gid_t *gid) } -/**************************************************************************** -check if a process exists. -****************************************************************************/ -int process_exists(int pid) -{ - return(kill(pid,0) == 0 || errno != ESRCH); -} - /* lock a byte range in a open file */ int lock_range(int fd, int offset, int len) { @@ -432,7 +427,7 @@ int lock_range(int fd, int offset, int len) static void glob_expand_one(char *s, char **argv, int *argc, int maxargs) { -#ifndef HAVE_GLOB +#if !(defined(HAVE_GLOB) && defined(HAVE_GLOB_H)) if (!*s) s = "."; argv[*argc] = strdup(s); (*argc)++; @@ -512,7 +507,6 @@ void strlower(char *s) pass 1023 for n */ int vslprintf(char *str, int n, const char *format, va_list ap) { -#ifdef HAVE_VSNPRINTF int ret = vsnprintf(str, n, format, ap); if (ret > n || ret < 0) { str[n] = 0; @@ -520,42 +514,6 @@ int vslprintf(char *str, int n, const char *format, va_list ap) } str[ret] = 0; return ret; -#else - static char *buf; - static int len=MAXPATHLEN*8; - int ret; - - /* this code is NOT a proper vsnprintf() implementation. It - relies on the fact that all calls to slprintf() in rsync - pass strings which have already been checked to be less - than MAXPATHLEN in length and never more than 2 strings are - concatenated. This means the above buffer is absolutely - ample and can never be overflowed. - - In the future we would like to replace this with a proper - vsnprintf() implementation but right now we need a solution - that is secure and portable. This is it. */ - - if (!buf) { - buf = malloc(len); - if (!buf) { - /* can't call debug or we would recurse */ - exit_cleanup(1); - } - } - - vsprintf(buf, format, ap); - ret = strlen(buf); - if (ret > n) { - /* yikes! */ - exit_cleanup(1); - } - buf[ret] = 0; - - memcpy(str, buf, ret+1); - - return ret; -#endif } @@ -685,3 +643,122 @@ int u_strcmp(const char *cs1, const char *cs2) return (int)*s1 - (int)*s2; } + +static OFF_T last_ofs; + +void end_progress(void) +{ + extern int do_progress, am_server; + + if (do_progress && !am_server) { + rprintf(FINFO,"\n"); + } + last_ofs = 0; +} + +void show_progress(OFF_T ofs, OFF_T size) +{ + extern int do_progress, am_server; + + if (do_progress && !am_server) { + if (ofs > last_ofs + 1000) { + int pct = (int)((100.0*ofs)/size); + rprintf(FINFO,"%.0f (%d%%)\r", (double)ofs, pct); + last_ofs = ofs; + } + } +} + +/* determine if a symlink points outside the current directory tree */ +int unsafe_symlink(char *dest, char *src) +{ + char *tok; + int depth = 0; + + /* all absolute and null symlinks are unsafe */ + if (!dest || !(*dest) || (*dest == '/')) return 1; + + src = strdup(src); + if (!src) out_of_memory("unsafe_symlink"); + + /* find out what our safety margin is */ + for (tok=strtok(src,"/"); tok; tok=strtok(NULL,"/")) { + if (strcmp(tok,"..") == 0) { + depth=0; + } else if (strcmp(tok,".") == 0) { + /* nothing */ + } else { + depth++; + } + } + free(src); + + /* drop by one to account for the filename portion */ + depth--; + + dest = strdup(dest); + if (!dest) out_of_memory("unsafe_symlink"); + + for (tok=strtok(dest,"/"); tok; tok=strtok(NULL,"/")) { + if (strcmp(tok,"..") == 0) { + depth--; + } else if (strcmp(tok,".") == 0) { + /* nothing */ + } else { + depth++; + } + /* if at any point we go outside the current directory then + stop - it is unsafe */ + if (depth < 0) break; + } + + free(dest); + return (depth < 0); +} + +/* + * Make path appear as if a chroot had occurred: + * 1. remove leading "/" (or replace with "." if at end) + * 2. remove leading ".." components + * 3. delete any other "/.." (recursively) + * Return a malloc'ed copy. + * Contributed by Dave Dykstra + */ + +char *sanitize_path(char *p) +{ + char *copy, *copyp; + + copy = (char *) malloc(strlen(p)+1); + copyp = copy; + while (*p != '\0') { + if ((*p == '/') && (copyp == copy)) { + /* remove leading slash */ + p++; + } + else if ((*p == '.') && (*(p+1) == '.') && + ((*(p+2) == '/') || (*(p+2) == '\0'))) { + /* remove .. followed by slash or end */ + p += 2; + if (copyp != copy) { + /* backup the copy one level */ + while ((--copyp != copy) && (*copyp == '/')) + /* skip trailing slashes */ + ; + while ((copyp != copy) && (*copyp != '/')) + /* skip back through slash */ + copyp--; + } + } else { + /* copy one component */ + while (1) { + *copyp++ = *p++; + if ((*p == '\0') || (*(p-1) == '/')) + break; + } + } + } + *copyp = '\0'; + return(copy); +} +