A slightly better reset mechanism for send_file_entry() and
[rsync/rsync.git] / flist.c
diff --git a/flist.c b/flist.c
index 46079d9..0601901 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -70,6 +70,7 @@ extern struct exclude_struct **local_exclude_list;
 int io_error;
 
 static struct file_struct null_file;
+static char empty_sum[MD4_SUM_LENGTH];
 
 static void clean_flist(struct file_list *flist, int strip_root, int no_dups);
 
@@ -350,17 +351,15 @@ static void flist_expand(struct file_list *flist)
        }
 }
 
-
-static void send_file_entry(struct file_struct *file, int f,
-                           unsigned short base_flags)
+void send_file_entry(struct file_struct *file, int f, unsigned short base_flags)
 {
        unsigned short flags;
        static time_t modtime;
        static mode_t mode;
-       static DEV64_T rdev;    /* just high bytes after p28 */
+       static DEV64_T rdev;    /* just high bytes in p28 onward */
+       static DEV64_T dev;
        static uid_t uid;
        static gid_t gid;
-       static DEV64_T dev;
        static char lastname[MAXPATHLEN];
        char *fname, fbuf[MAXPATHLEN];
        int l1, l2;
@@ -370,6 +369,10 @@ static void send_file_entry(struct file_struct *file, int f,
 
        if (!file) {
                write_byte(f, 0);
+               modtime = 0, mode = 0;
+               rdev = 0, dev = 0;
+               uid = 0, gid = 0;
+               *lastname = '\0';
                return;
        }
 
@@ -470,7 +473,8 @@ static void send_file_entry(struct file_struct *file, int f,
                write_int(f, gid);
        }
        if (preserve_devices && IS_DEVICE(mode)) {
-               /* If SAME_HIGH_RDEV is off, SAME_RDEV_pre28 is also off. */
+               /* If SAME_HIGH_RDEV is off, SAME_RDEV_pre28 is also off.
+                * Also, avoid using "rdev" because it may be incomplete. */
                if (!(flags & SAME_HIGH_RDEV))
                        write_int(f, file->rdev);
                else if (protocol_version >= 28)
@@ -499,11 +503,10 @@ static void send_file_entry(struct file_struct *file, int f,
        }
 #endif
 
-       if (always_checksum) {
-               if (protocol_version < 21)
-                       write_buf(f, file->sum, 2);
-               else
-                       write_buf(f, file->sum, MD4_SUM_LENGTH);
+       if (always_checksum && (protocol_version < 28 || S_ISREG(mode))) {
+               char *sum = file->sum? file->sum : empty_sum;
+               write_buf(f, sum, protocol_version < 21? 2
+                                               : MD4_SUM_LENGTH);
        }
 
        strlcpy(lastname, fname, MAXPATHLEN);
@@ -514,21 +517,28 @@ static void send_file_entry(struct file_struct *file, int f,
 
 
 
-static void receive_file_entry(struct file_struct **fptr,
-                              unsigned short flags, int f)
+void receive_file_entry(struct file_struct **fptr, unsigned short flags, int f)
 {
        static time_t modtime;
        static mode_t mode;
-       static DEV64_T rdev;    /* just high bytes after p28 */
+       static DEV64_T rdev;    /* just high bytes in p28 onward */
+       static DEV64_T dev;
        static uid_t uid;
        static gid_t gid;
-       static DEV64_T dev;
        static char lastname[MAXPATHLEN];
        char thisname[MAXPATHLEN];
        unsigned int l1 = 0, l2 = 0;
        char *p;
        struct file_struct *file;
 
+       if (!fptr) {
+               modtime = 0, mode = 0;
+               rdev = 0, dev = 0;
+               uid = 0, gid = 0;
+               *lastname = '\0';
+               return;
+       }
+
        if (flags & SAME_NAME)
                l1 = read_byte(f);
 
@@ -648,19 +658,26 @@ static void receive_file_entry(struct file_struct **fptr,
 #endif
 
        if (always_checksum) {
-               file->sum = new_array(char, MD4_SUM_LENGTH);
-               if (!file->sum)
-                       out_of_memory("md4 sum");
-               if (protocol_version < 21)
-                       read_buf(f, file->sum, 2);
-               else
-                       read_buf(f, file->sum, MD4_SUM_LENGTH);
+               char *sum;
+               if (S_ISREG(mode)) {
+                       sum = file->sum = new_array(char, MD4_SUM_LENGTH);
+                       if (!sum)
+                               out_of_memory("md4 sum");
+               } else if (protocol_version < 28) {
+                       /* Prior to 28, we get a useless set of nulls. */
+                       sum = empty_sum;
+               } else
+                       sum = NULL;
+               if (sum) {
+                       read_buf(f, sum, protocol_version < 21? 2
+                                               : MD4_SUM_LENGTH);
+               }
        }
 
        if (!preserve_perms) {
                extern int orig_umask;
                /* set an appropriate set of permissions based on original
-                  permissions and umask. This emulates what GNU cp does */
+                * permissions and umask. This emulates what GNU cp does */
                file->mode &= ~orig_umask;
        }
 }
@@ -816,18 +833,11 @@ struct file_struct *make_file(char *fname, struct string_area **ap,
                file->link = STRDUP(ap, linkbuf);
 #endif
 
-       if (always_checksum) {
-               file->sum = (char *) MALLOC(ap, MD4_SUM_LENGTH);
+       if (always_checksum && S_ISREG(st.st_mode)) {
+               file->sum = (char*)MALLOC(ap, MD4_SUM_LENGTH);
                if (!file->sum)
                        out_of_memory("md4 sum");
-               /* drat. we have to provide a null checksum for non-regular
-                  files in order to be compatible with earlier versions
-                  of rsync */
-               if (S_ISREG(st.st_mode)) {
-                       file_checksum(fname, file->sum, st.st_size);
-               } else {
-                       memset(file->sum, 0, MD4_SUM_LENGTH);
-               }
+               file_checksum(fname, file->sum, st.st_size);
        }
 
        if (flist_dir) {
@@ -1183,7 +1193,7 @@ struct file_list *recv_file_list(int f)
                                f_name(flist->files[i]));
                }
        }
-
+       receive_file_entry(NULL, 0, 0); /* Signal that we're done. */
 
        if (verbose > 2)
                rprintf(FINFO, "received %d names\n", flist->count);