Changed NO_INT64 to INT64_IS_OFF_T because off_t might actually be
[rsync/rsync.git] / options.c
index 2f73bae..2c3515f 100644 (file)
--- a/options.c
+++ b/options.c
@@ -22,6 +22,7 @@
 #include "popt.h"
 
 extern int sanitize_paths;
+extern int select_timeout;
 extern char curr_dir[MAXPATHLEN];
 extern struct exclude_list_struct exclude_list;
 
@@ -93,6 +94,7 @@ int ignore_errors = 0;
 int modify_window = 0;
 int blocking_io = -1;
 int checksum_seed = 0;
+int inplace = 0;
 unsigned int block_size = 0;
 
 
@@ -132,15 +134,14 @@ int quiet = 0;
 int always_checksum = 0;
 int list_only = 0;
 
-#define FIXED_CHECKSUM_SEED 32761
-#define MAX_BATCH_PREFIX_LEN 256       /* Must be less than MAXPATHLEN-13 */
-char *batch_prefix = NULL;
+#define MAX_BATCH_NAME_LEN 256 /* Must be less than MAXPATHLEN-13 */
+char *batch_name = NULL;
 
 static int daemon_opt;   /* sets am_daemon after option error-reporting */
 static int modify_window_set;
 
 /** Local address to bind.  As a character string because it's
- * interpreted by the IPv6 layer: should be a numeric IP4 or ip6
+ * interpreted by the IPv6 layer: should be a numeric IP4 or IP6
  * address, or a hostname. **/
 char *bind_address;
 
