X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/425094171007944fcfa37311dfae4be010e7c6a1..b084f9e092159b03c955312b0c90fe95eb490b2f:/util.c diff --git a/util.c b/util.c index 13ab38e3..327dd91d 100644 --- a/util.c +++ b/util.c @@ -28,6 +28,7 @@ #include "rsync.h" extern int verbose; +extern struct exclude_list_struct server_exclude_list; int sanitize_paths = 0; @@ -353,18 +354,33 @@ int robust_unlink(char *fname) #endif } -int robust_rename(char *from, char *to) +/* Returns 0 on success, -1 on most errors, and -2 if we got an error + * trying to copy the file across file systems. */ +int robust_rename(char *from, char *to, int mode) { -#ifndef ETXTBSY - return do_rename(from, to); -#else - int rc = do_rename(from, to); - if (rc == 0 || errno != ETXTBSY) - return rc; - if (robust_unlink(to) != 0) - return -1; - return do_rename(from, to); + int tries = 4; + + while (tries--) { + if (do_rename(from, to) == 0) + return 0; + + switch (errno) { +#ifdef ETXTBSY + case ETXTBSY: + if (robust_unlink(to) != 0) + return -1; + break; #endif + case EXDEV: + if (copy_file(from, to, mode) != 0) + return -2; + do_unlink(from); + return 0; + default: + return -1; + } + } + return -1; } @@ -456,12 +472,11 @@ int lock_range(int fd, int offset, int len) static int exclude_server_path(char *arg) { char *s; - extern struct exclude_struct **server_exclude_list; - if (server_exclude_list) { + if (server_exclude_list.head) { for (s = arg; (s = strchr(s, '/')) != NULL; ) { *s = '\0'; - if (check_exclude(server_exclude_list, arg, 1)) { + if (check_exclude(&server_exclude_list, arg, 1) < 0) { /* We must leave arg truncated! */ return 1; } @@ -558,8 +573,8 @@ void strlower(char *s) /* Join strings p1 & p2 into "dest" with a guaranteed '/' between them. (If * p1 ends with a '/', no extra '/' is inserted.) Returns the length of both - * strings + 1 (if '/' was inserted), regardless of whether the whole thing - * fits into destsize (including the terminating '\0'). */ + * strings + 1 (if '/' was inserted), regardless of whether the null-terminated + * string fits into destsize. */ size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2) { size_t len = strlcpy(dest, p1, destsize); @@ -579,9 +594,9 @@ size_t pathjoin(char *dest, size_t destsize, const char *p1, const char *p2) } /* Join any number of strings together, putting them in "dest". The return - * value is the length of all the strings, regardless of whether they fit in - * destsize (including the terminating '\0'). Your list of string pointers - * should end with a NULL to indicate the end of the list. */ + * value is the length of all the strings, regardless of whether the null- + * terminated whole fits in destsize. Your list of string pointers must end + * with a NULL to indicate the end of the list. */ size_t stringjoin(char *dest, size_t destsize, ...) { va_list ap; @@ -760,6 +775,39 @@ void sanitize_path(char *p, char *reldir) *sanp = '\0'; } +/* Works much like sanitize_path(), with these differences: (1) a new buffer + * is allocated for the sanitized path rather than modifying it in-place; (2) + * a leading slash gets transformed into the rootdir value (which can be empty + * or NULL if you just want the slash to get dropped); (3) no "reldir" can be + * specified. */ +char *alloc_sanitize_path(const char *path, const char *rootdir) +{ + char *buf; + int rlen, plen = strlen(path); + + if (*path == '/' && rootdir) { + rlen = strlen(rootdir); + if (rlen == 1) + path++; + } else + rlen = 0; + if (!(buf = new_array(char, rlen + plen + 1))) + out_of_memory("alloc_sanitize_path"); + if (rlen) + memcpy(buf, rootdir, rlen); + memcpy(buf + rlen, path, plen + 1); + + if (rlen > 1) + rlen++; + sanitize_path(buf + rlen, NULL); + if (rlen && buf[rlen] == '.' && buf[rlen+1] == '\0') { + if (rlen > 1) + rlen--; + buf[rlen] = '\0'; + } + + return buf; +} char curr_dir[MAXPATHLEN]; unsigned int curr_dir_len;