summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>1998-01-13 18:35:10 +0000
committerAndrew Tridgell <tridge@samba.org>1998-01-13 18:35:10 +0000
commit950ab32d38ab6ed1940ba58ff250d414e9db4708 (patch)
tree45f5281dc6f279030434de4777ea47fc25cf34c6
parentd0390cd3841db9dd175ae6c9a6472d0ca72801a8 (diff)
downloadrsync-950ab32d38ab6ed1940ba58ff250d414e9db4708.tar.gz
*** empty log message ***
-rw-r--r--main.c14
-rw-r--r--rsync.c32
-rw-r--r--util.c102
3 files changed, 141 insertions, 7 deletions
diff --git a/main.c b/main.c
index 16f280d2..9b2d9db2 100644
--- a/main.c
+++ b/main.c
@@ -26,6 +26,7 @@ off_t total_size = 0;
int block_size=BLOCK_SIZE;
char *backup_suffix = BACKUP_SUFFIX;
+char *tmpdir = NULL;
static char *rsync_path = RSYNC_NAME;
@@ -170,6 +171,11 @@ static void server_options(char **args,int *argc)
if (numeric_ids)
args[ac++] = "--numeric-ids";
+ if (tmpdir) {
+ args[ac++] = "--temp-dir";
+ args[ac++] = tmpdir;
+ }
+
*argc = ac;
}
@@ -440,6 +446,7 @@ static void usage(FILE *f)
fprintf(f," --delete delete files that don't exist on the sending side\n");
fprintf(f," --numeric-ids don't map uid/gid values by user/group name\n");
fprintf(f,"-I, --ignore-times don't exclude files that match length and time\n");
+ fprintf(f,"-T --temp-dir DIR create temporary files in directory DIR\n");
fprintf(f,"-z, --compress compress file data\n");
fprintf(f," --exclude FILE exclude file FILE\n");
fprintf(f," --exclude-from FILE exclude files listed in FILE\n");
@@ -454,7 +461,7 @@ static void usage(FILE *f)
enum {OPT_VERSION,OPT_SUFFIX,OPT_SENDER,OPT_SERVER,OPT_EXCLUDE,
OPT_EXCLUDE_FROM,OPT_DELETE,OPT_NUMERIC_IDS,OPT_RSYNC_PATH};
-static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:z";
+static char *short_options = "oblLWHpguDCtcahvrRIxnSe:B:T:z";
static struct option long_options[] = {
{"version", 0, 0, OPT_VERSION},
@@ -490,6 +497,7 @@ static struct option long_options[] = {
{"rsh", 1, 0, 'e'},
{"suffix", 1, 0, OPT_SUFFIX},
{"block-size", 1, 0, 'B'},
+ {"temp-dir", 1, 0, 'T'},
{"compress", 0, 0, 'z'},
{0,0,0,0}};
@@ -682,6 +690,10 @@ int main(int argc,char *argv[])
block_size = atoi(optarg);
break;
+ case 'T':
+ tmpdir = optarg;
+ break;
+
case 'z':
do_compression = 1;
break;
diff --git a/rsync.c b/rsync.c
index 673f1414..3eb64678 100644
--- a/rsync.c
+++ b/rsync.c
@@ -29,6 +29,7 @@ extern time_t starttime;
extern int remote_version;
extern char *backup_suffix;
+extern char *tmpdir;
extern int whole_file;
extern int block_size;
@@ -744,7 +745,17 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
close(fd1);
continue;
}
- sprintf(fnametmp,"%s.XXXXXX",fname);
+ if (tmpdir) {
+ char *f;
+ f = strrchr(fname,'/');
+ if (f == NULL)
+ f = fname;
+ else
+ f++;
+ sprintf(fnametmp,"%s/%s.XXXXXX",tmpdir,f);
+ } else {
+ sprintf(fnametmp,"%s.XXXXXX",fname);
+ }
if (NULL == mktemp(fnametmp)) {
fprintf(FERROR,"mktemp %s failed\n",fnametmp);
receive_data(f_in,buf,-1,NULL);
@@ -752,10 +763,10 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
close(fd1);
continue;
}
- fd2 = open(fnametmp,O_WRONLY|O_CREAT,file->mode);
+ fd2 = open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode);
if (fd2 == -1 && relative_paths && errno == ENOENT &&
create_directory_path(fnametmp) == 0) {
- fd2 = open(fnametmp,O_WRONLY|O_CREAT,file->mode);
+ fd2 = open(fnametmp,O_WRONLY|O_CREAT|O_EXCL,file->mode);
}
if (fd2 == -1) {
fprintf(FERROR,"open %s : %s\n",fnametmp,strerror(errno));
@@ -797,9 +808,18 @@ int recv_files(int f_in,struct file_list *flist,char *local_name,int f_gen)
/* move tmp file over real file */
if (rename(fnametmp,fname) != 0) {
- fprintf(FERROR,"rename %s -> %s : %s\n",
- fnametmp,fname,strerror(errno));
- unlink(fnametmp);
+ if (errno == EXDEV) {
+ /* rename failed on cross-filesystem link.
+ Copy the file instead. */
+ if (copy_file(fnametmp,fname, file->mode))
+ fprintf(FERROR,"copy %s -> %s : %s\n",
+ fnametmp,fname,strerror(errno));
+ unlink(fnametmp);
+ } else {
+ fprintf(FERROR,"rename %s -> %s : %s\n",
+ fnametmp,fname,strerror(errno));
+ unlink(fnametmp);
+ }
}
cleanup_fname = NULL;
diff --git a/util.c b/util.c
index e53d02a0..d04a2173 100644
--- a/util.c
+++ b/util.c
@@ -251,3 +251,105 @@ int create_directory_path(char *fname)
}
return 0;
}
+
+
+/* Write LEN bytes at PTR to descriptor DESC, retrying if interrupted.
+ Return LEN upon success, write's (negative) error code otherwise.
+
+ derived from GNU C's cccp.c.
+*/
+int full_write(int desc, char *ptr, int len)
+{
+ int total_written;
+
+ total_written = 0;
+ while (len > 0) {
+ int written = write (desc, ptr, len);
+ if (written < 0) {
+#ifdef EINTR
+ if (errno == EINTR)
+ continue;
+#endif
+ return written;
+ }
+ total_written += written;
+ ptr += written;
+ len -= written;
+ }
+ return total_written;
+}
+
+/* Read LEN bytes at PTR from descriptor DESC, retrying if interrupted.
+ Return the actual number of bytes read, zero for EOF, or negative
+ for an error.
+
+ derived from GNU C's cccp.c. */
+int safe_read(int desc, char *ptr, int len)
+{
+ int n_chars;
+
+ if (len <= 0)
+ return len;
+
+#ifdef EINTR
+ do {
+ n_chars = read(desc, ptr, len);
+ } while (n_chars < 0 && errno == EINTR);
+#else
+ n_chars = read(desc, ptr, len);
+#endif
+
+ return n_chars;
+}
+
+
+/* copy a file - this is used in conjunction with the --temp-dir option */
+int copy_file(char *source, char *dest, mode_t mode)
+{
+ int ifd;
+ int ofd;
+ char buf[1024 * 8];
+ int len; /* Number of bytes read into `buf'. */
+
+ ifd = open(source, O_RDONLY);
+ if (ifd == -1) {
+ fprintf(FERROR,"open %s: %s\n",
+ source,strerror(errno));
+ return -1;
+ }
+
+ if (unlink(dest) && errno != ENOENT) {
+ fprintf(FERROR,"unlink %s: %s\n",
+ dest,strerror(errno));
+ return -1;
+ }
+
+ ofd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, mode);
+ if (ofd < 0) {
+ fprintf(FERROR,"open %s: %s\n",
+ dest,strerror(errno));
+ close(ifd);
+ return -1;
+ }
+
+ while ((len = safe_read(ifd, buf, sizeof(buf))) > 0) {
+ if (full_write(ofd, buf, len) < 0) {
+ fprintf(FERROR,"write %s: %s\n",
+ dest,strerror(errno));
+ close(ifd);
+ close(ofd);
+ return -1;
+ }
+ }
+
+ close(ifd);
+ close(ofd);
+
+ if (len < 0) {
+ fprintf(FERROR,"read %s: %s\n",
+ source,strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}