@@ -148,6 +149,7 @@ char *bind_address;
 static void print_rsync_version(enum logcode f)
 {
        char const *got_socketpair = "no ";
+       char const *have_inplace = "no ";
        char const *hardlinks = "no ";
        char const *links = "no ";
        char const *ipv6 = "no ";
@@ -157,6 +159,10 @@ static void print_rsync_version(enum logcode f)
        got_socketpair = "";
 #endif
 
+#if HAVE_FTRUNCATE
+       have_inplace = "";
+#endif
+
 #if SUPPORT_HARD_LINKS
        hardlinks = "";
 #endif
@@ -182,8 +188,8 @@ static void print_rsync_version(enum logcode f)
        /* Note that this field may not have type ino_t.  It depends
         * on the complicated interaction between largefile feature
         * macros. */
-       rprintf(f, "              %sIPv6, %d-bit system inums, %d-bit internal inums\n",
-               ipv6,
+       rprintf(f, "              %sinplace, %sIPv6, %d-bit system inums, %d-bit internal inums\n",
+               have_inplace, ipv6,
                (int) (sizeof dumstat->st_ino * 8),
                (int) (sizeof (uint64) * 8));
 #ifdef MAINTAINER_MODE
@@ -191,8 +197,9 @@ static void print_rsync_version(enum logcode f)
                get_panic_action());
 #endif
 
-#ifdef NO_INT64
-       rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
+#ifdef INT64_IS_OFF_T
+       if (sizeof (int64) < 8)
+               rprintf(f, "WARNING: no 64-bit integers on this platform!\n");
 #endif
 
        rprintf(f,
@@ -233,6 +240,7 @@ void usage(enum logcode F)
   rprintf(F,"     --backup-dir            make backups into this directory\n");
   rprintf(F,"     --suffix=SUFFIX         backup suffix (default %s w/o --backup-dir)\n",BACKUP_SUFFIX);
   rprintf(F," -u, --update                update only (don't overwrite newer files)\n");
+  rprintf(F,"     --inplace               update destination files inplace (SEE MAN PAGE)\n");
   rprintf(F," -K, --keep-dirlinks         treat symlinked dir on receiver as dir\n");
   rprintf(F," -l, --links                 copy symlinks as symlinks\n");
   rprintf(F," -L, --copy-links            copy the referent of all symlinks\n");
@@ -266,7 +274,7 @@ void usage(enum logcode F)
   rprintf(F," -I, --ignore-times          turn off mod time & file size quick check\n");
   rprintf(F,"     --size-only             ignore mod time for quick check (use size)\n");
   rprintf(F,"     --modify-window=NUM     compare mod times with reduced accuracy\n");
-  rprintf(F," -T  --temp-dir=DIR          create temporary files in directory DIR\n");
+  rprintf(F," -T, --temp-dir=DIR          create temporary files in directory DIR\n");
   rprintf(F,"     --compare-dest=DIR      also compare destination files relative to DIR\n");
   rprintf(F,"     --link-dest=DIR         create hardlinks to DIR for unchanged files\n");
   rprintf(F," -P                          equivalent to --partial --progress\n");
@@ -277,7 +285,7 @@ void usage(enum logcode F)
   rprintf(F,"     --include=PATTERN       don't exclude files matching PATTERN\n");
   rprintf(F,"     --include-from=FILE     don't exclude patterns listed in FILE\n");
   rprintf(F,"     --files-from=FILE       read FILE for list of source-file names\n");
-  rprintf(F," -0  --from0                 all *-from file lists are delimited by nulls\n");
+  rprintf(F," -0, --from0                 all *-from file lists are delimited by nulls\n");
   rprintf(F,"     --version               print version number\n");
   rprintf(F,"     --daemon                run as an rsync daemon\n");
   rprintf(F,"     --no-detach             do not detach from the parent\n");
@@ -291,12 +299,12 @@ void usage(enum logcode F)
   rprintf(F,"     --log-format=FORMAT     log file transfers using specified format\n");
   rprintf(F,"     --password-file=FILE    get password from FILE\n");
   rprintf(F,"     --bwlimit=KBPS          limit I/O bandwidth, KBytes per second\n");
-  rprintf(F,"     --write-batch=PREFIX    write batch fileset starting with PREFIX\n");
-  rprintf(F,"     --read-batch=PREFIX     read batch fileset starting with PREFIX\n");
+  rprintf(F,"     --write-batch=FILE      write a batch to FILE\n");
+  rprintf(F,"     --read-batch=FILE       read a batch from FILE\n");
   rprintf(F,"     --checksum-seed=NUM     set block/file checksum seed\n");
 #ifdef INET6
-  rprintf(F," -4  --ipv4                  prefer IPv4\n");
-  rprintf(F," -6  --ipv6                  prefer IPv6\n");
+  rprintf(F," -4, --ipv4                  prefer IPv4\n");
+  rprintf(F," -6, --ipv6                  prefer IPv6\n");
 #endif
   rprintf(F," -h, --help                  show this help screen\n");
 
@@ -309,7 +317,7 @@ void usage(enum logcode F)
 enum {OPT_VERSION = 1000, OPT_SENDER, OPT_EXCLUDE, OPT_EXCLUDE_FROM,
       OPT_DELETE_AFTER, OPT_DELETE_EXCLUDED, OPT_LINK_DEST,
       OPT_INCLUDE, OPT_INCLUDE_FROM, OPT_MODIFY_WINDOW,
-      OPT_READ_BATCH, OPT_WRITE_BATCH,
+      OPT_READ_BATCH, OPT_WRITE_BATCH, OPT_TIMEOUT,
       OPT_REFUSED_BASE = 9000};
 
 static struct poptOption long_options[] = {
@@ -340,6 +348,7 @@ static struct poptOption long_options[] = {
   {"sparse",          'S', POPT_ARG_NONE,   &sparse_files, 0, 0, 0 },
   {"cvs-exclude",     'C', POPT_ARG_NONE,   &cvs_exclude, 0, 0, 0 },
   {"update",          'u', POPT_ARG_NONE,   &update_only, 0, 0, 0 },
+  {"inplace",          0,  POPT_ARG_NONE,   &inplace, 0, 0, 0 },
   {"keep-dirlinks",   'K', POPT_ARG_NONE,   &keep_dirlinks, 0, 0, 0 },
   {"links",           'l', POPT_ARG_NONE,   &preserve_links, 0, 0, 0 },
   {"copy-links",      'L', POPT_ARG_NONE,   &copy_links, 0, 0, 0 },
@@ -363,7 +372,7 @@ static struct poptOption long_options[] = {
   {"rsh",             'e', POPT_ARG_STRING, &shell_cmd, 0, 0, 0 },
   {"block-size",      'B', POPT_ARG_INT,    &block_size, 0, 0, 0 },
   {"max-delete",       0,  POPT_ARG_INT,    &max_delete, 0, 0, 0 },
-  {"timeout",          0,  POPT_ARG_INT,    &io_timeout, 0, 0, 0 },
+  {"timeout",          0,  POPT_ARG_INT,    &io_timeout, OPT_TIMEOUT, 0, 0 },
   {"temp-dir",        'T', POPT_ARG_STRING, &tmpdir, 0, 0, 0 },
   {"compare-dest",     0,  POPT_ARG_STRING, &compare_dest, 0, 0, 0 },
   {"link-dest",        0,  POPT_ARG_STRING, &compare_dest,  OPT_LINK_DEST, 0, 0 },
@@ -385,8 +394,8 @@ static struct poptOption long_options[] = {
   {"address",          0,  POPT_ARG_STRING, &bind_address, 0, 0, 0 },
   {"backup-dir",       0,  POPT_ARG_STRING, &backup_dir, 0, 0, 0 },
   {"hard-links",      'H', POPT_ARG_NONE,   &preserve_hard_links, 0, 0, 0 },
-  {"read-batch",       0,  POPT_ARG_STRING, &batch_prefix,  OPT_READ_BATCH, 0, 0 },
-  {"write-batch",      0,  POPT_ARG_STRING, &batch_prefix,  OPT_WRITE_BATCH, 0, 0 },
+  {"read-batch",       0,  POPT_ARG_STRING, &batch_name,  OPT_READ_BATCH, 0, 0 },
+  {"write-batch",      0,  POPT_ARG_STRING, &batch_name,  OPT_WRITE_BATCH, 0, 0 },
   {"files-from",       0,  POPT_ARG_STRING, &files_from, 0, 0, 0 },
   {"from0",           '0', POPT_ARG_NONE,   &eol_nulls, 0, 0, 0},
   {"no-implied-dirs",  0,  POPT_ARG_VAL,    &implied_dirs, 0, 0, 0 },
@@ -410,17 +419,12 @@ static char err_buf[200];
  **/
 void option_error(void)
 {
-       int save_daemon = am_daemon;
-
        if (!err_buf[0]) {
                strcpy(err_buf, "Error parsing options: "
                    "option may be supported on client but not on server?\n");
        }
 
-       rwrite(FLOG, err_buf, strlen(err_buf));
-       am_daemon = 0;
        rprintf(FERROR, RSYNC_NAME ": %s", err_buf);
-       am_daemon = save_daemon;
 }
 
 
@@ -573,15 +577,18 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        break;
 
                case OPT_WRITE_BATCH:
-                       /* popt stores the filename in batch_prefix for us */
+                       /* batch_name is already set */
                        write_batch = 1;
-                       checksum_seed = FIXED_CHECKSUM_SEED;
                        break;
 
                case OPT_READ_BATCH:
-                       /* popt stores the filename in batch_prefix for us */
+                       /* batch_name is already set */
                        read_batch = 1;
-                       checksum_seed = FIXED_CHECKSUM_SEED;
+                       break;
+
+               case OPT_TIMEOUT:
+                       if (io_timeout && io_timeout < select_timeout)
+                               select_timeout = io_timeout;
                        break;
 
                case OPT_LINK_DEST:
@@ -637,26 +644,49 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
        }
 #endif
 
+       if (block_size > MAX_MAP_SIZE) {
+               rprintf(FINFO, "limiting block-size to %d bytes\n",
+                       MAX_MAP_SIZE);
+               block_size = MAX_MAP_SIZE;
+       }
+
        if (write_batch && read_batch) {
                rprintf(FERROR,
-                       "write-batch and read-batch can not be used together\n");
+                       "--write-batch and --read-batch can not be used together\n");
                exit_cleanup(RERR_SYNTAX);
        }
-       if (batch_prefix && strlen(batch_prefix) > MAX_BATCH_PREFIX_LEN) {
+       if (write_batch || read_batch) {
+               if (dry_run) {
+                       rprintf(FERROR,
+                               "--%s-batch cannot be used with --dry_run (-n)\n",
+                               write_batch ? "write" : "read");
+                       exit_cleanup(RERR_SYNTAX);
+               }
+               if (am_server) {
+                       rprintf(FINFO,
+                               "ignoring --%s-batch option sent to server\n",
+                               write_batch ? "write" : "read");
+                       /* We don't actually exit_cleanup(), so that we can
+                        * still service older version clients that still send
+                        * batch args to server. */
+                       read_batch = write_batch = 0;
+                       batch_name = NULL;
+               }
+       }
+       if (read_batch && files_from) {
                rprintf(FERROR,
-                       "the batch-file prefix must be %d characters or less.\n",
-                       MAX_BATCH_PREFIX_LEN);
+                       "--read-batch cannot be used with --files-from\n");
                exit_cleanup(RERR_SYNTAX);
        }
-
-       if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
-               rprintf(FERROR, "the --temp-dir path is WAY too long.\n");
+       if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
+               rprintf(FERROR,
+                       "the batch-file name must be %d characters or less.\n",
+                       MAX_BATCH_NAME_LEN);
                exit_cleanup(RERR_SYNTAX);
        }
 
-       if (do_compression && (write_batch || read_batch)) {
-               rprintf(FERROR,
-                       "compress can not be used with write-batch or read-batch\n");
+       if (tmpdir && strlen(tmpdir) >= MAXPATHLEN - 10) {
+               rprintf(FERROR, "the --temp-dir path is WAY too long.\n");
                exit_cleanup(RERR_SYNTAX);
        }
 
@@ -738,6 +768,17 @@ int parse_arguments(int *argc, const char ***argv, int frommain)
                        bwlimit_writemax = 512;
        }
 
+       if (inplace) {
+#if HAVE_FTRUNCATE
+               keep_partial = 0;
+#else
+               snprintf(err_buf, sizeof err_buf,
+                        "--inplace is not supported on this %s\n",
+                        am_server ? "server" : "client");
+               return 0;
+#endif
+       }
+
        if (files_from) {
                char *colon;
                if (*argc != 2 && !(am_server && am_sender && *argc == 1)) {
@@ -883,13 +924,6 @@ void server_options(char **args,int *argc)
                args[ac++] = arg;
        }
 
-       if (batch_prefix) {
-               char *r_or_w = write_batch ? "write" : "read";
-               if (asprintf(&arg, "--%s-batch=%s", r_or_w, batch_prefix) < 0)
-                       goto oom;
-               args[ac++] = arg;
-       }
-
        if (io_timeout) {
                if (asprintf(&arg, "--timeout=%d", io_timeout) < 0)
                        goto oom;
@@ -962,6 +996,9 @@ void server_options(char **args,int *argc)
        if (opt_ignore_existing && am_sender)
                args[ac++] = "--ignore-existing";
 
+       if (inplace)
+               args[ac++] = "--inplace";
+
        if (tmpdir) {
                args[ac++] = "--temp-dir";
                args[ac++] = tmpdir;