X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/e175fb07f7fac17f3f269d1d52557f69feb07882..ac669e8b922c7ace230294f9bf9a3a2bdfbd19d2:/util.c diff --git a/util.c b/util.c index 876b9269..3beae578 100644 --- a/util.c +++ b/util.c @@ -70,7 +70,6 @@ void set_blocking(int fd) } } - /** * Create a file descriptor pair - like pipe() but use socketpair if * possible (because of blocking issues on pipes). @@ -95,7 +94,6 @@ int fd_pair(int fd[2]) return ret; } - void print_child_argv(char **cmd) { rprintf(FINFO, "opening connection using "); @@ -107,15 +105,14 @@ void print_child_argv(char **cmd) "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" ",.-_=+@/") != strlen(*cmd)) { - rprintf(FINFO, "\"%s\" ", safe_fname(*cmd)); + rprintf(FINFO, "\"%s\" ", *cmd); } else { - rprintf(FINFO, "%s ", safe_fname(*cmd)); + rprintf(FINFO, "%s ", *cmd); } } rprintf(FINFO, "\n"); } - void out_of_memory(char *str) { rprintf(FERROR, "ERROR: out of memory in %s\n", str); @@ -128,8 +125,6 @@ void overflow_exit(char *str) exit_cleanup(RERR_MALLOC); } - - int set_modtime(char *fname, time_t modtime, mode_t mode) { #if !defined HAVE_LUTIMES || !defined HAVE_UTIMES @@ -139,7 +134,7 @@ int set_modtime(char *fname, time_t modtime, mode_t mode) if (verbose > 2) { rprintf(FINFO, "set modtime of %s to (%ld) %s", - safe_fname(fname), (long)modtime, + fname, (long)modtime, asctime(localtime(&modtime))); } @@ -174,7 +169,6 @@ int set_modtime(char *fname, time_t modtime, mode_t mode) } } - /** 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 @@ -199,7 +193,6 @@ int create_directory_path(char *fname, int base_umask) return 0; } - /** * Write @p len bytes at @p ptr to descriptor @p desc, retrying if * interrupted. @@ -229,7 +222,6 @@ int full_write(int desc, char *ptr, size_t len) return total_written; } - /** * Read @p len bytes at @p ptr from descriptor @p desc, retrying if * interrupted. @@ -255,12 +247,11 @@ static int safe_read(int desc, char *ptr, size_t len) return n_chars; } - /** Copy a file. * * This is used in conjunction with the --temp-dir, --backup, and * --copy-dest options. */ -int copy_file(char *source, char *dest, mode_t mode) +int copy_file(const char *source, const char *dest, mode_t mode) { int ifd; int ofd; @@ -329,7 +320,7 @@ int copy_file(char *source, char *dest, mode_t mode) * --delete trying to remove old .rsyncNNN files, hence it renames it * each time. **/ -int robust_unlink(char *fname) +int robust_unlink(const char *fname) { #ifndef ETXTBSY return do_unlink(fname); @@ -364,7 +355,7 @@ int robust_unlink(char *fname) if (verbose > 0) { rprintf(FINFO,"renaming %s to %s because of text busy\n", - safe_fname(fname), safe_fname(path)); + fname, path); } /* maybe we should return rename()'s exit status? Nah. */ @@ -377,8 +368,11 @@ int robust_unlink(char *fname) } /* Returns 0 on successful rename, 1 if we successfully copied the file - * across filesystems, -2 if copy_file() failed, and -1 on other errors. */ -int robust_rename(char *from, char *to, int mode) + * across filesystems, -2 if copy_file() failed, and -1 on other errors. + * If partialptr is not NULL and we need to do a copy, copy the file into + * the active partial-dir instead of over the destination file. */ +int robust_rename(char *from, char *to, char *partialptr, + int mode) { int tries = 4; @@ -394,6 +388,11 @@ int robust_rename(char *from, char *to, int mode) break; #endif case EXDEV: + if (partialptr) { + if (!handle_partial_dir(partialptr,PDIR_CREATE)) + return -1; + to = partialptr; + } if (copy_file(from, to, mode) != 0) return -2; do_unlink(from); @@ -405,7 +404,6 @@ int robust_rename(char *from, char *to, int mode) return -1; } - static pid_t all_pids[10]; static int num_pids; @@ -449,7 +447,6 @@ void kill_all(int sig) } } - /** Turn a user name into a uid */ int name_to_uid(char *name, uid_t *uid) { @@ -478,7 +475,6 @@ int name_to_gid(char *name, gid_t *gid) return 0; } - /** Lock a byte range in a open file */ int lock_range(int fd, int offset, int len) { @@ -893,43 +889,6 @@ int pop_dir(char *dir) return 1; } -/* Return the filename, turning any non-printable characters into escaped - * characters (e.g. \n -> \012, \ -> \\). This ensures that outputting it - * cannot generate an empty line nor corrupt the screen. This function can - * return only MAX_SAFE_NAMES values at a time! The returned value can be - * longer than MAXPATHLEN (because we may be trying to output an error about - * a too-long filename)! */ -char *safe_fname(const char *fname) -{ -#define MAX_SAFE_NAMES 4 - static char fbuf[MAX_SAFE_NAMES][MAXPATHLEN*2]; - static int ndx = 0; - int limit = sizeof fbuf / MAX_SAFE_NAMES - 1; - char *t; - - ndx = (ndx + 1) % MAX_SAFE_NAMES; - for (t = fbuf[ndx]; *fname; fname++) { - if (*fname == '\\') { - if ((limit -= 2) < 0) - break; - *t++ = '\\'; - *t++ = '\\'; - } else if (!isprint(*(uchar*)fname)) { - if ((limit -= 4) < 0) - break; - sprintf(t, "\\%03o", *(uchar*)fname); - t += 4; - } else { - if (--limit < 0) - break; - *t++ = *fname; - } - } - *t = '\0'; - - return fbuf[ndx]; -} - /** * Return a quoted string with the full pathname of the indicated filename. * The string " (in MODNAME)" may also be appended. The returned pointer @@ -944,7 +903,6 @@ char *full_fname(const char *fn) if (result) free(result); - fn = safe_fname(fn); if (*fn == '/') p1 = p2 = ""; else { @@ -1039,22 +997,6 @@ int handle_partial_dir(const char *fname, int create) return 1; } -/** We need to supply our own strcmp function for file list comparisons - to ensure that signed/unsigned usage is consistent between machines. */ -int u_strcmp(const char *cs1, const char *cs2) -{ - const uchar *s1 = (const uchar *)cs1; - const uchar *s2 = (const uchar *)cs2; - - while (*s1 && *s2 && (*s1 == *s2)) { - s1++; s2++; - } - - return (int)*s1 - (int)*s2; -} - - - /** * Determine if a symlink points outside the current directory tree. * This is considered "unsafe" because e.g. when mirroring somebody @@ -1132,7 +1074,7 @@ char *human_num(int64 num) if (human_readable) { char units = '\0'; - int mult = human_readable == 1 ? 1024 : 1000; + int mult = human_readable == 1 ? 1000 : 1024; double dnum = 0; if (num > mult*mult*mult) { dnum = (double)num / (mult*mult*mult); @@ -1184,6 +1126,7 @@ char *timestring(time_t t) { static char TimeBuf[200]; struct tm *tm = localtime(&t); + char *p; #ifdef HAVE_STRFTIME strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm); @@ -1191,14 +1134,12 @@ char *timestring(time_t t) strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf); #endif - if (TimeBuf[strlen(TimeBuf)-1] == '\n') { - TimeBuf[strlen(TimeBuf)-1] = 0; - } + if ((p = strchr(TimeBuf, '\n')) != NULL) + *p = '\0'; - return(TimeBuf); + return TimeBuf; } - /** * Sleep for a specified number of milliseconds. * @@ -1227,11 +1168,8 @@ int msleep(int t) return True; } - -/** - * Determine if two file modification times are equivalent (either - * exact or in the modification timestamp window established by - * --modify-window). +/* Determine if two time_t values are equivalent (either exact, or in + * the modification timestamp window established by --modify-window). * * @retval 0 if the times should be treated as the same * @@ -1239,7 +1177,7 @@ int msleep(int t) * * @retval -1 if the 2nd is later **/ -int cmp_modtime(time_t file1, time_t file2) +int cmp_time(time_t file1, time_t file2) { if (file2 > file1) { if (file2 - file1 <= modify_window) @@ -1285,7 +1223,6 @@ int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6) } #endif - #define MALLOC_MAX 0x40000000 void *_new_array(unsigned int size, unsigned long num) @@ -1411,3 +1348,95 @@ uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2) return a[len2-1]; } + +#define BB_SLOT_SIZE (16*1024) /* Desired size in bytes */ +#define BB_PER_SLOT_BITS (BB_SLOT_SIZE * 8) /* Number of bits per slot */ +#define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */ + +struct bitbag { + uint32 **bits; + int slot_cnt; +}; + +struct bitbag *bitbag_create(int max_ndx) +{ + struct bitbag *bb = new(struct bitbag); + bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS; + + if (!(bb->bits = (uint32**)calloc(bb->slot_cnt, sizeof (uint32*)))) + out_of_memory("bitbag_create"); + + return bb; +} + +void bitbag_set_bit(struct bitbag *bb, int ndx) +{ + int slot = ndx / BB_PER_SLOT_BITS; + ndx %= BB_PER_SLOT_BITS; + + if (!bb->bits[slot]) { + if (!(bb->bits[slot] = (uint32*)calloc(BB_PER_SLOT_INTS, 4))) + out_of_memory("bitbag_set_bit"); + } + + bb->bits[slot][ndx/32] |= 1u << (ndx % 32); +} + +#if 0 /* not needed yet */ +void bitbag_clear_bit(struct bitbag *bb, int ndx) +{ + int slot = ndx / BB_PER_SLOT_BITS; + ndx %= BB_PER_SLOT_BITS; + + if (!bb->bits[slot]) + return; + + bb->bits[slot][ndx/32] &= ~(1u << (ndx % 32)); +} + +int bitbag_check_bit(struct bitbag *bb, int ndx) +{ + int slot = ndx / BB_PER_SLOT_BITS; + ndx %= BB_PER_SLOT_BITS; + + if (!bb->bits[slot]) + return 0; + + return bb->bits[slot][ndx/32] & (1u << (ndx % 32)) ? 1 : 0; +} +#endif + +/* Call this with -1 to start checking from 0. Returns -1 at the end. */ +int bitbag_next_bit(struct bitbag *bb, int after) +{ + uint32 bits, mask; + int i, ndx = after + 1; + int slot = ndx / BB_PER_SLOT_BITS; + ndx %= BB_PER_SLOT_BITS; + + mask = (1u << (ndx % 32)) - 1; + for (i = ndx / 32; slot < bb->slot_cnt; slot++, i = mask = 0) { + if (!bb->bits[slot]) + continue; + for ( ; i < BB_PER_SLOT_INTS; i++, mask = 0) { + if (!(bits = bb->bits[slot][i] & ~mask)) + continue; + /* The xor magic figures out the lowest enabled bit in + * bits, and the switch quickly computes log2(bit). */ + switch (bits ^ (bits & (bits-1))) { +#define LOG2(n) case 1u << n: return slot*BB_PER_SLOT_BITS + i*32 + n + LOG2(0); LOG2(1); LOG2(2); LOG2(3); + LOG2(4); LOG2(5); LOG2(6); LOG2(7); + LOG2(8); LOG2(9); LOG2(10); LOG2(11); + LOG2(12); LOG2(13); LOG2(14); LOG2(15); + LOG2(16); LOG2(17); LOG2(18); LOG2(19); + LOG2(20); LOG2(21); LOG2(22); LOG2(23); + LOG2(24); LOG2(25); LOG2(26); LOG2(27); + LOG2(28); LOG2(29); LOG2(30); LOG2(31); + } + return -1; /* impossible... */ + } + } + + return -1; +}