extern int modify_window;
extern int relative_paths;
extern int human_readable;
+extern int preserve_xattrs;
extern char *module_dir;
extern unsigned int module_dirlen;
extern mode_t orig_umask;
/* Copy a file. If ofd < 0, copy_file unlinks and opens the "dest" file.
* Otherwise, it just writes to and closes the provided file descriptor.
+ * In either case, if --xattrs are being preserved, the dest file will
+ * have its xattrs set from the source file.
*
* This is used in conjunction with the --temp-dir, --backup, and
* --copy-dest options. */
int len; /* Number of bytes read into `buf'. */
if ((ifd = do_open(source, O_RDONLY, 0)) < 0) {
+ int save_errno = errno;
rsyserr(FERROR_XFER, errno, "open %s", full_fname(source));
+ errno = save_errno;
return -1;
}
if (ofd < 0) {
if (robust_unlink(dest) && errno != ENOENT) {
+ int save_errno = errno;
rsyserr(FERROR_XFER, errno, "unlink %s", full_fname(dest));
+ errno = save_errno;
return -1;
}
- if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0
- && (!create_bak_dir || errno != ENOENT || make_bak_dir(dest) < 0
- || (ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0)) {
- rsyserr(FERROR_XFER, errno, "open %s", full_fname(dest));
- close(ifd);
- return -1;
+ if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0) {
+ int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
+ if (create_bak_dir && errno == ENOENT && make_bak_dir(dest) == 0) {
+ if ((ofd = do_open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode)) < 0)
+ save_errno = errno ? errno : save_errno;
+ else
+ save_errno = 0;
+ }
+ if (save_errno) {
+ rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(dest));
+ close(ifd);
+ errno = save_errno;
+ return -1;
+ }
}
}
while ((len = safe_read(ifd, buf, sizeof buf)) > 0) {
if (full_write(ofd, buf, len) < 0) {
+ int save_errno = errno;
rsyserr(FERROR_XFER, errno, "write %s", full_fname(dest));
close(ifd);
close(ofd);
+ errno = save_errno;
return -1;
}
}
if (len < 0) {
+ int save_errno = errno;
rsyserr(FERROR_XFER, errno, "read %s", full_fname(source));
close(ifd);
close(ofd);
+ errno = save_errno;
return -1;
}
}
if (close(ofd) < 0) {
+ int save_errno = errno;
rsyserr(FERROR_XFER, errno, "close failed on %s",
full_fname(dest));
+ errno = save_errno;
return -1;
}
+#ifdef SUPPORT_XATTRS
+ if (preserve_xattrs)
+ copy_xattrs(source, dest);
+#endif
+
return 0;
}
switch (errno) {
#ifdef ETXTBSY
case ETXTBSY:
- if (robust_unlink(to) != 0)
+ if (robust_unlink(to) != 0) {
+ errno = ETXTBSY;
return -1;
+ }
+ errno = ETXTBSY;
break;
#endif
case EXDEV:
}
#define ENSURE_MEMSPACE(buf, type, sz, req) \
- if ((req) >= sz && !(buf = realloc_array(buf, type, sz *= 2))) \
- out_of_memory("ENSURE_MEMSPACE")
+ if ((req) > sz && !(buf = realloc_array(buf, type, sz = MAX(sz * 2, req)))) \
+ out_of_memory("glob_expand")
static inline void call_glob_match(const char *name, int len, int from_glob,
char *arg, int abpos, int fbpos);
while (*arg == '.' && arg[1] == '/') {
if (fbpos < 0) {
- if (glob.fbsize < glob.absize) {
- glob.filt_buf = realloc_array(glob.filt_buf,
- char, glob.fbsize = glob.absize);
- }
+ ENSURE_MEMSPACE(glob.filt_buf, char, glob.fbsize, glob.absize);
memcpy(glob.filt_buf, glob.arg_buf, abpos + 1);
fbpos = abpos;
}
- ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + 2);
+ ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, abpos + 3);
glob.arg_buf[abpos++] = *arg++;
glob.arg_buf[abpos++] = *arg++;
glob.arg_buf[abpos] = '\0';
} else
use_buf = glob.arg_buf;
- if (from_glob || arg) {
+ if (from_glob || (arg && len)) {
STRUCT_STAT st;
int is_dir;
- if (do_stat(glob.arg_buf, &st) != 0) {
- if (from_glob)
- return;
- is_dir = 0;
- } else {
- is_dir = S_ISDIR(st.st_mode) != 0;
- if (arg && !is_dir)
- return;
- }
+ if (do_stat(glob.arg_buf, &st) != 0)
+ return;
+ is_dir = S_ISDIR(st.st_mode) != 0;
+ if (arg && !is_dir)
+ return;
if (daemon_filter_list.head
- && check_filter(&daemon_filter_list, use_buf, is_dir) < 0) {
- if (from_glob)
- return;
- arg = NULL;
- }
+ && check_filter(&daemon_filter_list, FLOG, use_buf, is_dir) < 0)
+ return;
}
if (arg) {
| CFN_COLLAPSE_DOT_DOT_DIRS);
}
- if (glob.absize < MAXPATHLEN
- && !(glob.arg_buf = realloc_array(glob.arg_buf, char, glob.absize = MAXPATHLEN)))
- out_of_memory("glob_expand");
+ ENSURE_MEMSPACE(glob.arg_buf, char, glob.absize, MAXPATHLEN);
*glob.arg_buf = '\0';
glob.argc = save_argc = *argc_p;
glob.argv = *argv_p;
glob.maxargs = *maxargs_p;
- if (glob.maxargs < 100
- && !(glob.argv = realloc_array(glob.argv, char *, glob.maxargs = 100)))
- out_of_memory("glob_expand");
+ ENSURE_MEMSPACE(glob.argv, char *, glob.maxargs, 100);
glob_match(s, 0, -1);
/* Like chdir(), but it keeps track of the current directory (in the
* global "curr_dir"), and ensures that the path size doesn't overflow.
* Also cleans the path using the clean_fname() function. */
-int push_dir(const char *dir, int set_path_only)
+int change_dir(const char *dir, int set_path_only)
{
static int initialised;
unsigned int len;
if (len == 1 && *dir == '.')
return 1;
- if ((*dir == '/' ? len : curr_dir_len + 1 + len) >= sizeof curr_dir) {
- errno = ENAMETOOLONG;
- return 0;
- }
-
- if (!set_path_only && chdir(dir))
- return 0;
-
if (*dir == '/') {
+ if (len >= sizeof curr_dir) {
+ errno = ENAMETOOLONG;
+ return 0;
+ }
+ if (!set_path_only && chdir(dir))
+ return 0;
memcpy(curr_dir, dir, len + 1);
- curr_dir_len = len;
} else {
- curr_dir[curr_dir_len++] = '/';
- memcpy(curr_dir + curr_dir_len, dir, len + 1);
- curr_dir_len += len;
+ if (curr_dir_len + 1 + len >= sizeof curr_dir) {
+ errno = ENAMETOOLONG;
+ return 0;
+ }
+ curr_dir[curr_dir_len] = '/';
+ memcpy(curr_dir + curr_dir_len + 1, dir, len + 1);
+
+ if (!set_path_only && chdir(curr_dir)) {
+ curr_dir[curr_dir_len] = '\0';
+ return 0;
+ }
}
curr_dir_len = clean_fname(curr_dir, CFN_COLLAPSE_DOT_DOT_DIRS);
}
if (verbose >= 5 && !set_path_only)
- rprintf(FINFO, "[%s] push_dir(%s)\n", who_am_i(), curr_dir);
-
- return 1;
-}
-
-/**
- * Reverse a push_dir() call. You must pass in an absolute path
- * that was copied from a prior value of "curr_dir".
- **/
-int pop_dir(const char *dir)
-{
- if (chdir(dir))
- return 0;
-
- curr_dir_len = strlcpy(curr_dir, dir, sizeof curr_dir);
- if (curr_dir_len >= sizeof curr_dir)
- curr_dir_len = sizeof curr_dir - 1;
- if (sanitize_paths)
- curr_dir_depth = count_dir_elements(curr_dir + module_dirlen);
-
- if (verbose >= 5)
- rprintf(FINFO, "[%s] pop_dir(%s)\n", who_am_i(), curr_dir);
+ rprintf(FINFO, "[%s] change_dir(%s)\n", who_am_i(), curr_dir);
return 1;
}
if (daemon_filter_list.head) {
t = strrchr(partial_fname, '/');
*t = '\0';
- if (check_filter(&daemon_filter_list, partial_fname, 1) < 0)
+ if (check_filter(&daemon_filter_list, FLOG, partial_fname, 1) < 0)
return NULL;
*t = '/';
- if (check_filter(&daemon_filter_list, partial_fname, 0) < 0)
+ if (check_filter(&daemon_filter_list, FLOG, partial_fname, 0) < 0)
return NULL;
}
return use_calloc ? calloc(num, size) : malloc(num * size);
}
-void *_realloc_array(void *ptr, unsigned int size, unsigned long num)
+void *_realloc_array(void *ptr, unsigned int size, size_t num)
{
if (num >= MALLOC_MAX/size)
return NULL;
new_size += incr;
else
new_size *= 2;
- new_ptr = realloc_array(lp->items, char, new_size * item_size);
+ if (new_size < lp->malloced)
+ overflow_exit("expand_item_list");
+ /* Using _realloc_array() lets us pass the size, not a type. */
+ new_ptr = _realloc_array(lp->items, item_size, new_size);
if (verbose >= 4) {
rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n",
who_am_i(), desc, (double)new_size * item_size,