Some checksum improvements
[rsync.git] / compat.c
index 40de14bb5c6716c045cca25e18c7c28d6f1391e7..8c77ea6934da5b4a5e5310a2761ffe28fcb266dd 100644 (file)
--- a/compat.c
+++ b/compat.c
@@ -28,6 +28,7 @@ int compat_flags = 0;
 int use_safe_inc_flist = 0;
 int want_xattr_optim = 0;
 int proper_seed_order = 0;
+int inplace_partial = 0;
 
 extern int am_server;
 extern int am_sender;
@@ -40,6 +41,7 @@ extern int preallocate_files;
 extern int append_mode;
 extern int fuzzy_basis;
 extern int read_batch;
+extern int write_batch;
 extern int delay_updates;
 extern int checksum_seed;
 extern int basis_dir_cnt;
@@ -51,6 +53,7 @@ extern int preserve_gid;
 extern int preserve_atimes;
 extern int preserve_acls;
 extern int preserve_xattrs;
+extern int xfer_flags_as_varint;
 extern int need_messages_from_generator;
 extern int delete_mode, delete_before, delete_during, delete_after;
 extern char *shell_cmd;
@@ -58,12 +61,14 @@ extern char *partial_dir;
 extern char *dest_option;
 extern char *files_from;
 extern char *filesfrom_host;
+extern char *checksum_choice;
 extern filter_rule_list filter_list;
 extern int need_unsorted_flist;
 #ifdef ICONV_OPTION
 extern iconv_t ic_send, ic_recv;
 extern char *iconv_opt;
 #endif
+extern const char *negotiated_csum_name;
 
 /* These index values are for the file-list's extra-attribute array. */
 int pathname_ndx, depth_ndx, atimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
@@ -81,6 +86,8 @@ int filesfrom_convert = 0;
 #define CF_SAFE_FLIST   (1<<3)
 #define CF_AVOID_XATTR_OPTIM (1<<4)
 #define CF_CHKSUM_SEED_FIX (1<<5)
+#define CF_INPLACE_PARTIAL_DIR (1<<6)
+#define CF_VARINT_FLIST_FLAGS (1<<7)
 
 static const char *client_info;
 
@@ -137,6 +144,8 @@ void set_allow_inc_recurse(void)
 
 void setup_protocol(int f_out,int f_in)
 {
+       int csum_exchange = 0;
+
        assert(file_extra_cnt == 0);
        assert(EXTRA64_CNT == 2 || EXTRA64_CNT == 1);
 
@@ -283,13 +292,30 @@ void setup_protocol(int f_out,int f_in)
                                compat_flags |= CF_AVOID_XATTR_OPTIM;
                        if (local_server || strchr(client_info, 'C') != NULL)
                                compat_flags |= CF_CHKSUM_SEED_FIX;
-                       write_byte(f_out, compat_flags);
-               } else
-                       compat_flags = read_byte(f_in);
+                       if (local_server || strchr(client_info, 'I') != NULL)
+                               compat_flags |= CF_INPLACE_PARTIAL_DIR;
+                       if (local_server || strchr(client_info, 'v') != NULL) {
+                               if (!write_batch || protocol_version >= 30) {
+                                       csum_exchange = 1;
+                                       compat_flags |= CF_VARINT_FLIST_FLAGS;
+                               }
+                       }
+                       if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */
+                               if (!write_batch)
+                                       compat_flags |= CF_VARINT_FLIST_FLAGS;
+                               write_byte(f_out, compat_flags);
+                       } else
+                               write_varint(f_out, compat_flags);
+               } else { /* read_varint() is compatible with the older write_byte() when the 0x80 bit isn't on. */
+                       compat_flags = read_varint(f_in);
+                       if  (compat_flags & CF_VARINT_FLIST_FLAGS)
+                               csum_exchange = 1;
+               }
                /* The inc_recurse var MUST be set to 0 or 1. */
                inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0;
                want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM);
                proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0;
+               xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0;
                if (am_sender) {
                        receiver_symlink_times = am_server
                            ? strchr(client_info, 'L') != NULL
@@ -313,6 +339,8 @@ void setup_protocol(int f_out,int f_in)
                }
                use_safe_inc_flist = (compat_flags & CF_SAFE_FLIST) || protocol_version >= 31;
                need_messages_from_generator = 1;
+               if (compat_flags & CF_INPLACE_PARTIAL_DIR)
+                       inplace_partial = 1;
 #ifdef CAN_SET_SYMLINK_TIMES
        } else if (!am_sender) {
                receiver_symlink_times = 1;
@@ -339,6 +367,17 @@ void setup_protocol(int f_out,int f_in)
        }
 #endif
 
+       if (!checksum_choice) {
+               const char *rcl = getenv("RSYNC_CHECKSUM_LIST");
+               int saw_fail = rcl && strstr(rcl, "FAIL");
+               if (csum_exchange)
+                       negotiate_checksum(f_in, f_out, rcl, saw_fail);
+               else if (!am_server && saw_fail) {
+                       rprintf(FERROR, "Remote rsync is too old for checksum negotation\n");
+                       exit_cleanup(RERR_UNSUPPORTED);
+               }
+       }
+
        if (am_server) {
                if (!checksum_seed)
                        checksum_seed = time(NULL) ^ (getpid() << 6);
@@ -349,3 +388,10 @@ void setup_protocol(int f_out,int f_in)
 
        init_flist();
 }
+
+void maybe_write_checksum(int batch_fd)
+{
+       assert(negotiated_csum_name != NULL);
+       if (compat_flags & CF_VARINT_FLIST_FLAGS)
+               write_vstring(batch_fd, negotiated_csum_name, strlen(negotiated_csum_name));
+}