Improved the %C (checksum) escape to work for all files when the
[rsync-patches.git] / log-checksum.diff
index 1eac37fd8d3f742ab2c01eff1e498fb997dd22fb..3d36e5270e59902194527453267310fa6cdbe442 100644 (file)
@@ -6,54 +6,163 @@ compute them.
 
 -- Matt McCutchen <hashproduct@gmail.com>
 
+To use this patch, run these commands for a successful build:
+
+    patch -p1 <patches/log-checksum.diff
+    ./configure                                 (optional if already run)
+    make
+
+diff --git a/flist.c b/flist.c
+--- a/flist.c
++++ b/flist.c
+@@ -67,6 +67,7 @@ extern int protocol_version;
+ extern int sanitize_paths;
+ extern int munge_symlinks;
+ extern int need_unsorted_flist;
++extern int sender_keeps_checksum;
+ extern int unsort_ndx;
+ extern struct stats stats;
+ extern char *filesfrom_host;
+@@ -1187,6 +1188,12 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+               extra_len += EXTRA_LEN;
+ #endif
++      if (always_checksum && am_sender && S_ISREG(st.st_mode)) {
++              file_checksum(thisname, tmp_sum, st.st_size);
++              if (sender_keeps_checksum)
++                      extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
++      }
++
+ #if EXTRA_ROUNDING > 0
+       if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN))
+               extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN;
+@@ -1250,9 +1257,6 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+               memcpy(bp + basename_len, linkname, linkname_len);
+ #endif
+-      if (always_checksum && am_sender && S_ISREG(st.st_mode))
+-              file_checksum(thisname, tmp_sum, st.st_size);
+-
+       if (am_sender)
+               F_PATHNAME(file) = pathname;
+       else if (!pool)
+@@ -1283,6 +1287,9 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
+               return NULL;
+       }
++      if (sender_keeps_checksum && S_ISREG(st.st_mode))
++              memcpy(F_SUM(file), tmp_sum, checksum_len);
++
+       if (unsort_ndx)
+               F_NDX(file) = dir_count;
 diff --git a/log.c b/log.c
 --- a/log.c
 +++ b/log.c
-@@ -58,6 +58,9 @@ extern char curr_dir[];
+@@ -32,8 +32,10 @@ extern int local_server;
+ extern int quiet;
+ extern int module_id;
+ extern int msg_fd_out;
++extern int checksum_len;
+ extern int allow_8bit_chars;
+ extern int protocol_version;
++extern int always_checksum;
+ extern int preserve_times;
+ extern int uid_ndx;
+ extern int gid_ndx;
+@@ -57,6 +59,7 @@ extern iconv_t ic_send, ic_recv;
+ extern char curr_dir[];
  extern char *module_dir;
  extern unsigned int module_dirlen;
 +extern char sender_file_sum[MAX_DIGEST_LEN];
-+extern int file_sum_len;
-+
  static int log_initialised;
  static int logfile_was_closed;
- static FILE *logfile_fp;
-@@ -628,6 +631,19 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
+@@ -628,6 +631,28 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
                        snprintf(buf2, sizeof buf2, fmt, (double)b);
                        n = buf2;
                        break;
 +              case 'C':
