|
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) |