X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/3ba62a830825f5e1e1f70a8ec1f85abeaadc3f1f..2b6b4d539b0aab98b1cbb9d8c639cb12473aae94:/util.c diff --git a/util.c b/util.c index 6537717d..f54acd2c 100644 --- a/util.c +++ b/util.c @@ -32,76 +32,129 @@ int num_waiting(int fd) } -struct map_struct *map_file(int fd,off_t len) +struct map_struct *map_file(int fd,OFF_T len) { - struct map_struct *ret; - ret = (struct map_struct *)malloc(sizeof(*ret)); - if (!ret) out_of_memory("map_file"); - - ret->map = NULL; - ret->fd = fd; - ret->size = len; - ret->p = NULL; - ret->p_size = 0; - ret->p_offset = 0; - ret->p_len = 0; - -#ifdef HAVE_MMAP - if (len < MAX_MAP_SIZE) - ret->map = (char *)mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0); + struct map_struct *ret; + ret = (struct map_struct *)malloc(sizeof(*ret)); + if (!ret) out_of_memory("map_file"); + + ret->map = NULL; + ret->fd = fd; + ret->size = len; + ret->p = NULL; + ret->p_size = 0; + ret->p_offset = 0; + ret->p_len = 0; + +#ifdef USE_MMAP + len = MIN(len, MAX_MAP_SIZE); + ret->map = (char *)do_mmap(NULL,len,PROT_READ,MAP_SHARED,fd,0); + if (ret->map == (char *)-1) { + ret->map = NULL; + } else { + ret->p_len = len; + } #endif - return ret; + return ret; } -char *map_ptr(struct map_struct *map,off_t offset,int len) + +char *map_ptr(struct map_struct *map,OFF_T offset,int len) { - int nread = -2; + int nread; - if (map->map) - return map->map+offset; + if (len == 0) + return NULL; - if (len == 0) - return NULL; + if (len > (map->size-offset)) + len = map->size-offset; - len = MIN(len,map->size-offset); +#ifdef USE_MMAP + if (map->map) { + if (offset >= map->p_offset && + offset+len <= map->p_offset+map->p_len) { + return (map->map + (offset - map->p_offset)); + } + if (munmap(map->map, map->p_len) != 0) { + rprintf(FERROR,"munmap failed : %s\n", strerror(errno)); + exit_cleanup(1); + } - if (offset >= map->p_offset && - offset+len <= map->p_offset+map->p_len) { - return (map->p + (offset - map->p_offset)); - } + /* align the mmap region on a nice boundary back a bit from + where it is asked for to allow for some seeking */ + if (offset > 2*CHUNK_SIZE) { + map->p_offset = offset - 2*CHUNK_SIZE; + map->p_offset &= ~((OFF_T)(CHUNK_SIZE-1)); + } else { + map->p_offset = 0; + } + + /* map up to MAX_MAP_SIZE */ + map->p_len = MAX(len, MAX_MAP_SIZE); + map->p_len = MIN(map->p_len, map->size - map->p_offset); + + map->map = (char *)do_mmap(NULL,map->p_len,PROT_READ, + MAP_SHARED,map->fd,map->p_offset); + + if (map->map == (char *)-1) { + map->map = NULL; + map->p_len = 0; + map->p_offset = 0; + } else { + return (map->map + (offset - map->p_offset)); + } + } +#endif - len = MAX(len,CHUNK_SIZE); - len = MIN(len,map->size - offset); + if (offset >= map->p_offset && + offset+len <= map->p_offset+map->p_len) { + return (map->p + (offset - map->p_offset)); + } - if (len > map->p_size) { - if (map->p) free(map->p); - map->p = (char *)malloc(len); - if (!map->p) out_of_memory("map_ptr"); - map->p_size = len; - } + len = MAX(len,CHUNK_SIZE); + if (len > (map->size-offset)) + len = map->size-offset; - if (lseek(map->fd,offset,SEEK_SET) != offset || - (nread=read(map->fd,map->p,len)) != len) { - fprintf(FERROR,"EOF in map_ptr! (offset=%d len=%d nread=%d errno=%d)\n", - (int)offset, len, nread, errno); - exit_cleanup(1); - } + if (len > map->p_size) { + if (map->p) free(map->p); + map->p = (char *)malloc(len); + if (!map->p) out_of_memory("map_ptr"); + map->p_size = len; + } + + map->p_offset = offset; + map->p_len = len; - map->p_offset = offset; - map->p_len = len; + if (do_lseek(map->fd,offset,SEEK_SET) != offset) { + rprintf(FERROR,"lseek failed in map_ptr\n"); + exit_cleanup(1); + } - return map->p; + if ((nread=read(map->fd,map->p,len)) != len) { + if (nread < 0) nread = 0; + /* the best we can do is zero the buffer - the file + has changed mid transfer! */ + memset(map->p+nread, 0, len - nread); + } + + return map->p; } void unmap_file(struct map_struct *map) { -#ifdef HAVE_MMAP - if (map->map) - munmap(map->map,map->size); +#ifdef USE_MMAP + if (map->map) { + munmap(map->map,map->p_len); + map->map = NULL; + } #endif - if (map->p) free(map->p); - free(map); + if (map->p) { + free(map->p); + map->p = NULL; + } + memset(map, 0, sizeof(*map)); + free(map); } @@ -114,14 +167,14 @@ int piped_child(char **command,int *f_in,int *f_out) if (pipe(to_child_pipe) < 0 || pipe(from_child_pipe) < 0) { - fprintf(FERROR,"pipe: %s\n",strerror(errno)); + rprintf(FERROR,"pipe: %s\n",strerror(errno)); exit_cleanup(1); } pid = do_fork(); if (pid < 0) { - fprintf(FERROR,"fork: %s\n",strerror(errno)); + rprintf(FERROR,"fork: %s\n",strerror(errno)); exit_cleanup(1); } @@ -132,21 +185,21 @@ int piped_child(char **command,int *f_in,int *f_out) close(to_child_pipe[1]) < 0 || close(from_child_pipe[0]) < 0 || dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { - fprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno)); + rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno)); exit_cleanup(1); } 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", + rprintf(FERROR,"Failed to exec %s : %s\n", command[0],strerror(errno)); exit_cleanup(1); } if (close(from_child_pipe[1]) < 0 || close(to_child_pipe[0]) < 0) { - fprintf(FERROR,"Failed to close : %s\n",strerror(errno)); + rprintf(FERROR,"Failed to close : %s\n",strerror(errno)); exit_cleanup(1); } @@ -156,10 +209,67 @@ int piped_child(char **command,int *f_in,int *f_out) return pid; } +int local_child(int argc, char **argv,int *f_in,int *f_out) +{ + int pid; + int to_child_pipe[2]; + int from_child_pipe[2]; + + if (pipe(to_child_pipe) < 0 || + pipe(from_child_pipe) < 0) { + rprintf(FERROR,"pipe: %s\n",strerror(errno)); + exit_cleanup(1); + } + + + pid = do_fork(); + if (pid < 0) { + rprintf(FERROR,"fork: %s\n",strerror(errno)); + exit_cleanup(1); + } + + if (pid == 0) { + extern int am_sender; + extern int am_server; + + am_sender = !am_sender; + am_server = 1; + + if (dup2(to_child_pipe[0], STDIN_FILENO) < 0 || + close(to_child_pipe[1]) < 0 || + close(from_child_pipe[0]) < 0 || + dup2(from_child_pipe[1], STDOUT_FILENO) < 0) { + rprintf(FERROR,"Failed to dup/close : %s\n",strerror(errno)); + exit_cleanup(1); + } + if (to_child_pipe[0] != STDIN_FILENO) close(to_child_pipe[0]); + if (from_child_pipe[1] != STDOUT_FILENO) close(from_child_pipe[1]); + start_server(STDIN_FILENO, STDOUT_FILENO, argc, argv); + } + + if (close(from_child_pipe[1]) < 0 || + close(to_child_pipe[0]) < 0) { + rprintf(FERROR,"Failed to close : %s\n",strerror(errno)); + exit_cleanup(1); + } + + *f_in = from_child_pipe[0]; + *f_out = to_child_pipe[1]; + + return pid; +} + + void out_of_memory(char *str) { - fprintf(FERROR,"out of memory in %s\n",str); + rprintf(FERROR,"ERROR: out of memory in %s\n",str); + exit_cleanup(1); +} + +void overflow(char *str) +{ + rprintf(FERROR,"ERROR: buffer overflow in %s\n",str); exit_cleanup(1); } @@ -167,24 +277,28 @@ void out_of_memory(char *str) int set_modtime(char *fname,time_t modtime) { + extern int dry_run; + if (dry_run) return 0; + { #ifdef HAVE_UTIMBUF - struct utimbuf tbuf; - tbuf.actime = time(NULL); - tbuf.modtime = modtime; - return utime(fname,&tbuf); + struct utimbuf tbuf; + tbuf.actime = time(NULL); + tbuf.modtime = modtime; + return utime(fname,&tbuf); #elif defined(HAVE_UTIME) - time_t t[2]; - t[0] = time(NULL); - t[1] = modtime; - return utime(fname,t); + time_t t[2]; + t[0] = time(NULL); + t[1] = modtime; + return utime(fname,t); #else - struct timeval t[2]; - t[0].tv_sec = time(NULL); - t[0].tv_usec = 0; - t[1].tv_sec = modtime; - t[1].tv_usec = 0; - return utimes(fname,t); + struct timeval t[2]; + t[0].tv_sec = time(NULL); + t[0].tv_usec = 0; + t[1].tv_sec = modtime; + t[1].tv_usec = 0; + return utimes(fname,t); #endif + } } @@ -234,7 +348,7 @@ int create_directory_path(char *fname) p = fname; while ((p=strchr(p,'/'))) { *p = 0; - mkdir(fname,0777 & ~orig_umask); + do_mkdir(fname,0777 & ~orig_umask); *p = '/'; p++; } @@ -302,20 +416,20 @@ int copy_file(char *source, char *dest, mode_t mode) ifd = open(source, O_RDONLY); if (ifd == -1) { - fprintf(FERROR,"open %s: %s\n", + rprintf(FERROR,"open %s: %s\n", source,strerror(errno)); return -1; } - if (unlink(dest) && errno != ENOENT) { - fprintf(FERROR,"unlink %s: %s\n", + if (do_unlink(dest) && errno != ENOENT) { + rprintf(FERROR,"unlink %s: %s\n", dest,strerror(errno)); return -1; } - ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode); + ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode); if (ofd < 0) { - fprintf(FERROR,"open %s: %s\n", + rprintf(FERROR,"open %s: %s\n", dest,strerror(errno)); close(ifd); return -1; @@ -323,7 +437,7 @@ int copy_file(char *source, char *dest, mode_t mode) while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) { if (full_write(ofd, buf, len) < 0) { - fprintf(FERROR,"write %s: %s\n", + rprintf(FERROR,"write %s: %s\n", dest,strerror(errno)); close(ifd); close(ofd); @@ -335,7 +449,7 @@ int copy_file(char *source, char *dest, mode_t mode) close(ofd); if (len < 0) { - fprintf(FERROR,"read %s: %s\n", + rprintf(FERROR,"read %s: %s\n", source,strerror(errno)); return -1; } @@ -377,3 +491,220 @@ void kill_all(int sig) kill(all_pids[i], sig); } } + +/* like strncpy but does not 0 fill the buffer and always null + terminates (thus it can use maxlen+1 space in d) */ +void strlcpy(char *d, char *s, int maxlen) +{ + int len = strlen(s); + if (len > maxlen) len = maxlen; + memcpy(d, s, len); + d[len] = 0; +} + +/* like strncat but does not 0 fill the buffer and always null + terminates (thus it can use maxlen+1 space in d) */ +void strlcat(char *d, char *s, int maxlen) +{ + int len1 = strlen(d); + int len2 = strlen(s); + if (len1+len2 > maxlen) { + len2 = maxlen-len1; + } + if (len2 > 0) { + memcpy(d+len1, s, len2); + d[len1+len2] = 0; + } +} + +/* turn a user name into a uid */ +int name_to_uid(char *name, uid_t *uid) +{ + struct passwd *pass; + if (!name || !*name) return 0; + pass = getpwnam(name); + if (pass) { + *uid = pass->pw_uid; + return 1; + } + return 0; +} + +/* turn a group name into a gid */ +int name_to_gid(char *name, gid_t *gid) +{ + struct group *grp; + if (!name || !*name) return 0; + grp = getgrnam(name); + if (grp) { + *gid = grp->gr_gid; + return 1; + } + return 0; +} + + +/**************************************************************************** +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) +{ + struct flock lock; + + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + lock.l_start = offset; + lock.l_len = len; + lock.l_pid = 0; + + return fcntl(fd,F_SETLK,&lock) == 0; +} + + +static void glob_expand_one(char *s, char **argv, int *argc, int maxargs) +{ +#ifndef HAVE_GLOB + if (!*s) s = "."; + argv[*argc] = strdup(s); + (*argc)++; + return; +#else + glob_t globbuf; + int i; + + if (!*s) s = "."; + + argv[*argc] = strdup(s); + + memset(&globbuf, 0, sizeof(globbuf)); + glob(argv[*argc], 0, NULL, &globbuf); + if (globbuf.gl_pathc == 0) { + (*argc)++; + globfree(&globbuf); + return; + } + for (i=0; i<(maxargs - (*argc)) && i n || ret < 0) { + str[n] = 0; + return -1; + } + 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 +} + + +/* like snprintf but always null terminates */ +int slprintf(char *str, int n, char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = vslprintf(str,n,format,ap); + va_end(ap); + return ret; +} +