-+                      if (iflags & ITEM_TRANSFER && protocol_version >= 30) {
-+                              int i;
-+                              for (i = 0; i < file_sum_len; i++)
-+                                      snprintf(buf2 + i*2, 3, "%02x", (int)CVAL(sender_file_sum,i));
++                      if (protocol_version >= 30
++                       && (iflags & ITEM_TRANSFER
++                        || (always_checksum && S_ISREG(file->mode)))) {
++                              int i, x1, x2;
++                              const char *sum = iflags & ITEM_TRANSFER
++                                              ? sender_file_sum : F_SUM(file);
++                              c = buf2 + checksum_len*2;
++                              *c = '\0';
++                              for (i = checksum_len; --i >= 0; ) {
++                                      x1 = CVAL(sum, i);
++                                      x2 = x1 >> 4;
++                                      x1 &= 0xF;
++                                      *--c = x1 <= 9 ? x1 + '0' : x1 + 'a' - 10;
++                                      *--c = x2 <= 9 ? x2 + '0' : x2 + 'a' - 10;
++                              }
 +                      } else {
-+                              int i;
-+                              for (i = 0; i < file_sum_len*2; i++)
-+                                      buf2[i] = '?';
-+                              buf2[i] = '\0';
++                              memset(buf2, ' ', checksum_len*2);
++                              buf2[checksum_len*2] = '\0';
 +                      }
 +                      n = buf2;
 +                      break;
                case 'i':
                        if (iflags & ITEM_DELETED) {
                                n = "*deleting  ";
+diff --git a/main.c b/main.c
+--- a/main.c
++++ b/main.c
+@@ -37,6 +37,7 @@ extern int am_generator;
+ extern int am_daemon;
+ extern int inc_recurse;
+ extern int blocking_io;
++extern int always_checksum;
+ extern int remove_source_files;
+ extern int need_messages_from_generator;
+ extern int kluge_around_eof;
+@@ -68,6 +69,8 @@ extern int connect_timeout;
+ extern pid_t cleanup_child_pid;
+ extern unsigned int module_dirlen;
+ extern struct stats stats;
++extern char *stdout_format;
++extern char *logfile_format;
+ extern char *filesfrom_host;
+ extern char *partial_dir;
+ extern char *dest_option;
+@@ -85,6 +88,7 @@ int local_server = 0;
+ int daemon_over_rsh = 0;
+ mode_t orig_umask = 0;
+ int batch_gen_fd = -1;
++int sender_keeps_checksum = 0;
+ /* There's probably never more than at most 2 outstanding child processes,
+  * but set it higher, just in case. */
+@@ -1003,6 +1007,12 @@ int client_run(int f_in, int f_out, pid_t pid, int argc, char *argv[])
+       if (am_sender) {
+               keep_dirlinks = 0; /* Must be disabled on the sender. */
++
++              if (always_checksum
++               && (log_format_has(stdout_format, 'C')
++                || log_format_has(logfile_format, 'C')))
++                      sender_keeps_checksum = 1;
++
+               if (protocol_version >= 30)
+                       io_start_multiplex_out();
+               else
 diff --git a/match.c b/match.c
 --- a/match.c
 +++ b/match.c
-@@ -312,6 +312,10 @@ static void hash_search(int f,struct sum_struct *s,
-       map_ptr(buf, len-1, 1);
- }
+@@ -25,8 +25,10 @@ extern int verbose;
+ extern int do_progress;
+ extern int checksum_seed;
+ extern int append_mode;
++extern int checksum_len;
  
-+/* Global variables to make the sender's checksum of a transferred file
-+ * available to the code for log escape %C. */
+ int updating_basis_file;
 +char sender_file_sum[MAX_DIGEST_LEN];
-+int file_sum_len = MD5_DIGEST_LEN;
  
- /**
-  * Scan through a origin file, looking for sections that match
-@@ -329,9 +333,6 @@ static void hash_search(int f,struct sum_struct *s,
+ static int false_alarms;
+ static int hash_hits;
+@@ -329,9 +331,6 @@ static void hash_search(int f,struct sum_struct *s,
   **/
  void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
  {
@@ -63,7 +172,7 @@ diff --git a/match.c b/match.c
        last_match = 0;
        false_alarms = 0;
        hash_hits = 0;
-@@ -379,14 +380,26 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
+@@ -379,18 +378,28 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len)
                matched(f, s, buf, len, -1);
        }
  
@@ -71,30 +180,33 @@ diff --git a/match.c b/match.c
 -      /* If we had a read error, send a bad checksum. */
 -      if (buf && buf->status != 0)
 -              file_sum[0]++;
-+      file_sum_len = sum_end(sender_file_sum);
++      if (sum_end(sender_file_sum) != checksum_len)
++              overflow_exit("checksum_len"); /* Impossible... */
 +
 +      /* If we had a read error, send a bad checksum.  We use all bits
-+       * off or all bits on so that a user logging checksums with %C
-+       * can recognize a bad checksum. */
++       * off as long as the checksum doesn't happen to be that, in
++       * which case we turn the last 0 bit into a 1. */
 +      if (buf && buf->status != 0) {
 +              int i;
-+              for (i = 0; i < file_sum_len; i++) {
-+                      if (sender_file_sum[i])
-+                              break;
-+              }
-+              if (i < file_sum_len)
-+                      memset(sender_file_sum, 0, file_sum_len);
-+              else
-+                      memset(sender_file_sum, 0xFF, file_sum_len);
++              for (i = 0; i < checksum_len && sender_file_sum[i] == 0; i++) {}
++              memset(sender_file_sum, 0, checksum_len);
++              if (i == checksum_len)
++                      sender_file_sum[i-1]++;
 +      }
  
        if (verbose > 2)
                rprintf(FINFO,"sending file_sum\n");
 -      write_buf(f, file_sum, sum_len);
-+      write_buf(f, sender_file_sum, file_sum_len);
++      write_buf(f, sender_file_sum, checksum_len);
  
-       if (verbose > 2)
+-      if (verbose > 2)
++      if (verbose > 2) {
                rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
+                       false_alarms, hash_hits, matches);
++      }
+       total_hash_hits += hash_hits;
+       total_false_alarms += false_alarms;
 diff --git a/options.c b/options.c
 --- a/options.c
 +++ b/options.c
@@ -111,17 +223,23 @@ diff --git a/options.c b/options.c
 diff --git a/receiver.c b/receiver.c
 --- a/receiver.c
 +++ b/receiver.c
-@@ -62,6 +62,9 @@ static int phase = 0, redoing = 0;
- /* We're either updating the basis file or an identical copy: */
- static int updating_basis_or_equiv;
+@@ -46,6 +46,7 @@ extern int remove_source_files;
+ extern int append_mode;
+ extern int sparse_files;
+ extern int keep_partial;
++extern int checksum_len;
+ extern int checksum_seed;
+ extern int inplace;
+ extern int delay_updates;
+@@ -54,6 +55,7 @@ extern struct stats stats;
+ extern char *tmpdir;
+ extern char *partial_dir;
+ extern char *basis_dir[];
 +extern char sender_file_sum[MAX_DIGEST_LEN];
-+extern int file_sum_len;
-+
- /*
-  * get_tmpname() - create a tmp filename for a given filename
-  *
-@@ -165,10 +168,9 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
+ extern struct file_list *cur_flist, *first_flist, *dir_flist;
+ extern struct filter_list_struct daemon_filter_list;
+@@ -165,10 +167,9 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                        const char *fname, int fd, OFF_T total_size)
  {
        static char file_sum1[MAX_DIGEST_LEN];
@@ -133,22 +251,23 @@ diff --git a/receiver.c b/receiver.c
        OFF_T offset = 0;
        OFF_T offset2;
        char *data;
-@@ -298,15 +300,15 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
+@@ -298,15 +299,16 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r,
                exit_cleanup(RERR_FILEIO);
        }
  
 -      sum_len = sum_end(file_sum1);
-+      file_sum_len = sum_end(file_sum1);
++      if (sum_end(file_sum1) != checksum_len)
++              overflow_exit("checksum_len"); /* Impossible... */
  
        if (mapbuf)
                unmap_file(mapbuf);
  
 -      read_buf(f_in, file_sum2, sum_len);
-+      read_buf(f_in, sender_file_sum, file_sum_len);
++      read_buf(f_in, sender_file_sum, checksum_len);
        if (verbose > 2)
                rprintf(FINFO,"got file_sum\n");
 -      if (fd != -1 && memcmp(file_sum1, file_sum2, sum_len) != 0)
-+      if (fd != -1 && memcmp(file_sum1, sender_file_sum, file_sum_len) != 0)
++      if (fd != -1 && memcmp(file_sum1, sender_file_sum, checksum_len) != 0)
                return 0;
        return 1;
  }
@@ -173,7 +292,7 @@ diff --git a/rsyncd.conf.yo b/rsyncd.conf.yo
    it() %B the permission bits of the file (e.g. rwxrwxrwt)
 -  it() %c the checksum bytes received for this file (only when sending)
 +  it() %c the total size of the block checksums received for the basis file (only when sending)
-+  it() %C the full-file MD5 checksum of a transferred file (only for protocol 30 or above).
++  it() %C the full-file MD5 checksum if bf(--checksum) is enabled or a file was transferred (only for protocol 30 or above).
    it() %f the filename (long form on sender; no trailing "/")
    it() %G the gid of the file (decimal) or "DEFAULT"
    it() %h the remote host name