*
* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
- * Copyright (C) 2003-2007 Wayne Davison
+ * Copyright (C) 2003-2008 Wayne Davison
*
* 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
}
#endif
+void send_protected_args(int fd, char *args[])
+{
+ int i;
+#ifdef ICONV_OPTION
+ int convert = ic_send != (iconv_t)-1;
+ xbuf outbuf, inbuf;
+
+ if (convert)
+ alloc_xbuf(&outbuf, 1024);
+#endif
+
+ for (i = 0; args[i]; i++) {} /* find first NULL */
+ args[i] = "rsync"; /* set a new arg0 */
+ if (verbose > 1)
+ print_child_argv("protected args:", args + i + 1);
+ do {
+#ifdef ICONV_OPTION
+ if (convert) {
+ INIT_XBUF_STRLEN(inbuf, args[i]);
+ iconvbufs(ic_send, &inbuf, &outbuf,
+ ICB_EXPAND_OUT | ICB_INCLUDE_BAD | ICB_INCLUDE_INCOMPLETE);
+ outbuf.buf[outbuf.len] = '\0';
+ write_buf(fd, outbuf.buf, outbuf.len + 1);
+ outbuf.len = 0;
+ } else
+#endif
+ write_buf(fd, args[i], strlen(args[i]) + 1);
+ } while (args[++i]);
+ write_byte(fd, 0);
+
+#ifdef ICONV_OPTION
+ if (convert)
+ free(outbuf.buf);
+#endif
+}
+
int read_ndx_and_attrs(int f_in, int *iflag_ptr, uchar *type_ptr,
char *buf, int *len_ptr)
{
}
if (!(flist = flist_for_ndx(ndx))) {
+ int start, used;
invalid_ndx:
+ start = first_flist ? first_flist->ndx_start : 0;
+ used = first_flist ? first_flist->used : 0;
rprintf(FERROR,
"Invalid file index: %d (%d - %d) with iflags %x [%s]\n",
- ndx, first_flist ? first_flist->ndx_start - 1 : -1,
- first_flist ? first_flist->prev->ndx_end : -1,
- iflags, who_am_i());
+ ndx, start - 1, start + used -1, iflags, who_am_i());
exit_cleanup(RERR_PROTOCOL);
}
cur_flist = flist;
if (dry_run)
return 1;
if (link_stat(fname, &sx2.st, 0) < 0) {
- rsyserr(FERROR, errno, "stat %s failed",
+ rsyserr(FERROR_XFER, errno, "stat %s failed",
full_fname(fname));
return 0;
}
new_mode |= S_ISGID;
}
+ if (daemon_chmod_modes && !S_ISLNK(new_mode))
+ new_mode = tweak_mode(new_mode, daemon_chmod_modes);
+
#ifdef SUPPORT_ACLS
if (preserve_acls && !S_ISLNK(file->mode) && !ACL_READY(*sxp))
get_acl(fname, sxp);
#endif
#ifdef SUPPORT_XATTRS
+ if (am_root < 0)
+ set_stat_xattr(fname, file, new_mode);
if (preserve_xattrs && fnamecmp)
set_xattr(fname, file, fnamecmp, sxp);
- if (am_root < 0)
- set_stat_xattr(fname, file);
#endif
if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && preserve_times == 1))
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
int ret = set_modtime(fname, file->modtime, sxp->st.st_mode);
if (ret < 0) {
- rsyserr(FERROR, errno, "failed to set times on %s",
+ rsyserr(FERROR_XFER, errno, "failed to set times on %s",
full_fname(fname));
goto cleanup;
}
if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1;
+ else
+ file->flags |= FLAG_TIME_FAILED;
}
change_uid = am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file);
fname, (unsigned)sxp->st.st_gid, F_GROUP(file));
}
}
- if (am_root < 0) {
- ;
- } else if (do_lchown(fname,
- change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid,
- change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid) != 0) {
- /* shouldn't have attempted to change uid or gid
- * unless have the privilege */
- rsyserr(FERROR, errno, "%s %s failed",
- change_uid ? "chown" : "chgrp",
- full_fname(fname));
- goto cleanup;
- } else
- /* a lchown had been done - we have to re-stat if the
- * destination had the setuid or setgid bits set due
- * to the side effect of the chown call */
- if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
- link_stat(fname, &sxp->st,
- keep_dirlinks && S_ISDIR(sxp->st.st_mode));
+ if (am_root >= 0) {
+ if (do_lchown(fname,
+ change_uid ? (uid_t)F_OWNER(file) : sxp->st.st_uid,
+ change_gid ? (gid_t)F_GROUP(file) : sxp->st.st_gid) != 0) {
+ /* We shouldn't have attempted to change uid
+ * or gid unless have the privilege. */
+ rsyserr(FERROR_XFER, errno, "%s %s failed",
+ change_uid ? "chown" : "chgrp",
+ full_fname(fname));
+ goto cleanup;
+ }
+ /* A lchown had been done, so we need to re-stat if
+ * the destination had the setuid or setgid bits set
+ * (due to the side effect of the chown call). */
+ if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
+ link_stat(fname, &sxp->st,
+ keep_dirlinks && S_ISDIR(sxp->st.st_mode));
+ }
}
updated = 1;
}
- if (daemon_chmod_modes && !S_ISLNK(new_mode))
- new_mode = tweak_mode(new_mode, daemon_chmod_modes);
-
#ifdef SUPPORT_ACLS
/* It's OK to call set_acl() now, even for a dir, as the generator
* will enable owner-writability using chmod, if necessary.
if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
int ret = am_root < 0 ? 0 : do_chmod(fname, new_mode);
if (ret < 0) {
- rsyserr(FERROR, errno,
+ rsyserr(FERROR_XFER, errno,
"failed to set permissions on %s",
full_fname(fname));
goto cleanup;
}
/* Finish off a file transfer: renaming the file and setting the file's
- * attributes (e.g. permissions, ownership, etc.). If partialptr is not
- * NULL and the robust_rename() call is forced to copy the temp file, we
- * stage the file into the partial-dir and then rename it into place. */
-void finish_transfer(const char *fname, const char *fnametmp,
- const char *fnamecmp, const char *partialptr,
- struct file_struct *file, int ok_to_set_time,
- int overwriting_basis)
+ * attributes (e.g. permissions, ownership, etc.). If the robust_rename()
+ * call is forced to copy the temp file and partialptr is both non-NULL and
+ * not an absolute path, we stage the file into the partial-dir and then
+ * rename it into place. This returns 1 on succcess or 0 on failure. */
+int finish_transfer(const char *fname, const char *fnametmp,
+ const char *fnamecmp, const char *partialptr,
+ struct file_struct *file, int ok_to_set_time,
+ int overwriting_basis)
{
int ret;
+ const char *temp_copy_name = partialptr && *partialptr != '/' ? partialptr : NULL;
if (inplace) {
if (verbose > 2)
goto do_set_file_attrs;
}
- if (make_backups > 0 && overwriting_basis && !make_backup(fname))
- return;
+ if (make_backups > 0 && overwriting_basis) {
+ if (!make_backup(fname))
+ return 1;
+ if (fnamecmp == fname)
+ fnamecmp = get_backup_name(fname);
+ }
/* Change permissions before putting the file into place. */
set_file_attrs(fnametmp, file, NULL, fnamecmp,
/* move tmp file over real file */
if (verbose > 2)
rprintf(FINFO, "renaming %s to %s\n", fnametmp, fname);
- ret = robust_rename(fnametmp, fname, partialptr,
+ ret = robust_rename(fnametmp, fname, temp_copy_name,
file->mode & INITACCESSPERMS);
if (ret < 0) {
- rsyserr(FERROR, errno, "%s %s -> \"%s\"",
+ rsyserr(FERROR_XFER, errno, "%s %s -> \"%s\"",
ret == -2 ? "copy" : "rename",
full_fname(fnametmp), fname);
- do_unlink(fnametmp);
- return;
+ if (!partialptr || (ret == -2 && temp_copy_name)
+ || robust_rename(fnametmp, partialptr, NULL,
+ file->mode & INITACCESSPERMS) < 0)
+ do_unlink(fnametmp);
+ return 0;
}
if (ret == 0) {
/* The file was moved into place (not copied), so it's done. */
- return;
+ return 1;
}
/* The file was copied, so tweak the perms of the copied file. If it
* was copied to partialptr, move it into its final destination. */
- fnametmp = partialptr ? partialptr : fname;
+ fnametmp = temp_copy_name ? temp_copy_name : fname;
do_set_file_attrs:
set_file_attrs(fnametmp, file, NULL, fnamecmp,
ok_to_set_time ? 0 : ATTRS_SKIP_MTIME);
- if (partialptr) {
+ if (temp_copy_name) {
if (do_rename(fnametmp, fname) < 0) {
- rsyserr(FERROR, errno, "rename %s -> \"%s\"",
+ rsyserr(FERROR_XFER, errno, "rename %s -> \"%s\"",
full_fname(fnametmp), fname);
- } else
- handle_partial_dir(partialptr, PDIR_DELETE);
+ return 0;
+ }
+ handle_partial_dir(temp_copy_name, PDIR_DELETE);
}
+ return 1;
}
struct file_list *flist_for_ndx(int ndx)
return NULL;
flist = flist->prev;
}
- while (ndx > flist->ndx_end) {
+ while (ndx >= flist->ndx_start + flist->used) {
if (!(flist = flist->next))
return NULL;
}