X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/63cf5ae72cc8f844bb8b478de0343f862db40a41..0f78b81511be65d8fe21af1e6ac674f9e80ac29d:/util.c diff --git a/util.c b/util.c index 3d88b15c..2ec56a7c 100644 --- a/util.c +++ b/util.c @@ -1,8 +1,10 @@ -/* -*- c-file-style: "linux" -*- +/* + * Utility routines used in rsync. * - * Copyright (C) 1996-2000 by Andrew Tridgell - * Copyright (C) Paul Mackerras 1996 - * Copyright (C) 2001, 2002 by Martin Pool + * Copyright (C) 1996-2000 Andrew Tridgell + * Copyright (C) 1996 Paul Mackerras + * Copyright (C) 2001, 2002 Martin Pool + * Copyright (C) 2003, 2004, 2005, 2006 Wayne Davison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,15 +18,9 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/** - * @file - * - * Utilities used in rsync - **/ - #include "rsync.h" extern int verbose; @@ -33,16 +29,13 @@ extern int module_id; extern int modify_window; extern int relative_paths; extern int human_readable; +extern mode_t orig_umask; extern char *partial_dir; extern struct filter_list_struct server_filter_list; int sanitize_paths = 0; - - -/** - * Set a fd into nonblocking mode - **/ +/* Set a fd into nonblocking mode. */ void set_nonblocking(int fd) { int val; @@ -55,9 +48,7 @@ void set_nonblocking(int fd) } } -/** - * Set a fd into blocking mode - **/ +/* Set a fd into blocking mode. */ void set_blocking(int fd) { int val; @@ -70,7 +61,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 +85,6 @@ int fd_pair(int fd[2]) return ret; } - void print_child_argv(char **cmd) { rprintf(FINFO, "opening connection using "); @@ -115,7 +104,6 @@ void print_child_argv(char **cmd) rprintf(FINFO, "\n"); } - void out_of_memory(char *str) { rprintf(FERROR, "ERROR: out of memory in %s\n", str); @@ -128,8 +116,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 @@ -174,31 +160,44 @@ int set_modtime(char *fname, time_t modtime, mode_t mode) } } +/* This creates a new directory with default permissions. Since there + * might be some directory-default permissions affecting this, we can't + * force the permissions directly using the original umask and mkdir(). */ +int mkdir_defmode(char *fname) +{ + int ret; -/** - 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 - on the umask -**/ -int create_directory_path(char *fname, int base_umask) + umask(orig_umask); + ret = do_mkdir(fname, ACCESSPERMS); + umask(0); + + return ret; +} + +/* Create any necessary directories in fname. Any missing directories are + * created with default permissions. */ +int create_directory_path(char *fname) { char *p; + int ret = 0; while (*fname == '/') fname++; while (strncmp(fname, "./", 2) == 0) fname += 2; + umask(orig_umask); p = fname; while ((p = strchr(p,'/')) != NULL) { - *p = 0; - do_mkdir(fname, 0777 & ~base_umask); - *p = '/'; - p++; + *p = '\0'; + if (do_mkdir(fname, ACCESSPERMS) < 0 && errno != EEXIST) + ret = -1; + *p++ = '/'; } - return 0; -} + umask(0); + return ret; +} /** * Write @p len bytes at @p ptr to descriptor @p desc, retrying if @@ -229,7 +228,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,7 +253,6 @@ 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 @@ -377,8 +374,11 @@ int robust_unlink(const 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(const char *from, const 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 +394,11 @@ int robust_rename(const char *from, const 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 +410,6 @@ int robust_rename(const char *from, const char *to, int mode) return -1; } - static pid_t all_pids[10]; static int num_pids; @@ -449,7 +453,6 @@ void kill_all(int sig) } } - /** Turn a user name into a uid */ int name_to_uid(char *name, uid_t *uid) { @@ -478,7 +481,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) { @@ -747,7 +749,7 @@ unsigned int clean_fname(char *name, BOOL collapse_dot_dot) * of the path. Use -1 to allow unlimited depth. * * We also clean the path in a manner similar to clean_fname() but with a - * few differences: + * few differences: * * Turns multiple adjacent slashes into a single slash, gets rid of "." dir * elements (INCLUDING a trailing dot dir), PRESERVES a trailing slash, and @@ -1078,7 +1080,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); @@ -1130,6 +1132,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); @@ -1137,14 +1140,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. * @@ -1173,11 +1174,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 * @@ -1185,7 +1183,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) @@ -1231,7 +1229,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) @@ -1357,3 +1354,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; +}