static int set_perms(char *fname,struct file_struct *file,STRUCT_STAT *st,
int report)
{
- int updated = 0;
- STRUCT_STAT st2;
- extern int am_daemon;
+ int updated = 0;
+ STRUCT_STAT st2;
+ extern int am_daemon;
- if (dry_run) return 0;
+ if (dry_run) return 0;
- if (!st) {
- if (link_stat(fname,&st2) != 0) {
- rprintf(FERROR,"stat %s : %s\n",fname,strerror(errno));
- return 0;
- }
- st = &st2;
- }
+ if (!st) {
+ if (link_stat(fname,&st2) != 0) {
+ rprintf(FERROR,"stat %s : %s\n",fname,strerror(errno));
+ return 0;
+ }
+ st = &st2;
+ }
- if (preserve_times && !S_ISLNK(st->st_mode) &&
- st->st_mtime != file->modtime) {
- updated = 1;
- if (set_modtime(fname,file->modtime) != 0) {
- rprintf(FERROR,"failed to set times on %s : %s\n",
- fname,strerror(errno));
- return 0;
- }
- }
+ if (preserve_times && !S_ISLNK(st->st_mode) &&
+ st->st_mtime != file->modtime) {
+ updated = 1;
+ if (set_modtime(fname,file->modtime) != 0) {
+ rprintf(FERROR,"failed to set times on %s : %s\n",
+ fname,strerror(errno));
+ return 0;
+ }
+ }
+
+ if ((am_root || !am_daemon) &&
+ ((am_root && preserve_uid && st->st_uid != file->uid) ||
+ (preserve_gid && st->st_gid != file->gid))) {
+ if (do_lchown(fname,
+ (am_root&&preserve_uid)?file->uid:-1,
+ preserve_gid?file->gid:-1) != 0) {
+ if (preserve_uid && st->st_uid != file->uid)
+ updated = 1;
+ if (verbose>1 || preserve_uid) {
+ rprintf(FERROR,"chown %s : %s\n",
+ fname,strerror(errno));
+ return 0;
+ }
+ } else {
+ updated = 1;
+ }
+ }
#ifdef HAVE_CHMOD
- if (preserve_perms && !S_ISLNK(st->st_mode) &&
- st->st_mode != file->mode) {
- updated = 1;
- if (do_chmod(fname,file->mode) != 0) {
- rprintf(FERROR,"failed to set permissions on %s : %s\n",
- fname,strerror(errno));
- return 0;
- }
- }
+ if (preserve_perms && !S_ISLNK(st->st_mode) &&
+ (st->st_mode != file->mode ||
+ (updated && (file->mode & ~ACCESSPERMS)))) {
+ updated = 1;
+ if (do_chmod(fname,file->mode) != 0) {
+ rprintf(FERROR,"failed to set permissions on %s : %s\n",
+ fname,strerror(errno));
+ return 0;
+ }
+ }
#endif
-
- if ((am_root || !am_daemon) &&
- ((am_root && preserve_uid && st->st_uid != file->uid) ||
- (preserve_gid && st->st_gid != file->gid))) {
- if (do_lchown(fname,
- (am_root&&preserve_uid)?file->uid:-1,
- preserve_gid?file->gid:-1) != 0) {
- if (preserve_uid && st->st_uid != file->uid)
- updated = 1;
- if (verbose>1 || preserve_uid)
- rprintf(FERROR,"chown %s : %s\n",
- fname,strerror(errno));
- return updated;
- }
- updated = 1;
- }
- if (verbose > 1 && report) {
- if (updated)
- rprintf(FINFO,"%s\n",fname);
- else
- rprintf(FINFO,"%s is uptodate\n",fname);
- }
- return updated;
+ if (verbose > 1 && report) {
+ if (updated)
+ rprintf(FINFO,"%s\n",fname);
+ else
+ rprintf(FINFO,"%s is uptodate\n",fname);
+ }
+ return updated;
}
}
static char *cleanup_fname;
+static char *cleanup_new_fname;
+static struct file_struct *cleanup_file;
+static void finish_transfer(char *fname, char *fnametmp, struct file_struct *file);
void exit_cleanup(int code)
{
+ extern int keep_partial;
+
+ if (cleanup_fname && keep_partial) {
+ finish_transfer(cleanup_new_fname, cleanup_fname, cleanup_file);
+ }
io_flush();
- if (cleanup_fname)
+ if (cleanup_fname && !keep_partial)
do_unlink(cleanup_fname);
signal(SIGUSR1, SIG_IGN);
if (code) {
return 1;
}
+/* finish off a file transfer, renaming the file and setting the permissions
+ and ownership */
+static void finish_transfer(char *fname, char *fnametmp, struct file_struct *file)
+{
+ if (make_backups) {
+ char fnamebak[MAXPATHLEN];
+ if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
+ rprintf(FERROR,"backup filename too long\n");
+ return;
+ }
+ slprintf(fnamebak,sizeof(fnamebak)-1,"%s%s",fname,backup_suffix);
+ if (do_rename(fname,fnamebak) != 0 && errno != ENOENT) {
+ rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno));
+ return;
+ }
+ }
+
+ /* move tmp file over real file */
+ if (do_rename(fnametmp,fname) != 0) {
+ if (errno == EXDEV) {
+ /* rename failed on cross-filesystem link.
+ Copy the file instead. */
+ if (copy_file(fnametmp,fname, file->mode)) {
+ rprintf(FERROR,"copy %s -> %s : %s\n",
+ fnametmp,fname,strerror(errno));
+ } else {
+ set_perms(fname,file,NULL,0);
+ }
+ do_unlink(fnametmp);
+ } else {
+ rprintf(FERROR,"rename %s -> %s : %s\n",
+ fnametmp,fname,strerror(errno));
+ do_unlink(fnametmp);
+ }
+ } else {
+ set_perms(fname,file,NULL,0);
+ }
+}
+
+
int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
{
int fd1,fd2;
}
while (1) {
+ cleanup_fname = NULL;
+ cleanup_new_fname = NULL;
+
i = read_int(f_in);
if (i == -1) {
if (phase==0 && remote_version >= 13) {
continue;
}
- fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode);
+ /* we initially set the perms without the
+ setuid/setgid bits to ensure that there is no race
+ condition. They are then correctly updated after
+ the lchown. Thanks to snabb@epipe.fi for pointing
+ this out */
+ fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
+ file->mode & ACCESSPERMS);
+
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
- fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode);
+ fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
+ file->mode & ACCESSPERMS);
}
if (fd2 == -1) {
rprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno));
}
cleanup_fname = fnametmp;
+ cleanup_new_fname = fname;
+ cleanup_file = file;
if (!am_server && verbose)
printf("%s\n",fname);
if (verbose > 2)
rprintf(FINFO,"renaming %s to %s\n",fnametmp,fname);
-
- if (make_backups) {
- char fnamebak[MAXPATHLEN];
- if (strlen(fname) + strlen(backup_suffix) > (MAXPATHLEN-1)) {
- rprintf(FERROR,"backup filename too long\n");
- continue;
- }
- slprintf(fnamebak,sizeof(fnamebak)-1,"%s%s",fname,backup_suffix);
- if (do_rename(fname,fnamebak) != 0 && errno != ENOENT) {
- rprintf(FERROR,"rename %s %s : %s\n",fname,fnamebak,strerror(errno));
- continue;
- }
- }
-
- /* move tmp file over real file */
- if (do_rename(fnametmp,fname) != 0) {
- if (errno == EXDEV) {
- /* rename failed on cross-filesystem link.
- Copy the file instead. */
- if (copy_file(fnametmp,fname, file->mode)) {
- rprintf(FERROR,"copy %s -> %s : %s\n",
- fnametmp,fname,strerror(errno));
- } else {
- set_perms(fname,file,NULL,0);
- }
- do_unlink(fnametmp);
- } else {
- rprintf(FERROR,"rename %s -> %s : %s\n",
- fnametmp,fname,strerror(errno));
- do_unlink(fnametmp);
- }
- } else {
- set_perms(fname,file,NULL,0);
- }
+ finish_transfer(fname, fnametmp, file);
+
cleanup_fname = NULL;
-
+ cleanup_new_fname = NULL;
+ cleanup_file = NULL;
if (!recv_ok) {
if (csum_length == SUM_LENGTH) {