Improve the "--delete does not work without -r or -d" message.
[rsync.git] / options.c
index 90c0b9147a20ddbcf3a421acd6b1c3b12c26844e..7b9e5a8d36b3125be0893058a7f64b41f82d2d0a 100644 (file)
--- a/options.c
+++ b/options.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 1998-2001 Andrew Tridgell <tridge@samba.org>
  * Copyright (C) 2000, 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2002-2008 Wayne Davison
+ * Copyright (C) 2002-2009 Wayne Davison
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -261,7 +261,7 @@ static void print_rsync_version(enum logcode f)
 
        rprintf(f, "%s  version %s  protocol version %d%s\n",
                RSYNC_NAME, RSYNC_VERSION, PROTOCOL_VERSION, subprotocol);
-       rprintf(f, "Copyright (C) 1996-2008 by Andrew Tridgell, Wayne Davison, and others.\n");
+       rprintf(f, "Copyright (C) 1996-2009 by Andrew Tridgell, Wayne Davison, and others.\n");
        rprintf(f, "Web site: http://rsync.samba.org/\n");
        rprintf(f, "Capabilities:\n");
        rprintf(f, "    %d-bit files, %d-bit inums, %d-bit timestamps, %d-bit long ints,\n",
@@ -1357,6 +1357,12 @@ int parse_arguments(int *argc_p, const char ***argv_p)
                        "--read-batch cannot be used with --files-from\n");
                return 0;
        }
+       if (read_batch && remove_source_files) {
+               snprintf(err_buf, sizeof err_buf,
+                       "--read-batch cannot be used with --remove-%s-files\n",
+                       remove_source_files == 1 ? "source" : "sent");
+               return 0;
+       }
        if (batch_name && strlen(batch_name) > MAX_BATCH_NAME_LEN) {
                snprintf(err_buf, sizeof err_buf,
                        "the batch-file name must be %d characters or less.\n",
@@ -1426,7 +1432,7 @@ int parse_arguments(int *argc_p, const char ***argv_p)
        }
        if (!xfer_dirs && delete_mode) {
                snprintf(err_buf, sizeof err_buf,
-                       "--delete does not work without -r or -d.\n");
+                       "--delete does not work without --recursive (-r) or --dirs (-d).\n");
                return 0;
        }
 
@@ -2075,6 +2081,62 @@ void server_options(char **args, int *argc_p)
        out_of_memory("server_options");
 }
 
+/* If str points to a valid hostspec, return allocated memory containing the
+ * [USER@]HOST part of the string, and set the path_start_ptr to the part of
+ * the string after the host part.  Otherwise, return NULL.  If port_ptr is
+ * non-NULL, we must be parsing an rsync:// URL hostname, and we will set
+ * *port_ptr if a port number is found.  Note that IPv6 IPs will have their
+ * (required for parsing) [ and ] chars elided from the returned string. */
+static char *parse_hostspec(char *str, char **path_start_ptr, int *port_ptr)
+{
+       char *s, *host_start = str;
+       int hostlen = 0, userlen = 0;
+       char *ret;
+
+       for (s = str; ; s++) {
+               if (!*s) {
+                       /* It is only OK if we run out of string with rsync:// */
+                       if (!port_ptr)
+                               return NULL;
+                       if (!hostlen)
+                               hostlen = s - host_start;
+                       break;
+               }
+               if (*s == ':' || *s == '/') {
+                       if (!hostlen)
+                               hostlen = s - host_start;
+                       if (*s++ == '/') {
+                               if (!port_ptr)
+                                       return NULL;
+                       } else if (port_ptr) {
+                               *port_ptr = atoi(s);
+                               while (isDigit(s)) s++;
+                               if (*s && *s++ != '/')
+                                       return NULL;
+                       }
+                       break;
+               }
+               if (*s == '@') {
+                       userlen = s - str + 1;
+                       host_start = s + 1;
+               } else if (*s == '[') {
+                       if (s != host_start++)
+                               return NULL;
+                       while (*s && *s != ']' && *s != '/') s++; /*SHARED ITERATOR*/
+                       hostlen = s - host_start;
+                       if (*s != ']' || (s[1] && s[1] != '/' && s[1] != ':') || !hostlen)
+                               return NULL;
+               }
+       }
+
+       *path_start_ptr = s;
+       ret = new_array(char, userlen + hostlen + 1);
+       if (userlen)
+               strlcpy(ret, str, userlen + 1);
+       strlcpy(ret + userlen, host_start, hostlen + 1);
+       return ret;
+}
+
 /* Look for a HOST specfication of the form "HOST:PATH", "HOST::PATH", or
  * "rsync://HOST:PORT/PATH".  If found, *host_ptr will be set to some allocated
  * memory with the HOST.  If a daemon-accessing spec was specified, the value
@@ -2084,68 +2146,28 @@ void server_options(char **args, int *argc_p)
  * "[::ffff:127.0.0.1]") which is returned without the '[' and ']'. */
 char *check_for_hostspec(char *s, char **host_ptr, int *port_ptr)
 {
-       char *p;
-       int not_host;
-       int hostlen;
+       char *path;
 
        if (port_ptr && strncasecmp(URL_PREFIX, s, strlen(URL_PREFIX)) == 0) {
-               char *path;
-               s += strlen(URL_PREFIX);
-               if ((p = strchr(s, '/')) != NULL) {
-                       hostlen = p - s;
-                       path = p + 1;
-               } else {
-                       hostlen = strlen(s);
-                       path = "";
+               *host_ptr = parse_hostspec(s + strlen(URL_PREFIX), &path, port_ptr);
+               if (*host_ptr) {
+                       if (!*port_ptr)
+                               *port_ptr = RSYNC_PORT;
+                       return path;
                }
-               if (*s == '[' && (p = strchr(s, ']')) != NULL) {
-                       s++;
-                       hostlen = p - s;
-                       if (p[1] == ':')
-                               *port_ptr = atoi(p+2);
-               } else {
-                       if ((p = strchr(s, ':')) != NULL && p < s + hostlen) {
-                               hostlen = p - s;
-                               *port_ptr = atoi(p+1);
-                       }
-               }
-               if (!*port_ptr)
-                       *port_ptr = RSYNC_PORT;
-               *host_ptr = new_array(char, hostlen + 1);
-               strlcpy(*host_ptr, s, hostlen + 1);
-               return path;
-       }
-
-       if (*s == '[' && (p = strchr(s, ']')) != NULL && p[1] == ':') {
-               s++;
-               hostlen = p - s;
-               *p = '\0';
-               not_host = strchr(s, '/') || !strchr(s, ':');
-               *p = ']';
-               if (not_host)
-                       return NULL;
-               p++;
-       } else {
-               if (!(p = strchr(s, ':')))
-                       return NULL;
-               hostlen = p - s;
-               *p = '\0';
-               not_host = strchr(s, '/') != NULL;
-               *p = ':';
-               if (not_host)
-                       return NULL;
        }
 
-       *host_ptr = new_array(char, hostlen + 1);
-       strlcpy(*host_ptr, s, hostlen + 1);
+       *host_ptr = parse_hostspec(s, &path, NULL);
+       if (!*host_ptr)
+               return NULL;
 
-       if (p[1] == ':') {
+       if (*path == ':') {
                if (port_ptr && !*port_ptr)
                        *port_ptr = RSYNC_PORT;
-               return p + 2;
+               return path + 1;
        }
        if (port_ptr)
                *port_ptr = 0;
 
-       return p + 1;
+       return path;
 }