*** empty log message ***
authorAndrew Tridgell <tridge@samba.org>
Tue, 13 Jan 1998 18:35:10 +0000 (18:35 +0000)
committerAndrew Tridgell <tridge@samba.org>
Tue, 13 Jan 1998 18:35:10 +0000 (18:35 +0000)
main.c
rsync.c
util.c

diff --git a/main.c b/main.c
index 16f280d..9b2d9db 100644 (file)
--- 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 673f141..3eb6467 100644 (file)
--- 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 e53d02a..d04a217 100644 (file)
--- 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;
+}