-/*
- Copyright (C) Andrew Tridgell 1996
+/* -*- c-file-style: "linux" -*-
+
+ Copyright (C) 1996-2000 by Andrew Tridgell
Copyright (C) Paul Mackerras 1996
This program is free software; you can redistribute it and/or modify
extern char *tmpdir;
extern char *compare_dest;
extern int make_backups;
+extern int do_progress;
+extern char *backup_dir;
extern char *backup_suffix;
-
+extern int backup_suffix_len;
static struct delete_list {
- dev_t dev;
- INO_T inode;
+ DEV64_T dev;
+ INO64_T inode;
} *delete_list;
static int dlist_len, dlist_alloc_len;
for (i=0;i<dlist_len;i++) {
if (st.st_ino == delete_list[i].inode &&
- st.st_dev == delete_list[i].dev)
+ (DEV64_T)st.st_dev == delete_list[i].dev)
return 1;
}
rprintf(FINFO,"added %s to delete list\n", f_name(file));
}
-static void delete_one(struct file_struct *f)
+static void delete_one(char *fn, int is_dir)
{
- if (!S_ISDIR(f->mode)) {
- if (robust_unlink(f_name(f)) != 0) {
- rprintf(FERROR,"unlink %s : %s\n",f_name(f),strerror(errno));
+ if (!is_dir) {
+ if (robust_unlink(fn) != 0) {
+ rprintf(FERROR, "delete_one: unlink %s: %s\n",
+ fn, strerror(errno));
} else if (verbose) {
- rprintf(FINFO,"deleting %s\n",f_name(f));
+ rprintf(FINFO, "deleting %s\n", fn);
}
} else {
- if (do_rmdir(f_name(f)) != 0) {
- if (errno != ENOTEMPTY && errno != EEXIST)
- rprintf(FERROR,"rmdir %s : %s\n",f_name(f),strerror(errno));
+ if (do_rmdir(fn) != 0) {
+ if (errno != ENOTEMPTY && errno != EEXIST) {
+ rprintf(FERROR, "delete_one: rmdir %s: %s\n",
+ fn, strerror(errno));
+ }
} else if (verbose) {
- rprintf(FINFO,"deleting directory %s\n",f_name(f));
+ rprintf(FINFO, "deleting directory %s\n", fn);
}
}
}
+static int is_backup_file(char *fn)
+{
+ int k = strlen(fn) - backup_suffix_len;
+ return k > 0 && strcmp(fn+k, backup_suffix) == 0;
+}
/* this deletes any files on the receiving side that are not present
on the sending side. For version 1.6.4 I have changed the behaviour
to match more closely what most people seem to expect of this option */
-static void delete_files(struct file_list *flist)
+void delete_files(struct file_list *flist)
{
struct file_list *local_file_list;
int i, j;
char *name;
extern int module_id;
+ extern int ignore_errors;
extern int max_delete;
static int deletion_count;
if (cvs_exclude)
add_cvs_excludes();
- if (io_error && !lp_ignore_errors(module_id)) {
+ if (io_error && !(lp_ignore_errors(module_id) || ignore_errors)) {
rprintf(FINFO,"IO error encountered - skipping file deletion\n");
return;
}
add_delete_entry(local_file_list->files[i]);
if (-1 == flist_find(flist,local_file_list->files[i])) {
char *f = f_name(local_file_list->files[i]);
- int k = strlen(f) - strlen(backup_suffix);
- if (make_backups && ((k <= 0) ||
- (strcmp(f+k,backup_suffix) != 0))) {
+ if (make_backups && (backup_dir || !is_backup_file(f))) {
(void) make_backup(f);
+ if (verbose)
+ rprintf(FINFO, "deleting %s\n", f);
} else {
- deletion_count++;
- delete_one(local_file_list->files[i]);
+ int mode = local_file_list->files[i]->mode;
+ delete_one(f, S_ISDIR(mode) != 0);
}
+ deletion_count++;
}
}
flist_free(local_file_list);
}
+/*
+ * get_tmpname() - create a tmp filename for a given filename
+ *
+ * If a tmpdir is defined, use that as the directory to
+ * put it in. Otherwise, the tmp filename is in the same
+ * directory as the given name. Note that there may be no
+ * directory at all in the given name!
+ *
+ * The tmp filename is basically the given filename with a
+ * dot prepended, and .XXXXXX appended (for mkstemp() to
+ * put its unique gunk in). Take care to not exceed
+ * either the MAXPATHLEN or NAME_MAX, esp. the last, as
+ * the basename basically becomes 8 chars longer. In that
+ * case, the original name is shortened sufficiently to
+ * make it all fit.
+ *
+ * Of course, there's no real reason for the tmp name to
+ * look like the original, except to satisfy us humans.
+ * As long as it's unique, rsync will work.
+ */
+
static int get_tmpname(char *fnametmp, char *fname)
{
char *f;
+ int length = 0;
+ int maxname;
- /* open tmp file */
if (tmpdir) {
- f = strrchr(fname,'/');
- if (f == NULL)
- f = fname;
- else
- f++;
- if (strlen(tmpdir)+strlen(f)+10 > MAXPATHLEN) {
- rprintf(FERROR,"filename too long\n");
- return 0;
+ strlcpy(fnametmp, tmpdir, MAXPATHLEN - 2);
+ length = strlen(fnametmp);
+ fnametmp[length++] = '/';
+ fnametmp[length] = '\0'; /* always NULL terminated */
+ }
+
+ if ((f = strrchr(fname, '/')) != NULL) {
+ ++f;
+ if (!tmpdir) {
+ length = f - fname;
+ /* copy up to and including the slash */
+ strlcpy(fnametmp, fname, length + 1);
}
- slprintf(fnametmp,MAXPATHLEN, "%s/.%s.XXXXXX",tmpdir,f);
- return 1;
+ } else {
+ f = fname;
}
+ fnametmp[length++] = '.';
+ fnametmp[length] = '\0'; /* always NULL terminated */
- f = strrchr(fname,'/');
+ maxname = MIN(MAXPATHLEN - 7 - length, NAME_MAX - 8);
- if (strlen(fname)+9 > MAXPATHLEN) {
- rprintf(FERROR,"filename too long\n");
+ if (maxname < 1) {
+ rprintf(FERROR, "temporary filename too long: %s\n", fname);
+ fnametmp[0] = '\0';
return 0;
}
- if (f) {
- *f = 0;
- slprintf(fnametmp,MAXPATHLEN,"%s/.%s.XXXXXX",
- fname,f+1);
- *f = '/';
- } else {
- slprintf(fnametmp,MAXPATHLEN,".%s.XXXXXX",fname);
- }
+ strlcpy(fnametmp + length, f, maxname);
+ strcat(fnametmp + length, ".XXXXXX");
return 1;
}
static int receive_data(int f_in,struct map_struct *buf,int fd,char *fname,
OFF_T total_size)
{
- int i,n,remainder,len,count;
+ int i;
+ struct sum_struct sum;
+ unsigned int len;
OFF_T offset = 0;
OFF_T offset2;
char *data;
static char file_sum2[MD4_SUM_LENGTH];
char *map=NULL;
- count = read_int(f_in);
- n = read_int(f_in);
- remainder = read_int(f_in);
+ read_sum_head(f_in, &sum);
sum_init();
for (i=recv_token(f_in,&data); i != 0; i=recv_token(f_in,&data)) {
-
- show_progress(offset, total_size);
+ if (do_progress)
+ show_progress(offset, total_size);
if (i > 0) {
extern int cleanup_got_literal;
}
i = -(i+1);
- offset2 = i*(OFF_T)n;
- len = n;
- if (i == count-1 && remainder != 0)
- len = remainder;
+ offset2 = i*(OFF_T)sum.blength;
+ len = sum.blength;
+ if (i == (int) sum.count-1 && sum.remainder != 0)
+ len = sum.remainder;
stats.matched_data += len;
rprintf(FINFO,"chunk[%d] of size %d at %.0f offset=%.0f\n",
i,len,(double)offset2,(double)offset);
- map = map_ptr(buf,offset2,len);
+ if (buf) {
+ map = map_ptr(buf,offset2,len);
- see_token(map, len);
- sum_update(map,len);
+ see_token(map, len);
+ sum_update(map,len);
+ }
- if (fd != -1 && write_file(fd,map,len) != len) {
+ if (fd != -1 && write_file(fd,map,len) != (int) len) {
rprintf(FERROR,"write failed on %s : %s\n",
fname,strerror(errno));
exit_cleanup(RERR_FILEIO);
offset += len;
}
- end_progress();
+ if (do_progress)
+ end_progress(total_size);
if (fd != -1 && offset > 0 && sparse_end(fd) != 0) {
rprintf(FERROR,"write failed on %s : %s\n",
sum_end(file_sum1);
- if (remote_version >= 14) {
- read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
- if (verbose > 2) {
- rprintf(FINFO,"got file_sum\n");
- }
- if (fd != -1 &&
- memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) {
- return 0;
- }
+ read_buf(f_in,file_sum2,MD4_SUM_LENGTH);
+ if (verbose > 2) {
+ rprintf(FINFO,"got file_sum\n");
+ }
+ if (fd != -1
+ && memcmp(file_sum1,file_sum2,MD4_SUM_LENGTH) != 0) {
+ return 0;
}
return 1;
}
-
+/**
+ * main routine for receiver process.
+ *
+ * Receiver process runs on the same host as the generator process. */
int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
{
int fd1,fd2;
STRUCT_STAT st;
char *fname;
+ char template[MAXPATHLEN];
char fnametmp[MAXPATHLEN];
char *fnamecmp;
char fnamecmpbuf[MAXPATHLEN];
extern struct stats stats;
extern int preserve_perms;
extern int delete_after;
+ extern int orig_umask;
struct stats initial_stats;
if (verbose > 2) {
rprintf(FINFO,"recv_files(%d) starting\n",flist->count);
}
- if (!delete_after) {
- if (recurse && delete_mode && !local_name && flist->count>0) {
- delete_files(flist);
- }
- }
-
while (1) {
cleanup_disable();
i = read_int(f_in);
if (i == -1) {
- if (phase==0 && remote_version >= 13) {
+ if (phase==0) {
phase++;
csum_length = SUM_LENGTH;
if (verbose > 2)
fname = local_name;
if (dry_run) {
- if (!am_server) {
- log_transfer(file, fname);
+ if (!am_server && verbose) { /* log transfer */
+ rprintf(FINFO, "%s\n", fname);
}
continue;
}
if ((fd1 == -1) && (compare_dest != NULL)) {
/* try the file at compare_dest instead */
- slprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
+ snprintf(fnamecmpbuf,MAXPATHLEN,"%s/%s",
compare_dest,fname);
fnamecmp = fnamecmpbuf;
fd1 = do_open(fnamecmp, O_RDONLY, 0);
}
if (fd1 != -1 && !preserve_perms) {
- /* if the file exists already and we aren't perserving
- presmissions then act as though the remote end sent
+ /* if the file exists already and we aren't preserving
+ permissions then act as though the remote end sent
us the file permissions we already have */
file->mode = st.st_mode;
}
continue;
}
- /* mktemp is deliberately used here instead of mkstemp.
- because O_EXCL is used on the open, the race condition
- is not a problem or a security hole, and we want to
- control the access permissions on the created file. */
- if (NULL == do_mktemp(fnametmp)) {
- rprintf(FERROR,"mktemp %s failed\n",fnametmp);
- receive_data(f_in,buf,-1,NULL,file->length);
- if (buf) unmap_file(buf);
- if (fd1 != -1) close(fd1);
- continue;
- }
+ strlcpy(template, fnametmp, sizeof(template));
/* we initially set the perms without the
setuid/setgid bits to ensure that there is no race
the lchown. Thanks to snabb@epipe.fi for pointing
this out. We also set it initially without group
access because of a similar race condition. */
- fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
- file->mode & INITACCESSPERMS);
+ fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
/* in most cases parent directories will already exist
because their information should have been previously
transferred, but that may not be the case with -R */
if (fd2 == -1 && relative_paths && errno == ENOENT &&
- create_directory_path(fnametmp) == 0) {
- fd2 = do_open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,
- file->mode & INITACCESSPERMS);
+ create_directory_path(fnametmp, orig_umask) == 0) {
+ strlcpy(fnametmp, template, sizeof(fnametmp));
+ fd2 = do_mkstemp(fnametmp, file->mode & INITACCESSPERMS);
}
if (fd2 == -1) {
- rprintf(FERROR,"cannot create %s : %s\n",fnametmp,strerror(errno));
+ extern char curr_dir[];
+ char *p1, *p2;
+ if (*fnametmp == '.') {
+ p1 = curr_dir;
+ p2 = "/";
+ } else
+ p1 = p2 = "";
+ rprintf(FERROR, "mkstemp %s%s%s failed: %s\n",
+ p1, p2, fnametmp, strerror(errno));
receive_data(f_in,buf,-1,NULL,file->length);
if (buf) unmap_file(buf);
if (fd1 != -1) close(fd1);
cleanup_set(fnametmp, fname, file, buf, fd1, fd2);
- if (!am_server) {
- log_transfer(file, fname);
+ if (!am_server && verbose) { /* log transfer */
+ rprintf(FINFO, "%s\n", fname);
}
/* recv file data */
}
if (preserve_hard_links)
- do_hard_links(flist);
+ do_hard_links();
/* now we need to fix any directory permissions that were
modified during the transfer */