#include "rsync.h"
#include "ifuncs.h"
+#include "itypes.h"
+#include "inums.h"
-extern int verbose;
extern int dry_run;
extern int module_id;
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;
return 1;
#endif
- if (verbose > 2) {
+ if (DEBUG_GTE(TIME, 1)) {
rprintf(FINFO, "set modtime of %s to (%ld) %s",
fname, (long)modtime,
asctime(localtime(&modtime)));
/* 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;
}
counter = 1;
} 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",
fname, path);
}
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:
if (partialptr) {
if (!handle_partial_dir(partialptr,PDIR_CREATE))
- return -1;
+ return -2;
to = partialptr;
}
if (copy_file(from, to, -1, mode, 0) != 0)
} else
use_buf = glob.arg_buf;
- if (from_glob || arg) {
+ if (from_glob || (arg && len)) {
STRUCT_STAT st;
int is_dir;
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);
return 1;
}
+/* This will make a relative path absolute and clean it up via clean_fname().
+ * Returns the string, which might be newly allocated, or NULL on error. */
+char *normalize_path(char *path, BOOL force_newbuf, unsigned int *len_ptr)
+{
+ unsigned int len;
+
+ if (*path != '/') { /* Make path absolute. */
+ int len = strlen(path);
+ if (curr_dir_len + 1 + len >= sizeof curr_dir)
+ return NULL;
+ curr_dir[curr_dir_len] = '/';
+ memcpy(curr_dir + curr_dir_len + 1, path, len + 1);
+ if (!(path = strdup(curr_dir)))
+ out_of_memory("normalize_path");
+ curr_dir[curr_dir_len] = '\0';
+ } else if (force_newbuf) {
+ if (!(path = strdup(path)))
+ out_of_memory("normalize_path");
+ }
+
+ len = clean_fname(path, CFN_COLLAPSE_DOT_DOT_DIRS | CFN_DROP_TRAILING_DOT_DIR);
+
+ if (len_ptr)
+ *len_ptr = len;
+
+ return path;
+}
+
/**
* Return a quoted string with the full pathname of the indicated filename.
* The string " (in MODNAME)" may also be appended. The returned pointer
STRUCT_STAT st;
int statret = do_lstat(dir, &st);
if (statret == 0 && !S_ISDIR(st.st_mode)) {
- if (do_unlink(dir) < 0)
+ if (do_unlink(dir) < 0) {
+ *fn = '/';
return 0;
+ }
statret = -1;
}
- if (statret < 0 && do_mkdir(dir, 0700) < 0)
+ if (statret < 0 && do_mkdir(dir, 0700) < 0) {
+ *fn = '/';
return 0;
+ }
} else
do_rmdir(dir);
*fn = '/';
return (depth < 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;
-
- n = (n + 1) % (sizeof bufs / sizeof bufs[0]);
-
- if (human_readable) {
- char units = '\0';
- int mult = human_readable == 1 ? 1000 : 1024;
- double dnum = 0;
- if (num > mult*mult*mult) {
- dnum = (double)num / (mult*mult*mult);
- units = 'G';
- } else if (num > mult*mult) {
- dnum = (double)num / (mult*mult);
- units = 'M';
- } else if (num > mult) {
- dnum = (double)num / mult;
- units = 'K';
- }
- if (units) {
- snprintf(bufs[n], sizeof bufs[0], "%.2f%c", dnum, units);
- return bufs[n];
- }
- }
-
- s = bufs[n] + sizeof bufs[0] - 1;
- *s = '\0';
-
- if (!num)
- *--s = '0';
- while (num) {
- *--s = (char)(num % 10) + '0';
- num /= 10;
- }
- 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 + 1;
- snprintf(buf, len + decimal_digits + 2, "%.*f", decimal_digits, dnum);
- }
- return buf;
-}
-
/* Return the date and time as a string. Some callers tweak returned buf. */
char *timestring(time_t t)
{
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;
return -1;
}
+void flist_ndx_push(flist_ndx_list *lp, int ndx)
+{
+ struct flist_ndx_item *item;
+
+ if (!(item = new(struct flist_ndx_item)))
+ out_of_memory("flist_ndx_push");
+ item->next = NULL;
+ item->ndx = ndx;
+ if (lp->tail)
+ lp->tail->next = item;
+ else
+ lp->head = item;
+ lp->tail = item;
+}
+
+int flist_ndx_pop(flist_ndx_list *lp)
+{
+ struct flist_ndx_item *next;
+ int ndx;
+
+ if (!lp->head)
+ return -1;
+
+ ndx = lp->head->ndx;
+ next = lp->head->next;
+ free(lp->head);
+ lp->head = next;
+ if (!next)
+ lp->tail = NULL;
+
+ return ndx;
+}
+
void *expand_item_list(item_list *lp, size_t item_size,
const char *desc, int incr)
{
new_size += incr;
else
new_size *= 2;
- new_ptr = realloc_array(lp->items, char, new_size * item_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,
+ 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 (DEBUG_GTE(FLIST, 3)) {
+ rprintf(FINFO, "[%s] expand %s to %s bytes, did%s move\n",
+ who_am_i(), desc, big_num(new_size * item_size),
new_ptr == lp->items ? " not" : "");
}
if (!new_ptr)