version 1.1.1.1.2.1, 2013/07/22 00:20:21
|
version 1.1.1.3, 2016/11/01 09:54:32
|
Line 4
|
Line 4
|
* Copyright (C) 1996-2000 Andrew Tridgell |
* Copyright (C) 1996-2000 Andrew Tridgell |
* Copyright (C) 1996 Paul Mackerras |
* Copyright (C) 1996 Paul Mackerras |
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org> |
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org> |
* Copyright (C) 2003-2009 Wayne Davison | * Copyright (C) 2003-2015 Wayne Davison |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* 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 |
* it under the terms of the GNU General Public License as published by |
Line 22
|
Line 22
|
|
|
#include "rsync.h" |
#include "rsync.h" |
#include "ifuncs.h" |
#include "ifuncs.h" |
|
#include "itypes.h" |
|
#include "inums.h" |
|
|
extern int verbose; | extern int dry_run; |
extern int module_id; |
extern int module_id; |
|
extern int protect_args; |
extern int modify_window; |
extern int modify_window; |
extern int relative_paths; |
extern int relative_paths; |
extern int preserve_times; |
extern int preserve_times; |
extern int human_readable; |
|
extern int preserve_xattrs; |
extern int preserve_xattrs; |
|
extern int preallocate_files; |
extern char *module_dir; |
extern char *module_dir; |
extern unsigned int module_dirlen; |
extern unsigned int module_dirlen; |
extern mode_t orig_umask; |
|
extern char *partial_dir; |
extern char *partial_dir; |
extern struct filter_list_struct daemon_filter_list; | extern filter_rule_list daemon_filter_list; |
|
|
int sanitize_paths = 0; |
int sanitize_paths = 0; |
|
|
Line 94 int fd_pair(int fd[2])
|
Line 96 int fd_pair(int fd[2])
|
|
|
void print_child_argv(const char *prefix, char **cmd) |
void print_child_argv(const char *prefix, char **cmd) |
{ |
{ |
|
int cnt = 0; |
rprintf(FCLIENT, "%s ", prefix); |
rprintf(FCLIENT, "%s ", prefix); |
for (; *cmd; cmd++) { |
for (; *cmd; cmd++) { |
/* Look for characters that ought to be quoted. This |
/* Look for characters that ought to be quoted. This |
Line 107 void print_child_argv(const char *prefix, char **cmd)
|
Line 110 void print_child_argv(const char *prefix, char **cmd)
|
} else { |
} else { |
rprintf(FCLIENT, "%s ", *cmd); |
rprintf(FCLIENT, "%s ", *cmd); |
} |
} |
|
cnt++; |
} |
} |
rprintf(FCLIENT, "\n"); | rprintf(FCLIENT, " (%d args)\n", cnt); |
} |
} |
|
|
NORETURN void out_of_memory(const char *str) |
|
{ |
|
rprintf(FERROR, "ERROR: out of memory in %s [%s]\n", str, who_am_i()); |
|
exit_cleanup(RERR_MALLOC); |
|
} |
|
|
|
NORETURN void overflow_exit(const char *str) |
|
{ |
|
rprintf(FERROR, "ERROR: buffer overflow in %s [%s]\n", str, who_am_i()); |
|
exit_cleanup(RERR_MALLOC); |
|
} |
|
|
|
/* This returns 0 for success, 1 for a symlink if symlink time-setting |
/* This returns 0 for success, 1 for a symlink if symlink time-setting |
* is not possible, or -1 for any other error. */ |
* is not possible, or -1 for any other error. */ |
int set_modtime(const char *fname, time_t modtime, mode_t mode) | int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) |
{ |
{ |
static int switch_step = 0; |
static int switch_step = 0; |
|
|
if (verbose > 2) { | if (DEBUG_GTE(TIME, 1)) { |
rprintf(FINFO, "set modtime of %s to (%ld) %s", |
rprintf(FINFO, "set modtime of %s to (%ld) %s", |
fname, (long)modtime, |
fname, (long)modtime, |
asctime(localtime(&modtime))); |
asctime(localtime(&modtime))); |
Line 138 int set_modtime(const char *fname, time_t modtime, mod
|
Line 130 int set_modtime(const char *fname, time_t modtime, mod
|
switch (switch_step) { |
switch (switch_step) { |
#ifdef HAVE_UTIMENSAT |
#ifdef HAVE_UTIMENSAT |
#include "case_N.h" |
#include "case_N.h" |
if (do_utimensat(fname, modtime, 0) == 0) | if (do_utimensat(fname, modtime, mod_nsec) == 0) |
break; |
break; |
if (errno != ENOSYS) |
if (errno != ENOSYS) |
return -1; |
return -1; |
Line 148 int set_modtime(const char *fname, time_t modtime, mod
|
Line 140 int set_modtime(const char *fname, time_t modtime, mod
|
|
|
#ifdef HAVE_LUTIMES |
#ifdef HAVE_LUTIMES |
#include "case_N.h" |
#include "case_N.h" |
if (do_lutimes(fname, modtime, 0) == 0) | if (do_lutimes(fname, modtime, mod_nsec) == 0) |
break; |
break; |
if (errno != ENOSYS) |
if (errno != ENOSYS) |
return -1; |
return -1; |
Line 167 int set_modtime(const char *fname, time_t modtime, mod
|
Line 159 int set_modtime(const char *fname, time_t modtime, mod
|
|
|
#include "case_N.h" |
#include "case_N.h" |
#ifdef HAVE_UTIMES |
#ifdef HAVE_UTIMES |
if (do_utimes(fname, modtime, 0) == 0) | if (do_utimes(fname, modtime, mod_nsec) == 0) |
break; |
break; |
#else |
#else |
if (do_utime(fname, modtime, 0) == 0) | if (do_utime(fname, modtime, mod_nsec) == 0) |
break; |
break; |
#endif |
#endif |
|
|
Line 180 int set_modtime(const char *fname, time_t modtime, mod
|
Line 172 int set_modtime(const char *fname, time_t modtime, mod
|
return 0; |
return 0; |
} |
} |
|
|
/* 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; |
|
|
|
umask(orig_umask); |
|
ret = do_mkdir(fname, ACCESSPERMS); |
|
umask(0); |
|
|
|
return ret; |
|
} |
|
|
|
/* Create any necessary directories in fname. Any missing directories are |
/* Create any necessary directories in fname. Any missing directories are |
* created with default permissions. */ | * created with default permissions. Returns < 0 on error, or the number |
int create_directory_path(char *fname) | * of directories created. */ |
| int make_path(char *fname, int flags) |
{ |
{ |
char *p; | char *end, *p; |
int ret = 0; |
int ret = 0; |
|
|
while (*fname == '/') | if (flags & MKP_SKIP_SLASH) { |
fname++; | while (*fname == '/') |
while (strncmp(fname, "./", 2) == 0) | fname++; |
| } |
| |
| while (*fname == '.' && fname[1] == '/') |
fname += 2; |
fname += 2; |
|
|
umask(orig_umask); | if (flags & MKP_DROP_NAME) { |
p = fname; | end = strrchr(fname, '/'); |
while ((p = strchr(p,'/')) != NULL) { | if (!end || end == fname) |
*p = '\0'; | return 0; |
if (do_mkdir(fname, ACCESSPERMS) < 0 && errno != EEXIST) | *end = '\0'; |
ret = -1; | } else |
*p++ = '/'; | end = fname + strlen(fname); |
| |
| /* Try to find an existing dir, starting from the deepest dir. */ |
| for (p = end; ; ) { |
| if (dry_run) { |
| STRUCT_STAT st; |
| if (do_stat(fname, &st) == 0) { |
| if (S_ISDIR(st.st_mode)) |
| errno = EEXIST; |
| else |
| errno = ENOTDIR; |
| } |
| } else if (do_mkdir(fname, ACCESSPERMS) == 0) { |
| ret++; |
| break; |
| } |
| |
| if (errno != ENOENT) { |
| STRUCT_STAT st; |
| if (errno != EEXIST || (do_stat(fname, &st) == 0 && !S_ISDIR(st.st_mode))) |
| ret = -ret - 1; |
| break; |
| } |
| while (1) { |
| if (p == fname) { |
| /* We got a relative path that doesn't exist, so assume that '.' |
| * is there and just break out and create the whole thing. */ |
| p = NULL; |
| goto double_break; |
| } |
| if (*--p == '/') { |
| if (p == fname) { |
| /* We reached the "/" dir, which we assume is there. */ |
| goto double_break; |
| } |
| *p = '\0'; |
| break; |
| } |
| } |
} |
} |
umask(0); | double_break: |
|
|
|
/* Make all the dirs that we didn't find on the way here. */ |
|
while (p != end) { |
|
if (p) |
|
*p = '/'; |
|
else |
|
p = fname; |
|
p += strlen(p); |
|
if (ret < 0) /* Skip mkdir on error, but keep restoring the path. */ |
|
continue; |
|
if (do_mkdir(fname, ACCESSPERMS) < 0) |
|
ret = -ret - 1; |
|
else |
|
ret++; |
|
} |
|
|
|
if (flags & MKP_DROP_NAME) |
|
*end = '/'; |
|
|
return ret; |
return ret; |
} |
} |
|
|
Line 280 static int safe_read(int desc, char *ptr, size_t len)
|
Line 318 static int safe_read(int desc, char *ptr, size_t len)
|
* |
* |
* This is used in conjunction with the --temp-dir, --backup, and |
* This is used in conjunction with the --temp-dir, --backup, and |
* --copy-dest options. */ |
* --copy-dest options. */ |
int copy_file(const char *source, const char *dest, int ofd, | int copy_file(const char *source, const char *dest, int ofd, mode_t mode) |
mode_t mode, int create_bak_dir) | |
{ |
{ |
int ifd; |
int ifd; |
char buf[1024 * 8]; |
char buf[1024 * 8]; |
int len; /* Number of bytes read into `buf'. */ |
int len; /* Number of bytes read into `buf'. */ |
|
#ifdef PREALLOCATE_NEEDS_TRUNCATE |
|
OFF_T preallocated_len = 0, offset = 0; |
|
#endif |
|
|
if ((ifd = do_open(source, O_RDONLY, 0)) < 0) { |
if ((ifd = do_open(source, O_RDONLY, 0)) < 0) { |
int save_errno = errno; |
int save_errno = errno; |
Line 302 int copy_file(const char *source, const char *dest, in
|
Line 342 int copy_file(const char *source, const char *dest, in
|
return -1; |
return -1; |
} |
} |
|
|
|
#ifdef SUPPORT_XATTRS |
|
if (preserve_xattrs) |
|
mode |= S_IWUSR; |
|
#endif |
|
mode &= INITACCESSPERMS; |
if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) { |
if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) { |
int save_errno = errno ? errno : EINVAL; /* 0 paranoia */ | int save_errno = errno; |
if (create_bak_dir && errno == ENOENT && make_bak_dir(dest) == 0) { | rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest)); |
if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) | close(ifd); |
save_errno = errno ? errno : save_errno; | errno = save_errno; |
else | return -1; |
save_errno = 0; | |
} | |
if (save_errno) { | |
rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest)); | |
close(ifd); | |
errno = save_errno; | |
return -1; | |
} | |
} |
} |
} |
} |
|
|
|
#ifdef SUPPORT_PREALLOCATION |
|
if (preallocate_files) { |
|
STRUCT_STAT srcst; |
|
|
|
/* Try to preallocate enough space for file's eventual length. Can |
|
* reduce fragmentation on filesystems like ext4, xfs, and NTFS. */ |
|
if (do_fstat(ifd, &srcst) < 0) |
|
rsyserr(FWARNING, errno, "fstat %s", full_fname(source)); |
|
else if (srcst.st_size > 0) { |
|
if (do_fallocate(ofd, 0, srcst.st_size) == 0) { |
|
#ifdef PREALLOCATE_NEEDS_TRUNCATE |
|
preallocated_len = srcst.st_size; |
|
#endif |
|
} else |
|
rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest)); |
|
} |
|
} |
|
#endif |
|
|
while ((len = safe_read(ifd, buf, sizeof buf)) > 0) { |
while ((len = safe_read(ifd, buf, sizeof buf)) > 0) { |
if (full_write(ofd, buf, len) < 0) { |
if (full_write(ofd, buf, len) < 0) { |
int save_errno = errno; |
int save_errno = errno; |
Line 328 int copy_file(const char *source, const char *dest, in
|
Line 384 int copy_file(const char *source, const char *dest, in
|
errno = save_errno; |
errno = save_errno; |
return -1; |
return -1; |
} |
} |
|
#ifdef PREALLOCATE_NEEDS_TRUNCATE |
|
offset += len; |
|
#endif |
} |
} |
|
|
if (len < 0) { |
if (len < 0) { |
Line 344 int copy_file(const char *source, const char *dest, in
|
Line 403 int copy_file(const char *source, const char *dest, in
|
full_fname(source)); |
full_fname(source)); |
} |
} |
|
|
|
#ifdef PREALLOCATE_NEEDS_TRUNCATE |
|
/* Source file might have shrunk since we fstatted it. |
|
* Cut off any extra preallocated zeros from dest file. */ |
|
if (offset < preallocated_len && do_ftruncate(ofd, offset) < 0) { |
|
/* If we fail to truncate, the dest file may be wrong, so we |
|
* must trigger the "partial transfer" error. */ |
|
rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest)); |
|
} |
|
#endif |
|
|
if (close(ofd) < 0) { |
if (close(ofd) < 0) { |
int save_errno = errno; |
int save_errno = errno; |
rsyserr(FERROR_XFER, errno, "close failed on %s", |
rsyserr(FERROR_XFER, errno, "close failed on %s", |
Line 407 int robust_unlink(const char *fname)
|
Line 476 int robust_unlink(const char *fname)
|
counter = 1; |
counter = 1; |
} while ((rc = access(path, 0)) == 0 && counter != start); |
} while ((rc = access(path, 0)) == 0 && counter != start); |
|
|
if (verbose > 0) { | if (INFO_GTE(MISC, 1)) { |
rprintf(FWARNING, "renaming %s to %s because of text busy\n", |
rprintf(FWARNING, "renaming %s to %s because of text busy\n", |
fname, path); |
fname, path); |
} |
} |
Line 450 int robust_rename(const char *from, const char *to, co
|
Line 519 int robust_rename(const char *from, const char *to, co
|
return -2; |
return -2; |
to = partialptr; |
to = partialptr; |
} |
} |
if (copy_file(from, to, -1, mode, 0) != 0) | if (copy_file(from, to, -1, mode) != 0) |
return -2; |
return -2; |
do_unlink(from); |
do_unlink(from); |
return 1; |
return 1; |
Line 504 void kill_all(int sig)
|
Line 573 void kill_all(int sig)
|
} |
} |
} |
} |
|
|
/** Turn a user name into a uid */ |
|
int name_to_uid(const char *name, uid_t *uid_p) |
|
{ |
|
struct passwd *pass; |
|
if (!name || !*name) |
|
return 0; |
|
if (!(pass = getpwnam(name))) |
|
return 0; |
|
*uid_p = pass->pw_uid; |
|
return 1; |
|
} |
|
|
|
/** Turn a group name into a gid */ |
|
int name_to_gid(const char *name, gid_t *gid_p) |
|
{ |
|
struct group *grp; |
|
if (!name || !*name) |
|
return 0; |
|
if (!(grp = getgrnam(name))) |
|
return 0; |
|
*gid_p = grp->gr_gid; |
|
return 1; |
|
} |
|
|
|
/** Lock a byte range in a open file */ |
/** Lock a byte range in a open file */ |
int lock_range(int fd, int offset, int len) |
int lock_range(int fd, int offset, int len) |
{ |
{ |
Line 719 void glob_expand_module(char *base1, char *arg, char *
|
Line 764 void glob_expand_module(char *base1, char *arg, char *
|
if (strncmp(arg, base, base_len) == 0) |
if (strncmp(arg, base, base_len) == 0) |
arg += base_len; |
arg += base_len; |
|
|
|
if (protect_args) { |
|
glob_expand(arg, argv_p, argc_p, maxargs_p); |
|
return; |
|
} |
|
|
if (!(arg = strdup(arg))) |
if (!(arg = strdup(arg))) |
out_of_memory("glob_expand_module"); |
out_of_memory("glob_expand_module"); |
|
|
if (asprintf(&base," %s/", base1) <= 0) | if (asprintf(&base," %s/", base1) < 0) |
out_of_memory("glob_expand_module"); |
out_of_memory("glob_expand_module"); |
base_len++; |
base_len++; |
|
|
Line 824 int count_dir_elements(const char *p)
|
Line 874 int count_dir_elements(const char *p)
|
* CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements |
* CFN_KEEP_TRAILING_SLASH is flagged, and will also collapse ".." elements |
* (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged. If the |
* (except at the start) if CFN_COLLAPSE_DOT_DOT_DIRS is flagged. If the |
* resulting name would be empty, returns ".". */ |
* resulting name would be empty, returns ".". */ |
unsigned int clean_fname(char *name, int flags) | int clean_fname(char *name, int flags) |
{ |
{ |
char *limit = name - 1, *t = name, *f = name; |
char *limit = name - 1, *t = name, *f = name; |
int anchored; |
int anchored; |
Line 832 unsigned int clean_fname(char *name, int flags)
|
Line 882 unsigned int clean_fname(char *name, int flags)
|
if (!name) |
if (!name) |
return 0; |
return 0; |
|
|
|
#define DOT_IS_DOT_DOT_DIR(bp) (bp[1] == '.' && (bp[2] == '/' || !bp[2])) |
|
|
if ((anchored = *f == '/') != 0) { |
if ((anchored = *f == '/') != 0) { |
*t++ = *f++; |
*t++ = *f++; |
#ifdef __CYGWIN__ |
#ifdef __CYGWIN__ |
Line 844 unsigned int clean_fname(char *name, int flags)
|
Line 896 unsigned int clean_fname(char *name, int flags)
|
} else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') { |
} else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' && f[1] == '/') { |
*t++ = *f++; |
*t++ = *f++; |
*t++ = *f++; |
*t++ = *f++; |
} | } else if (flags & CFN_REFUSE_DOT_DOT_DIRS && *f == '.' && DOT_IS_DOT_DOT_DIR(f)) |
| return -1; |
while (*f) { |
while (*f) { |
/* discard extra slashes */ |
/* discard extra slashes */ |
if (*f == '/') { |
if (*f == '/') { |
Line 860 unsigned int clean_fname(char *name, int flags)
|
Line 913 unsigned int clean_fname(char *name, int flags)
|
if (f[1] == '\0' && flags & CFN_DROP_TRAILING_DOT_DIR) |
if (f[1] == '\0' && flags & CFN_DROP_TRAILING_DOT_DIR) |
break; |
break; |
/* collapse ".." dirs */ |
/* collapse ".." dirs */ |
if (flags & CFN_COLLAPSE_DOT_DOT_DIRS | if (flags & (CFN_COLLAPSE_DOT_DOT_DIRS|CFN_REFUSE_DOT_DOT_DIRS) && DOT_IS_DOT_DOT_DIR(f)) { |
&& f[1] == '.' && (f[2] == '/' || !f[2])) { | |
char *s = t - 1; |
char *s = t - 1; |
|
if (flags & CFN_REFUSE_DOT_DOT_DIRS) |
|
return -1; |
if (s == name && anchored) { |
if (s == name && anchored) { |
f += 2; |
f += 2; |
continue; |
continue; |
Line 885 unsigned int clean_fname(char *name, int flags)
|
Line 939 unsigned int clean_fname(char *name, int flags)
|
*t++ = '.'; |
*t++ = '.'; |
*t = '\0'; |
*t = '\0'; |
|
|
|
#undef DOT_IS_DOT_DOT_DIR |
|
|
return t - name; |
return t - name; |
} |
} |
|
|
Line 992 char *sanitize_path(char *dest, const char *p, const c
|
Line 1048 char *sanitize_path(char *dest, const char *p, const c
|
* Also cleans the path using the clean_fname() function. */ |
* Also cleans the path using the clean_fname() function. */ |
int change_dir(const char *dir, int set_path_only) |
int change_dir(const char *dir, int set_path_only) |
{ |
{ |
static int initialised; | static int initialised, skipped_chdir; |
unsigned int len; |
unsigned int len; |
|
|
if (!initialised) { |
if (!initialised) { |
Line 1008 int change_dir(const char *dir, int set_path_only)
|
Line 1064 int change_dir(const char *dir, int set_path_only)
|
return 0; |
return 0; |
|
|
len = strlen(dir); |
len = strlen(dir); |
if (len == 1 && *dir == '.') | if (len == 1 && *dir == '.' && (!skipped_chdir || set_path_only)) |
return 1; |
return 1; |
|
|
if (*dir == '/') { |
if (*dir == '/') { |
Line 1018 int change_dir(const char *dir, int set_path_only)
|
Line 1074 int change_dir(const char *dir, int set_path_only)
|
} |
} |
if (!set_path_only && chdir(dir)) |
if (!set_path_only && chdir(dir)) |
return 0; |
return 0; |
|
skipped_chdir = set_path_only; |
memcpy(curr_dir, dir, len + 1); |
memcpy(curr_dir, dir, len + 1); |
} else { |
} else { |
if (curr_dir_len + 1 + len >= sizeof curr_dir) { |
if (curr_dir_len + 1 + len >= sizeof curr_dir) { |
Line 1032 int change_dir(const char *dir, int set_path_only)
|
Line 1089 int change_dir(const char *dir, int set_path_only)
|
curr_dir[curr_dir_len] = '\0'; |
curr_dir[curr_dir_len] = '\0'; |
return 0; |
return 0; |
} |
} |
|
skipped_chdir = set_path_only; |
} |
} |
|
|
curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS); | curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR); |
if (sanitize_paths) { |
if (sanitize_paths) { |
if (module_dirlen > curr_dir_len) |
if (module_dirlen > curr_dir_len) |
module_dirlen = curr_dir_len; |
module_dirlen = curr_dir_len; |
curr_dir_depth = count_dir_elements(curr_dir + module_dirlen); |
curr_dir_depth = count_dir_elements(curr_dir + module_dirlen); |
} |
} |
|
|
if (verbose >= 5 && !set_path_only) | if (DEBUG_GTE(CHDIR, 1) && !set_path_only) |
rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir); |
rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir); |
|
|
return 1; |
return 1; |
Line 1104 char *full_fname(const char *fn)
|
Line 1162 char *full_fname(const char *fn)
|
} else |
} else |
m1 = m2 = m3 = ""; |
m1 = m2 = m3 = ""; |
|
|
if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) <= 0) | if (asprintf(&result, "\"%s%s%s\"%s%s%s", p1, p2, fn, m1, m2, m3) < 0) |
out_of_memory("full_fname"); |
out_of_memory("full_fname"); |
|
|
return result; |
return result; |
Line 1168 int handle_partial_dir(const char *fname, int create)
|
Line 1226 int handle_partial_dir(const char *fname, int create)
|
} |
} |
statret = -1; |
statret = -1; |
} |
} |
if (statret < 0 && do_mkdir_path(dir, 0700) < 0) { | if (statret < 0 && do_mkdir(dir, 0700) < 0) { |
*fn = '/'; |
*fn = '/'; |
return 0; |
return 0; |
} |
} |
Line 1179 int handle_partial_dir(const char *fname, int create)
|
Line 1237 int handle_partial_dir(const char *fname, int create)
|
return 1; |
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 *p1, const char *p2) |
|
{ |
|
for ( ; *p1; p1++, p2++) { |
|
if (*p1 != *p2) |
|
break; |
|
} |
|
|
|
return (int)*(uchar*)p1 - (int)*(uchar*)p2; |
|
} |
|
|
|
/* We need a memcmp function compares unsigned-byte values. */ |
|
int u_memcmp(const void *p1, const void *p2, size_t len) |
|
{ |
|
const uchar *u1 = p1; |
|
const uchar *u2 = p2; |
|
|
|
while (len--) { |
|
if (*u1 != *u2) |
|
return (int)*u1 - (int)*u2; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
/* Determine if a symlink points outside the current directory tree. |
/* Determine if a symlink points outside the current directory tree. |
* This is considered "unsafe" because e.g. when mirroring somebody |
* This is considered "unsafe" because e.g. when mirroring somebody |
* else's machine it might allow them to establish a symlink to |
* else's machine it might allow them to establish a symlink to |
Line 1264 int unsafe_symlink(const char *dest, const char *src)
|
Line 1296 int unsafe_symlink(const char *dest, const char *src)
|
return depth < 0; |
return depth < 0; |
} |
} |
|
|
#define HUMANIFY(mult) \ |
|
do { \ |
|
if (num >= mult || num <= -mult) { \ |
|
double dnum = (double)num / mult; \ |
|
char units; \ |
|
if (num < 0) \ |
|
dnum = -dnum; \ |
|
if (dnum < mult) \ |
|
units = 'K'; \ |
|
else if ((dnum /= mult) < mult) \ |
|
units = 'M'; \ |
|
else { \ |
|
dnum /= mult; \ |
|
units = 'G'; \ |
|
} \ |
|
if (num < 0) \ |
|
dnum = -dnum; \ |
|
snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units); \ |
|
return bufs[n]; \ |
|
} \ |
|
} while (0) |
|
|
|
/* Return the int64 number as a string. If the --human-readable option was |
|
* specified, we may output the number in K, M, or G units. We can return |
|
* up to 4 buffers at a time. */ |
|
char *human_num(int64 num) |
|
{ |
|
static char bufs[4][128]; /* more than enough room */ |
|
static unsigned int n; |
|
char *s; |
|
int negated; |
|
|
|
n = (n + 1) % (sizeof bufs / sizeof bufs[0]); |
|
|
|
if (human_readable) { |
|
if (human_readable == 1) |
|
HUMANIFY(1000); |
|
else |
|
HUMANIFY(1024); |
|
} |
|
|
|
s = bufs[n] + sizeof bufs[0] - 1; |
|
*s = '\0'; |
|
|
|
if (!num) |
|
*--s = '0'; |
|
if (num < 0) { |
|
/* A maximum-size negated number can't fit as a positive, |
|
* so do one digit in negated form to start us off. */ |
|
*--s = (char)(-(num % 10)) + '0'; |
|
num = -(num / 10); |
|
negated = 1; |
|
} else |
|
negated = 0; |
|
|
|
while (num) { |
|
*--s = (char)(num % 10) + '0'; |
|
num /= 10; |
|
} |
|
|
|
if (negated) |
|
*--s = '-'; |
|
|
|
return s; |
|
} |
|
|
|
/* Return the double number as a string. If the --human-readable option was |
|
* specified, we may output the number in K, M, or G units. We use a buffer |
|
* from human_num() to return our result. */ |
|
char *human_dnum(double dnum, int decimal_digits) |
|
{ |
|
char *buf = human_num(dnum); |
|
int len = strlen(buf); |
|
if (isDigit(buf + len - 1)) { |
|
/* There's extra room in buf prior to the start of the num. */ |
|
buf -= decimal_digits + 2; |
|
snprintf(buf, len + decimal_digits + 3, "%.*f", decimal_digits, dnum); |
|
} |
|
return buf; |
|
} |
|
|
|
/* Return the date and time as a string. Some callers tweak returned buf. */ |
/* Return the date and time as a string. Some callers tweak returned buf. */ |
char *timestring(time_t t) |
char *timestring(time_t t) |
{ |
{ |
Line 1364 char *timestring(time_t t)
|
Line 1315 char *timestring(time_t t)
|
return TimeBuf; |
return TimeBuf; |
} |
} |
|
|
/** |
|
* Sleep for a specified number of milliseconds. |
|
* |
|
* Always returns TRUE. (In the future it might return FALSE if |
|
* interrupted.) |
|
**/ |
|
int msleep(int t) |
|
{ |
|
int tdiff = 0; |
|
struct timeval tval, t1, t2; |
|
|
|
gettimeofday(&t1, NULL); |
|
|
|
while (tdiff < t) { |
|
tval.tv_sec = (t-tdiff)/1000; |
|
tval.tv_usec = 1000*((t-tdiff)%1000); |
|
|
|
errno = 0; |
|
select(0,NULL,NULL, NULL, &tval); |
|
|
|
gettimeofday(&t2, NULL); |
|
tdiff = (t2.tv_sec - t1.tv_sec)*1000 + |
|
(t2.tv_usec - t1.tv_usec)/1000; |
|
} |
|
|
|
return True; |
|
} |
|
|
|
/* Determine if two time_t values are equivalent (either exact, or in |
/* Determine if two time_t values are equivalent (either exact, or in |
* the modification timestamp window established by --modify-window). |
* the modification timestamp window established by --modify-window). |
* |
* |
Line 1404 int msleep(int t)
|
Line 1327 int msleep(int t)
|
int cmp_time(time_t file1, time_t file2) |
int cmp_time(time_t file1, time_t file2) |
{ |
{ |
if (file2 > file1) { |
if (file2 > file1) { |
if (file2 - file1 <= modify_window) | /* The final comparison makes sure that modify_window doesn't overflow a |
return 0; | * time_t, which would mean that file2 must be in the equality window. */ |
return -1; | if (!modify_window || (file2 > file1 + modify_window && file1 + modify_window > file1)) |
| return -1; |
| } else if (file1 > file2) { |
| if (!modify_window || (file1 > file2 + modify_window && file2 + modify_window > file2)) |
| return 1; |
} |
} |
if (file1 - file2 <= modify_window) | return 0; |
return 0; | |
return 1; | |
} |
} |
|
|
|
|
#ifdef __INSURE__XX |
#ifdef __INSURE__XX |
#include <dlfcn.h> |
#include <dlfcn.h> |
|
|
Line 1425 int cmp_time(time_t file1, time_t file2)
|
Line 1349 int cmp_time(time_t file1, time_t file2)
|
int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6) |
int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6) |
{ |
{ |
static int (*fn)(); |
static int (*fn)(); |
int ret; | int ret, pid_int = getpid(); |
char *cmd; |
char *cmd; |
|
|
asprintf(&cmd, "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; gdb /proc/%d/exe %d'", | if (asprintf(&cmd, |
getpid(), getpid(), getpid()); | "/usr/X11R6/bin/xterm -display :0 -T Panic -n Panic -e /bin/sh -c 'cat /tmp/ierrs.*.%d ; " |
| "gdb /proc/%d/exe %d'", pid_int, pid_int, pid_int) < 0) |
| return -1; |
|
|
if (!fn) { |
if (!fn) { |
static void *h; |
static void *h; |
Line 1447 int _Insure_trap_error(int a1, int a2, int a3, int a4,
|
Line 1373 int _Insure_trap_error(int a1, int a2, int a3, int a4,
|
} |
} |
#endif |
#endif |
|
|
#define MALLOC_MAX 0x40000000 |
|
|
|
void *_new_array(unsigned long num, unsigned int size, int use_calloc) |
|
{ |
|
if (num >= MALLOC_MAX/size) |
|
return NULL; |
|
return use_calloc ? calloc(num, size) : malloc(num * size); |
|
} |
|
|
|
void *_realloc_array(void *ptr, unsigned int size, size_t num) |
|
{ |
|
if (num >= MALLOC_MAX/size) |
|
return NULL; |
|
if (!ptr) |
|
return malloc(size * num); |
|
return realloc(ptr, size * num); |
|
} |
|
|
|
/* Take a filename and filename length and return the most significant |
/* Take a filename and filename length and return the most significant |
* filename suffix we can find. This ignores suffixes such as "~", |
* filename suffix we can find. This ignores suffixes such as "~", |
* ".bak", ".orig", ".~1~", etc. */ |
* ".bak", ".orig", ".~1~", etc. */ |
Line 1529 const char *find_filename_suffix(const char *fn, int f
|
Line 1437 const char *find_filename_suffix(const char *fn, int f
|
|
|
#define UNIT (1 << 16) |
#define UNIT (1 << 16) |
|
|
uint32 fuzzy_distance(const char *s1, int len1, const char *s2, int len2) | uint32 fuzzy_distance(const char *s1, unsigned len1, const char *s2, unsigned len2) |
{ |
{ |
uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc; |
uint32 a[MAXPATHLEN], diag, above, left, diag_inc, above_inc, left_inc; |
int32 cost; |
int32 cost; |
int i1, i2; | unsigned i1, i2; |
|
|
if (!len1 || !len2) { |
if (!len1 || !len2) { |
if (!len1) { |
if (!len1) { |
Line 1697 int flist_ndx_pop(flist_ndx_list *lp)
|
Line 1605 int flist_ndx_pop(flist_ndx_list *lp)
|
return ndx; |
return ndx; |
} |
} |
|
|
|
/* Make sure there is room for one more item in the item list. If there |
|
* is not, expand the list as indicated by the value of "incr": |
|
* - if incr < 0 then increase the malloced size by -1 * incr |
|
* - if incr >= 0 then either make the malloced size equal to "incr" |
|
* or (if that's not large enough) double the malloced size |
|
* After the size check, the list's count is incremented by 1 and a pointer |
|
* to the "new" list item is returned. |
|
*/ |
void *expand_item_list(item_list *lp, size_t item_size, |
void *expand_item_list(item_list *lp, size_t item_size, |
const char *desc, int incr) |
const char *desc, int incr) |
{ |
{ |
Line 1707 void *expand_item_list(item_list *lp, size_t item_size
|
Line 1623 void *expand_item_list(item_list *lp, size_t item_size
|
if (incr < 0) |
if (incr < 0) |
new_size += -incr; /* increase slowly */ |
new_size += -incr; /* increase slowly */ |
else if (new_size < (size_t)incr) |
else if (new_size < (size_t)incr) |
new_size += incr; | new_size = incr; |
else | else if (new_size) |
new_size *= 2; |
new_size *= 2; |
if (new_size < lp->malloced) | else |
| new_size = 1; |
| if (new_size <= lp->malloced) |
overflow_exit("expand_item_list"); |
overflow_exit("expand_item_list"); |
/* Using _realloc_array() lets us pass the size, not a type. */ |
/* Using _realloc_array() lets us pass the size, not a type. */ |
new_ptr = _realloc_array(lp->items, item_size, new_size); |
new_ptr = _realloc_array(lp->items, item_size, new_size); |
if (verbose >= 4) { | if (DEBUG_GTE(FLIST, 3)) { |
rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n", | rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n", |
who_am_i(), desc, (double)new_size * item_size, | who_am_i(), desc, big_num(new_size * item_size), |
new_ptr == lp->items ? " not" : ""); |
new_ptr == lp->items ? " not" : ""); |
} |
} |
if (!new_ptr) |
if (!new_ptr) |