version 1.1.1.3, 2016/11/01 09:54:32
|
version 1.1.1.4, 2021/03/17 00:32:36
|
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-2015 Wayne Davison | * Copyright (C) 2003-2020 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 27
|
Line 27
|
|
|
extern int dry_run; |
extern int dry_run; |
extern int module_id; |
extern int module_id; |
|
extern int do_fsync; |
extern int protect_args; |
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 preserve_xattrs; |
extern int preserve_xattrs; |
extern int preallocate_files; |
extern int preallocate_files; |
|
extern int force_change; |
extern char *module_dir; |
extern char *module_dir; |
extern unsigned int module_dirlen; |
extern unsigned int module_dirlen; |
extern char *partial_dir; |
extern char *partial_dir; |
Line 115 void print_child_argv(const char *prefix, char **cmd)
|
Line 117 void print_child_argv(const char *prefix, char **cmd)
|
rprintf(FCLIENT, " (%d args)\n", cnt); |
rprintf(FCLIENT, " (%d args)\n", cnt); |
} |
} |
|
|
|
#ifdef SUPPORT_FORCE_CHANGE |
|
static int try_a_force_change(const char *fname, STRUCT_STAT *stp) |
|
{ |
|
uint32 fileflags = ST_FLAGS(*stp); |
|
if (fileflags == NO_FFLAGS) { |
|
STRUCT_STAT st; |
|
if (x_lstat(fname, &st, NULL) == 0) |
|
fileflags = st.st_flags; |
|
} |
|
if (fileflags != NO_FFLAGS && make_mutable(fname, stp->st_mode, fileflags, force_change) > 0) { |
|
int ret, save_force_change = force_change; |
|
|
|
force_change = 0; /* Make certain we can't come back here. */ |
|
ret = set_times(fname, stp); |
|
force_change = save_force_change; |
|
|
|
undo_make_mutable(fname, fileflags); |
|
|
|
return ret; |
|
} |
|
|
|
errno = EPERM; |
|
|
|
return -1; |
|
} |
|
#endif |
|
|
/* 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, uint32 mod_nsec, mode_t mode) | int set_times(const char *fname, STRUCT_STAT *stp) |
{ |
{ |
static int switch_step = 0; |
static int switch_step = 0; |
|
|
if (DEBUG_GTE(TIME, 1)) { |
if (DEBUG_GTE(TIME, 1)) { |
rprintf(FINFO, "set modtime of %s to (%ld) %s", | rprintf(FINFO, |
fname, (long)modtime, | "set modtime, atime of %s to (%ld) %s, (%ld) %s\n", |
asctime(localtime(&modtime))); | fname, (long)stp->st_mtime, |
| timestring(stp->st_mtime), (long)stp->st_atime, timestring(stp->st_atime)); |
} |
} |
|
|
switch (switch_step) { |
switch (switch_step) { |
|
#ifdef HAVE_SETATTRLIST |
|
#include "case_N.h" |
|
if (do_setattrlist_times(fname, stp) == 0) |
|
break; |
|
if (errno != ENOSYS) |
|
return -1; |
|
switch_step++; |
|
#endif |
|
|
#ifdef HAVE_UTIMENSAT |
#ifdef HAVE_UTIMENSAT |
#include "case_N.h" |
#include "case_N.h" |
if (do_utimensat(fname, modtime, mod_nsec) == 0) | if (do_utimensat(fname, stp) == 0) |
break; |
break; |
|
#ifdef SUPPORT_FORCE_CHANGE |
|
if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0) |
|
break; |
|
#endif |
if (errno != ENOSYS) |
if (errno != ENOSYS) |
return -1; |
return -1; |
switch_step++; |
switch_step++; |
/* FALLTHROUGH */ |
|
#endif |
#endif |
|
|
#ifdef HAVE_LUTIMES |
#ifdef HAVE_LUTIMES |
#include "case_N.h" |
#include "case_N.h" |
if (do_lutimes(fname, modtime, mod_nsec) == 0) | if (do_lutimes(fname, stp) == 0) |
break; |
break; |
|
#ifdef SUPPORT_FORCE_CHANGE |
|
if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0) |
|
break; |
|
#endif |
if (errno != ENOSYS) |
if (errno != ENOSYS) |
return -1; |
return -1; |
switch_step++; |
switch_step++; |
/* FALLTHROUGH */ |
|
#endif |
#endif |
|
|
#include "case_N.h" |
#include "case_N.h" |
switch_step++; |
switch_step++; |
if (preserve_times & PRESERVE_LINK_TIMES) { |
if (preserve_times & PRESERVE_LINK_TIMES) { |
preserve_times &= ~PRESERVE_LINK_TIMES; |
preserve_times &= ~PRESERVE_LINK_TIMES; |
if (S_ISLNK(mode)) | if (S_ISLNK(stp->st_mode)) |
return 1; |
return 1; |
} |
} |
/* FALLTHROUGH */ |
|
|
|
#include "case_N.h" |
#include "case_N.h" |
#ifdef HAVE_UTIMES |
#ifdef HAVE_UTIMES |
if (do_utimes(fname, modtime, mod_nsec) == 0) | if (do_utimes(fname, stp) == 0) |
break; |
break; |
#else |
#else |
if (do_utime(fname, modtime, mod_nsec) == 0) | if (do_utime(fname, stp) == 0) |
break; |
break; |
#endif |
#endif |
|
#ifdef SUPPORT_FORCE_CHANGE |
|
if (force_change && errno == EPERM && try_a_force_change(fname, stp) == 0) |
|
break; |
|
#endif |
|
|
return -1; |
return -1; |
} |
} |
Line 175 int set_modtime(const char *fname, time_t modtime, uin
|
Line 223 int set_modtime(const char *fname, time_t modtime, uin
|
/* Create any necessary directories in fname. Any missing directories are |
/* Create any necessary directories in fname. Any missing directories are |
* created with default permissions. Returns < 0 on error, or the number |
* created with default permissions. Returns < 0 on error, or the number |
* of directories created. */ |
* of directories created. */ |
int make_path(char *fname, int flags) | int make_path(char *fname, mode_t mode, int flags) |
{ |
{ |
char *end, *p; |
char *end, *p; |
int ret = 0; |
int ret = 0; |
Line 206 int make_path(char *fname, int flags)
|
Line 254 int make_path(char *fname, int flags)
|
else |
else |
errno = ENOTDIR; |
errno = ENOTDIR; |
} |
} |
} else if (do_mkdir(fname, ACCESSPERMS) == 0) { | } else if (do_mkdir(fname, mode) == 0) { |
ret++; |
ret++; |
break; |
break; |
} |
} |
Line 245 int make_path(char *fname, int flags)
|
Line 293 int make_path(char *fname, int flags)
|
p += strlen(p); |
p += strlen(p); |
if (ret < 0) /* Skip mkdir on error, but keep restoring the path. */ |
if (ret < 0) /* Skip mkdir on error, but keep restoring the path. */ |
continue; |
continue; |
if (do_mkdir(fname, ACCESSPERMS) < 0) | if (do_mkdir(fname, mode) < 0) |
ret = -ret - 1; |
ret = -ret - 1; |
else |
else |
ret++; |
ret++; |
Line 323 int copy_file(const char *source, const char *dest, in
|
Line 371 int copy_file(const char *source, const char *dest, in
|
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 prealloc_len = 0, offset = 0; |
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 338 int copy_file(const char *source, const char *dest, in
|
Line 384 int copy_file(const char *source, const char *dest, in
|
if (robust_unlink(dest) && errno != ENOENT) { |
if (robust_unlink(dest) && errno != ENOENT) { |
int save_errno = errno; |
int save_errno = errno; |
rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest)); |
rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest)); |
|
close(ifd); |
errno = save_errno; |
errno = save_errno; |
return -1; |
return -1; |
} |
} |
Line 365 int copy_file(const char *source, const char *dest, in
|
Line 412 int copy_file(const char *source, const char *dest, in
|
if (do_fstat(ifd, &srcst) < 0) |
if (do_fstat(ifd, &srcst) < 0) |
rsyserr(FWARNING, errno, "fstat %s", full_fname(source)); |
rsyserr(FWARNING, errno, "fstat %s", full_fname(source)); |
else if (srcst.st_size > 0) { |
else if (srcst.st_size > 0) { |
if (do_fallocate(ofd, 0, srcst.st_size) == 0) { | prealloc_len = do_fallocate(ofd, 0, srcst.st_size); |
#ifdef PREALLOCATE_NEEDS_TRUNCATE | if (prealloc_len < 0) |
preallocated_len = srcst.st_size; | |
#endif | |
} else | |
rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest)); |
rsyserr(FWARNING, errno, "do_fallocate %s", full_fname(dest)); |
} |
} |
} |
} |
Line 384 int copy_file(const char *source, const char *dest, in
|
Line 428 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; |
offset += len; |
#endif |
|
} |
} |
|
|
if (len < 0) { |
if (len < 0) { |
Line 403 int copy_file(const char *source, const char *dest, in
|
Line 445 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. |
/* Source file might have shrunk since we fstatted it. |
* Cut off any extra preallocated zeros from dest file. */ |
* Cut off any extra preallocated zeros from dest file. */ |
if (offset < preallocated_len && do_ftruncate(ofd, offset) < 0) { | if (offset < prealloc_len && do_ftruncate(ofd, offset) < 0) { |
/* If we fail to truncate, the dest file may be wrong, so we |
/* If we fail to truncate, the dest file may be wrong, so we |
* must trigger the "partial transfer" error. */ |
* must trigger the "partial transfer" error. */ |
rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest)); |
rsyserr(FERROR_XFER, errno, "ftruncate %s", full_fname(dest)); |
} |
} |
#endif |
|
|
|
|
if (do_fsync && fsync(ofd) < 0) { |
|
rsyserr(FERROR, errno, "fsync failed on %s", |
|
full_fname(dest)); |
|
close(ofd); |
|
return -1; |
|
} |
|
|
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 499 int robust_rename(const char *from, const char *to, co
|
Line 546 int robust_rename(const char *from, const char *to, co
|
{ |
{ |
int tries = 4; |
int tries = 4; |
|
|
|
/* A resumed in-place partial-dir transfer might call us with from and |
|
* to pointing to the same buf if the transfer failed yet again. */ |
|
if (from == to) |
|
return 0; |
|
|
while (tries--) { |
while (tries--) { |
if (do_rename(from, to) == 0) |
if (do_rename(from, to) == 0) |
return 0; |
return 0; |
Line 588 int lock_range(int fd, int offset, int len)
|
Line 640 int lock_range(int fd, int offset, int len)
|
} |
} |
|
|
#define ENSURE_MEMSPACE(buf, type, sz, req) \ |
#define ENSURE_MEMSPACE(buf, type, sz, req) \ |
if ((req) > sz && !(buf = realloc_array(buf, type, sz = MAX(sz * 2, req)))) \ | do { if ((req) > sz) buf = realloc_array(buf, type, sz = MAX(sz * 2, req)); } while(0) |
out_of_memory("glob_expand") | |
|
|
static inline void call_glob_match(const char *name, int len, int from_glob, |
static inline void call_glob_match(const char *name, int len, int from_glob, |
char *arg, int abpos, int fbpos); |
char *arg, int abpos, int fbpos); |
Line 691 static inline void call_glob_match(const char *name, i
|
Line 742 static inline void call_glob_match(const char *name, i
|
glob_match(arg, abpos, fbpos); |
glob_match(arg, abpos, fbpos); |
} else { |
} else { |
ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1); |
ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, glob.argc + 1); |
if (!(glob.argv[glob.argc++] = strdup(glob.arg_buf))) | glob.argv[glob.argc++] = strdup(glob.arg_buf); |
out_of_memory("glob_match"); | |
} |
} |
} |
} |
|
|
Line 716 int glob_expand(const char *arg, char ***argv_p, int *
|
Line 766 int glob_expand(const char *arg, char ***argv_p, int *
|
s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS); |
s = sanitize_path(NULL, arg, "", 0, SP_KEEP_DOT_DIRS); |
else { |
else { |
s = strdup(arg); |
s = strdup(arg); |
if (!s) | clean_fname(s, CFN_KEEP_DOT_DIRS | CFN_KEEP_TRAILING_SLASH | CFN_COLLAPSE_DOT_DOT_DIRS); |
out_of_memory("glob_expand"); | |
clean_fname(s, CFN_KEEP_DOT_DIRS | |
| CFN_KEEP_TRAILING_SLASH | |
| CFN_COLLAPSE_DOT_DOT_DIRS); | |
} |
} |
|
|
ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN); |
ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN); |
Line 769 void glob_expand_module(char *base1, char *arg, char *
|
Line 815 void glob_expand_module(char *base1, char *arg, char *
|
return; |
return; |
} |
} |
|
|
if (!(arg = strdup(arg))) | arg = strdup(arg); |
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"); |
Line 800 void strlower(char *s)
|
Line 845 void strlower(char *s)
|
} |
} |
} |
} |
|
|
|
/** |
|
* Split a string into tokens based (usually) on whitespace & commas. If the |
|
* string starts with a comma (after skipping any leading whitespace), then |
|
* splitting is done only on commas. No empty tokens are ever returned. */ |
|
char *conf_strtok(char *str) |
|
{ |
|
static int commas_only = 0; |
|
|
|
if (str) { |
|
while (isSpace(str)) str++; |
|
if (*str == ',') { |
|
commas_only = 1; |
|
str++; |
|
} else |
|
commas_only = 0; |
|
} |
|
|
|
while (commas_only) { |
|
char *end, *tok = strtok(str, ","); |
|
if (!tok) |
|
return NULL; |
|
/* Trim just leading and trailing whitespace. */ |
|
while (isSpace(tok)) |
|
tok++; |
|
end = tok + strlen(tok); |
|
while (end > tok && isSpace(end-1)) |
|
*--end = '\0'; |
|
if (*tok) |
|
return tok; |
|
str = NULL; |
|
} |
|
|
|
return strtok(str, " ,\t\r\n"); |
|
} |
|
|
/* Join strings p1 & p2 into "dest" with a guaranteed '/' between them. (If |
/* 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 |
* p1 ends with a '/', no extra '/' is inserted.) Returns the length of both |
* strings + 1 (if '/' was inserted), regardless of whether the null-terminated |
* strings + 1 (if '/' was inserted), regardless of whether the null-terminated |
Line 852 size_t stringjoin(char *dest, size_t destsize, ...)
|
Line 932 size_t stringjoin(char *dest, size_t destsize, ...)
|
return ret; |
return ret; |
} |
} |
|
|
|
/* Append formatted text at *dest_ptr up to a maximum of sz (like snprintf). |
|
* On success, advance *dest_ptr and return True; on overflow, return False. */ |
|
BOOL snappendf(char **dest_ptr, size_t sz, const char *format, ...) |
|
{ |
|
va_list ap; |
|
size_t len; |
|
|
|
va_start(ap, format); |
|
len = vsnprintf(*dest_ptr, sz, format, ap); |
|
va_end(ap); |
|
|
|
if (len >= sz) |
|
return False; |
|
else { |
|
*dest_ptr += len; |
|
return True; |
|
} |
|
} |
|
|
int count_dir_elements(const char *p) |
int count_dir_elements(const char *p) |
{ |
{ |
int cnt = 0, new_component = 1; |
int cnt = 0, new_component = 1; |
Line 966 int clean_fname(char *name, int flags)
|
Line 1065 int clean_fname(char *name, int flags)
|
* ALWAYS collapses ".." elements (except for those at the start of the |
* ALWAYS collapses ".." elements (except for those at the start of the |
* string up to "depth" deep). If the resulting name would be empty, |
* string up to "depth" deep). If the resulting name would be empty, |
* change it into a ".". */ |
* change it into a ".". */ |
char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth, | char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth, int flags) |
int flags) | |
{ |
{ |
char *start, *sanp; |
char *start, *sanp; |
int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS); |
int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS); |
|
|
if (dest != p) { |
if (dest != p) { |
int plen = strlen(p); | int plen = strlen(p); /* the path len INCLUDING any separating slash */ |
if (*p == '/') { |
if (*p == '/') { |
if (!rootdir) |
if (!rootdir) |
rootdir = module_dir; |
rootdir = module_dir; |
Line 981 char *sanitize_path(char *dest, const char *p, const c
|
Line 1079 char *sanitize_path(char *dest, const char *p, const c
|
depth = 0; |
depth = 0; |
p++; |
p++; |
} |
} |
if (dest) { | if (!dest) |
if (rlen + plen + 1 >= MAXPATHLEN) | dest = new_array(char, MAX(rlen + plen + 1, 2)); |
return NULL; | else if (rlen + plen + 1 >= MAXPATHLEN) |
} else if (!(dest = new_array(char, rlen + plen + 1))) | return NULL; |
out_of_memory("sanitize_path"); | if (rlen) { /* only true if p previously started with a slash */ |
if (rlen) { | |
memcpy(dest, rootdir, rlen); |
memcpy(dest, rootdir, rlen); |
if (rlen > 1) | if (rlen > 1) /* a rootdir of len 1 is "/", so this avoids a 2nd slash */ |
dest[rlen++] = '/'; |
dest[rlen++] = '/'; |
} |
} |
} |
} |
Line 1077 int change_dir(const char *dir, int set_path_only)
|
Line 1174 int change_dir(const char *dir, int set_path_only)
|
skipped_chdir = set_path_only; |
skipped_chdir = set_path_only; |
memcpy(curr_dir, dir, len + 1); |
memcpy(curr_dir, dir, len + 1); |
} else { |
} else { |
|
unsigned int save_dir_len = curr_dir_len; |
if (curr_dir_len + 1 + len >= sizeof curr_dir) { |
if (curr_dir_len + 1 + len >= sizeof curr_dir) { |
errno = ENAMETOOLONG; |
errno = ENAMETOOLONG; |
return 0; |
return 0; |
Line 1086 int change_dir(const char *dir, int set_path_only)
|
Line 1184 int change_dir(const char *dir, int set_path_only)
|
memcpy(curr_dir + curr_dir_len, dir, len + 1); |
memcpy(curr_dir + curr_dir_len, dir, len + 1); |
|
|
if (!set_path_only && chdir(curr_dir)) { |
if (!set_path_only && chdir(curr_dir)) { |
|
curr_dir_len = save_dir_len; |
curr_dir[curr_dir_len] = '\0'; |
curr_dir[curr_dir_len] = '\0'; |
return 0; |
return 0; |
} |
} |
Line 1117 char *normalize_path(char *path, BOOL force_newbuf, un
|
Line 1216 char *normalize_path(char *path, BOOL force_newbuf, un
|
return NULL; |
return NULL; |
curr_dir[curr_dir_len] = '/'; |
curr_dir[curr_dir_len] = '/'; |
memcpy(curr_dir + curr_dir_len + 1, path, len + 1); |
memcpy(curr_dir + curr_dir_len + 1, path, len + 1); |
if (!(path = strdup(curr_dir))) | path = strdup(curr_dir); |
out_of_memory("normalize_path"); | |
curr_dir[curr_dir_len] = '\0'; |
curr_dir[curr_dir_len] = '\0'; |
} else if (force_newbuf) { | } else if (force_newbuf) |
if (!(path = strdup(path))) | path = strdup(path); |
out_of_memory("normalize_path"); | |
} | |
|
|
len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR); |
len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR); |
|
|
Line 1133 char *normalize_path(char *path, BOOL force_newbuf, un
|
Line 1229 char *normalize_path(char *path, BOOL force_newbuf, un
|
return path; |
return path; |
} |
} |
|
|
|
/* 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; |
|
} |
|
|
/** |
/** |
* Return a quoted string with the full pathname of the indicated filename. |
* Return a quoted string with the full pathname of the indicated filename. |
* The string " (in MODNAME)" may also be appended. The returned pointer |
* The string " (in MODNAME)" may also be appended. The returned pointer |
Line 1226 int handle_partial_dir(const char *fname, int create)
|
Line 1348 int handle_partial_dir(const char *fname, int create)
|
} |
} |
statret = -1; |
statret = -1; |
} |
} |
if (statret < 0 && do_mkdir(dir, 0700) < 0) { | if (statret < 0 && make_path(dir, 0700, 0) < 0) { |
*fn = '/'; |
*fn = '/'; |
return 0; |
return 0; |
} |
} |
Line 1299 int unsafe_symlink(const char *dest, const char *src)
|
Line 1421 int unsafe_symlink(const char *dest, const char *src)
|
/* 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) |
{ |
{ |
static char TimeBuf[200]; | static int ndx = 0; |
| static char buffers[4][20]; /* We support 4 simultaneous timestring results. */ |
| char *TimeBuf = buffers[ndx = (ndx + 1) % 4]; |
struct tm *tm = localtime(&t); |
struct tm *tm = localtime(&t); |
char *p; | int len = snprintf(TimeBuf, sizeof buffers[0], "%4d/%02d/%02d %02d:%02d:%02d", |
| (int)tm->tm_year + 1900, (int)tm->tm_mon + 1, (int)tm->tm_mday, |
| (int)tm->tm_hour, (int)tm->tm_min, (int)tm->tm_sec); |
| assert(len > 0); /* Silence gcc warning */ |
|
|
#ifdef HAVE_STRFTIME |
|
strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm); |
|
#else |
|
strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf); |
|
#endif |
|
|
|
if ((p = strchr(TimeBuf, '\n')) != NULL) |
|
*p = '\0'; |
|
|
|
return TimeBuf; |
return TimeBuf; |
} |
} |
|
|
/* 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). |
* | * Returns 1 if the times the "same", or 0 if they are different. */ |
* @retval 0 if the times should be treated as the same | int same_time(time_t f1_sec, unsigned long f1_nsec, time_t f2_sec, unsigned long f2_nsec) |
* | |
* @retval +1 if the first is later | |
* | |
* @retval -1 if the 2nd is later | |
**/ | |
int cmp_time(time_t file1, time_t file2) | |
{ |
{ |
if (file2 > file1) { | if (modify_window == 0) |
/* The final comparison makes sure that modify_window doesn't overflow a | return f1_sec == f2_sec; |
* time_t, which would mean that file2 must be in the equality window. */ | if (modify_window < 0) |
if (!modify_window || (file2 > file1 + modify_window && file1 + modify_window > file1)) | return f1_sec == f2_sec && f1_nsec == f2_nsec; |
return -1; | /* The nano seconds doesn't figure into these checks -- time windows don't care about that. */ |
} else if (file1 > file2) { | if (f2_sec > f1_sec) |
if (!modify_window || (file1 > file2 + modify_window && file2 + modify_window > file2)) | return f2_sec - f1_sec <= modify_window; |
return 1; | return f1_sec - f2_sec <= modify_window; |
} | |
return 0; | |
} |
} |
|
|
#ifdef __INSURE__XX |
#ifdef __INSURE__XX |
Line 1409 const char *find_filename_suffix(const char *fn, int f
|
Line 1519 const char *find_filename_suffix(const char *fn, int f
|
} else if (s_len == 5) { |
} else if (s_len == 5) { |
if (strcmp(s+1, "orig") == 0) |
if (strcmp(s+1, "orig") == 0) |
continue; |
continue; |
} else if (s_len > 2 && had_tilde | } else if (s_len > 2 && had_tilde && s[1] == '~' && isDigit(s + 2)) |
&& s[1] == '~' && isDigit(s + 2)) | |
continue; |
continue; |
*len_ptr = s_len; |
*len_ptr = s_len; |
suf = s; |
suf = s; |
Line 1421 const char *find_filename_suffix(const char *fn, int f
|
Line 1530 const char *find_filename_suffix(const char *fn, int f
|
if (!isDigit(s)) |
if (!isDigit(s)) |
return suf; |
return suf; |
} |
} |
/* An all-digit suffix may not be that signficant. */ | /* An all-digit suffix may not be that significant. */ |
s = suf; |
s = suf; |
} |
} |
|
|
Line 1485 uint32 fuzzy_distance(const char *s1, unsigned len1, c
|
Line 1594 uint32 fuzzy_distance(const char *s1, unsigned len1, c
|
#define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */ |
#define BB_PER_SLOT_INTS (BB_SLOT_SIZE / 4) /* Number of int32s per slot */ |
|
|
struct bitbag { |
struct bitbag { |
uint32 **bits; | uint32 **bits; |
int slot_cnt; | int slot_cnt; |
}; |
}; |
|
|
struct bitbag *bitbag_create(int max_ndx) |
struct bitbag *bitbag_create(int max_ndx) |
Line 1494 struct bitbag *bitbag_create(int max_ndx)
|
Line 1603 struct bitbag *bitbag_create(int max_ndx)
|
struct bitbag *bb = new(struct bitbag); |
struct bitbag *bb = new(struct bitbag); |
bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS; |
bb->slot_cnt = (max_ndx + BB_PER_SLOT_BITS - 1) / BB_PER_SLOT_BITS; |
|
|
if (!(bb->bits = (uint32**)calloc(bb->slot_cnt, sizeof (uint32*)))) | bb->bits = new_array0(uint32*, bb->slot_cnt); |
out_of_memory("bitbag_create"); | |
|
|
return bb; |
return bb; |
} |
} |
Line 1505 void bitbag_set_bit(struct bitbag *bb, int ndx)
|
Line 1613 void bitbag_set_bit(struct bitbag *bb, int ndx)
|
int slot = ndx / BB_PER_SLOT_BITS; |
int slot = ndx / BB_PER_SLOT_BITS; |
ndx %= BB_PER_SLOT_BITS; |
ndx %= BB_PER_SLOT_BITS; |
|
|
if (!bb->bits[slot]) { | if (!bb->bits[slot]) |
if (!(bb->bits[slot] = (uint32*)calloc(BB_PER_SLOT_INTS, 4))) | bb->bits[slot] = new_array0(uint32, BB_PER_SLOT_INTS); |
out_of_memory("bitbag_set_bit"); | |
} | |
|
|
bb->bits[slot][ndx/32] |= 1u << (ndx % 32); |
bb->bits[slot][ndx/32] |= 1u << (ndx % 32); |
} |
} |
Line 1576 void flist_ndx_push(flist_ndx_list *lp, int ndx)
|
Line 1682 void flist_ndx_push(flist_ndx_list *lp, int ndx)
|
{ |
{ |
struct flist_ndx_item *item; |
struct flist_ndx_item *item; |
|
|
if (!(item = new(struct flist_ndx_item))) | item = new(struct flist_ndx_item); |
out_of_memory("flist_ndx_push"); | |
item->next = NULL; |
item->next = NULL; |
item->ndx = ndx; |
item->ndx = ndx; |
if (lp->tail) |
if (lp->tail) |
Line 1613 int flist_ndx_pop(flist_ndx_list *lp)
|
Line 1718 int flist_ndx_pop(flist_ndx_list *lp)
|
* After the size check, the list's count is incremented by 1 and a pointer |
* After the size check, the list's count is incremented by 1 and a pointer |
* to the "new" list item is returned. |
* 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) | |
{ |
{ |
/* First time through, 0 <= 0, so list is expanded. */ |
/* First time through, 0 <= 0, so list is expanded. */ |
if (lp->malloced <= lp->count) { |
if (lp->malloced <= lp->count) { |
void *new_ptr; |
void *new_ptr; |
size_t new_size = lp->malloced; | size_t expand_size; |
if (incr < 0) |
if (incr < 0) |
new_size += -incr; /* increase slowly */ | expand_size = -incr; /* increase slowly */ |
else if (new_size < (size_t)incr) | else if (lp->malloced < (size_t)incr) |
new_size = incr; | expand_size = incr - lp->malloced; |
else if (new_size) | else if (lp->malloced) |
new_size *= 2; | expand_size = lp->malloced; /* double in size */ |
else |
else |
new_size = 1; | expand_size = 1; |
if (new_size <= lp->malloced) | if (SIZE_MAX/item_size - expand_size < lp->malloced) |
overflow_exit("expand_item_list"); |
overflow_exit("expand_item_list"); |
/* Using _realloc_array() lets us pass the size, not a type. */ | expand_size += lp->malloced; |
new_ptr = _realloc_array(lp->items, item_size, new_size); | new_ptr = realloc_buf(lp->items, expand_size * item_size); |
if (DEBUG_GTE(FLIST, 3)) { |
if (DEBUG_GTE(FLIST, 3)) { |
rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n", |
rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n", |
who_am_i(), desc, big_num(new_size * item_size), | who_am_i(), desc, big_num(expand_size * item_size), |
new_ptr == lp->items ? " not" : ""); |
new_ptr == lp->items ? " not" : ""); |
} |
} |
if (!new_ptr) |
|
out_of_memory("expand_item_list"); |
|
|
|
lp->items = new_ptr; |
lp->items = new_ptr; |
lp->malloced = new_size; | lp->malloced = expand_size; |
} |
} |
return (char*)lp->items + (lp->count++ * item_size); |
return (char*)lp->items + (lp->count++ * item_size); |
|
} |
|
|
|
/* This zeroing of memory won't be optimized away by the compiler. */ |
|
void force_memzero(void *buf, size_t len) |
|
{ |
|
volatile uchar *z = buf; |
|
while (len-- > 0) |
|
*z++ = '\0'; |
} |
} |