My version of Matt's improvements related to missing source args:
[rsync/rsync.git] / generator.c
index ed3db57..a9f9306 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1996-2000 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras
  * Copyright (C) 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2008 Wayne Davison
+ * Copyright (C) 2003-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
@@ -50,6 +50,7 @@ extern int delete_mode;
 extern int delete_before;
 extern int delete_during;
 extern int delete_after;
+extern int missing_args;
 extern int msgdone_cnt;
 extern int ignore_errors;
 extern int remove_source_files;
@@ -97,7 +98,7 @@ extern char *backup_dir;
 extern char *backup_suffix;
 extern int backup_suffix_len;
 extern struct file_list *cur_flist, *first_flist, *dir_flist;
-extern struct filter_list_struct daemon_filter_list;
+extern struct filter_list_struct filter_list, daemon_filter_list;
 
 int ignore_perishable = 0;
 int non_perishable_cnt = 0;
@@ -108,7 +109,7 @@ static int deletion_count = 0; /* used to implement --max-delete */
 static int deldelay_size = 0, deldelay_cnt = 0;
 static char *deldelay_buf = NULL;
 static int deldelay_fd = -1;
-static int lull_mod;
+static int loopchk_limit;
 static int dir_tweaking;
 static int symlink_timeset_failed_flags;
 static int need_retouch_dir_times;
@@ -521,7 +522,10 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev)
                                        f_name(fp, NULL));
                        continue;
                }
-               if (flist_find(cur_flist, fp) < 0) {
+               /* Here we want to match regardless of file type.  Replacement
+                * of a file with one of another type is handled separately by
+                * a delete_item call with a DEL_MAKE_ROOM flag. */
+               if (flist_find_ignore_dirness(cur_flist, fp) < 0) {
                        int flags = DEL_RECURSE;
                        if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid)
                                flags |= DEL_NO_UID_WRITE;
@@ -697,8 +701,11 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
                        if (iflags & ITEM_XNAME_FOLLOWS)
                                write_vstring(sock_f_out, xname, strlen(xname));
 #ifdef SUPPORT_XATTRS
-                       if (iflags & ITEM_REPORT_XATTR && !dry_run)
-                               send_xattr_request(NULL, file, sock_f_out);
+                       if (preserve_xattrs && do_xfers
+                        && iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) {
+                               send_xattr_request(NULL, file,
+                                       iflags & ITEM_REPORT_XATTR ? sock_f_out : -1);
+                       }
 #endif
                } else if (ndx >= 0) {
                        enum logcode code = logfile_format_has_i ? FINFO : FCLIENT;
@@ -753,18 +760,19 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
 {
        int32 blength;
        int s2length;
+       int64 l;
 
        if (block_size)
                blength = block_size;
        else if (len <= BLOCK_SIZE * BLOCK_SIZE)
                blength = BLOCK_SIZE;
        else {
+               int32 max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE;
                int32 c;
-               int64 l;
                int cnt;
                for (c = 1, l = len, cnt = 0; l >>= 2; c <<= 1, cnt++) {}
-               if (cnt >= 31 || c >= MAX_BLOCK_SIZE)
-                       blength = MAX_BLOCK_SIZE;
+               if (c < 0 || c >= max_blength)
+                       blength = max_blength;
                else {
                    blength = 0;
                    do {
@@ -783,7 +791,6 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
                s2length = SUM_LENGTH;
        } else {
                int32 c;
-               int64 l;
                int b = BLOCKSUM_BIAS;
                for (l = len; l >>= 1; b += 2) {}
                for (c = blength; (c >>= 1) && b; b--) {}
@@ -797,7 +804,10 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
        sum->blength    = blength;
        sum->s2length   = s2length;
        sum->remainder  = (int32)(len % blength);
-       sum->count      = (int32)(len / blength) + (sum->remainder != 0);
+       sum->count      = (int32)(l = (len / blength) + (sum->remainder != 0));
+
+       if ((int64)sum->count != l)
+               sum->count = -1;
 
        if (sum->count && verbose > 2) {
                rprintf(FINFO,
@@ -813,7 +823,7 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len)
  *
  * Generate approximately one checksum every block_len bytes.
  */
-static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
+static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
 {
        int32 i;
        struct map_struct *mapbuf;
@@ -821,10 +831,12 @@ static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
        OFF_T offset = 0;
 
        sum_sizes_sqroot(&sum, len);
+       if (sum.count < 0)
+               return -1;
        write_sum_head(f_out, &sum);
 
        if (append_mode > 0 && f_copy < 0)
-               return;
+               return 0;
 
        if (len > 0)
                mapbuf = map_file(fd, len, MAX_MAP_SIZE, sum.blength);
@@ -861,6 +873,8 @@ static void generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy)
 
        if (mapbuf)
                unmap_file(mapbuf);
+
+       return 0;
 }
 
 
@@ -922,6 +936,7 @@ static int copy_altdest_file(const char *src, const char *dest, struct file_stru
 {
        char buf[MAXPATHLEN];
        const char *copy_to, *partialptr;
+       int save_preserve_xattrs = preserve_xattrs;
        int ok, fd_w;
 
        if (inplace) {
@@ -946,7 +961,9 @@ static int copy_altdest_file(const char *src, const char *dest, struct file_stru
                return -1;
        }
        partialptr = partial_dir ? partial_dir_fname(dest) : NULL;
+       preserve_xattrs = 0; /* xattrs were copied with file */
        ok = finish_transfer(dest, copy_to, src, partialptr, file, 1, 0);
+       preserve_xattrs = save_preserve_xattrs;
        cleanup_disable();
        return ok ? 0 : -1;
 }
@@ -1108,8 +1125,8 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
                }
                switch (type) {
                case TYPE_DIR:
-                       break;
                case TYPE_SPECIAL:
+                       break;
                case TYPE_DEVICE:
                        devp = F_RDEV_P(file);
                        if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
@@ -1206,7 +1223,11 @@ static void list_file_entry(struct file_struct *f)
                        f_name(f, NULL), F_SYMLINK(f));
        } else
 #endif
-       {
+       if (missing_args == 2 && f->mode == 0) {
+               rprintf(FINFO, "%-*s %s\n",
+                       /*colwidth*/11 + 31, "*missing",
+                       f_name(f, NULL));
+       } else {
                rprintf(FINFO, "%s %11.0f %s %s\n",
                        permbuf, len, timestring(f->modtime),
                        f_name(f, NULL));
@@ -1353,6 +1374,14 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                stat_errno = errno;
        }
 
+       if (missing_args == 2 && file->mode == 0) {
+               if (filter_list.head && check_filter(&filter_list, FINFO, fname, is_dir) < 0)
+                       return;
+               if (statret == 0)
+                       delete_item(fname, sx.st.st_mode, del_opts);
+               return;
+       }
+
        if (ignore_non_existing > 0 && statret == -1 && stat_errno == ENOENT) {
                if (is_dir) {
                        if (is_dir < 0)
@@ -1432,6 +1461,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        if (j == -2) {
                                itemizing = 0;
                                code = FNONE;
+                               statret = 1;
                        } else if (j >= 0)
                                statret = 1;
                }
@@ -1454,6 +1484,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                                goto cleanup;
                        }
                }
+#ifdef SUPPORT_XATTRS
+               if (preserve_xattrs && statret == 1)
+                       copy_xattrs(fnamecmpbuf, fname);
+#endif
                if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0)
                    && verbose && code != FNONE && f_out != -1)
                        rprintf(code, "%s/\n", fname);
@@ -1592,8 +1626,12 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 
        if ((am_root && preserve_devices && IS_DEVICE(file->mode))
         || (preserve_specials && IS_SPECIAL(file->mode))) {
-               uint32 *devp = F_RDEV_P(file);
-               dev_t rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
+               dev_t rdev;
+               if (IS_DEVICE(file->mode)) {
+                       uint32 *devp = F_RDEV_P(file);
+                       rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
+               } else
+                       rdev = 0;
                if (statret == 0) {
                        int del_for_flag;
                        if (IS_DEVICE(file->mode)) {
@@ -1607,7 +1645,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        }
                        if (statret == 0
                         && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT)
-                        && sx.st.st_rdev == rdev) {
+                        && (IS_SPECIAL(sx.st.st_mode) || sx.st.st_rdev == rdev)) {
                                /* The device or special file is identical. */
                                set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT);
                                if (itemizing)
@@ -1868,15 +1906,21 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
                        close(fd);
                        goto cleanup;
                }
-               if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0
-                && (errno != ENOENT || make_bak_dir(backupptr) < 0
-                 || (f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0)) {
-                       rsyserr(FERROR_XFER, errno, "open %s",
-                               full_fname(backupptr));
-                       unmake_file(back_file);
-                       back_file = NULL;
-                       close(fd);
-                       goto cleanup;
+               if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
+                       int save_errno = errno ? errno : EINVAL; /* 0 paranoia */
+                       if (errno == ENOENT && make_bak_dir(backupptr) == 0) {
+                               if ((f_copy = do_open(backupptr, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0)
+                                       save_errno = errno ? errno : save_errno;
+                               else
+                                       save_errno = 0;
+                       }
+                       if (save_errno) {
+                               rsyserr(FERROR_XFER, save_errno, "open %s", full_fname(backupptr));
+                               unmake_file(back_file);
+                               back_file = NULL;
+                               close(fd);
+                               goto cleanup;
+                       }
                }
                fnamecmp_type = FNAMECMP_BACKUP;
        }
@@ -1931,16 +1975,32 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx,
 
        if (statret != 0 || whole_file)
                write_sum_head(f_out, NULL);
-       else {
-               generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy);
+       else if (sx.st.st_size <= 0) {
+               write_sum_head(f_out, NULL);
+               close(fd);
+       } else {
+               if (generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy) < 0) {
+                       rprintf(FWARNING,
+                           "WARNING: file is too large for checksum sending: %s\n",
+                           fnamecmp);
+                       write_sum_head(f_out, NULL);
+               }
                close(fd);
        }
 
   cleanup:
        if (back_file) {
+               int save_preserve_xattrs = preserve_xattrs;
                if (f_copy >= 0)
                        close(f_copy);
+#ifdef SUPPORT_XATTRS
+               if (preserve_xattrs) {
+                       copy_xattrs(fname, backupptr);
+                       preserve_xattrs = 0;
+               }
+#endif
                set_file_attrs(backupptr, back_file, NULL, NULL, 0);
+               preserve_xattrs = save_preserve_xattrs;
                if (verbose > 1) {
                        rprintf(FINFO, "backed up %s to %s\n",
                                fname, backupptr);
@@ -2018,10 +2078,13 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
                         && cmp_time(st.st_mtime, file->modtime) != 0)
                                set_modtime(fname, file->modtime, file->mode);
                }
-               if (allowed_lull && !(counter % lull_mod))
-                       maybe_send_keepalive();
-               else if (!(counter & 0xFF))
-                       maybe_flush_socket(0);
+               if (counter >= loopchk_limit) {
+                       if (allowed_lull)
+                               maybe_send_keepalive();
+                       else
+                               maybe_flush_socket(0);
+                       counter = 0;
+               }
        }
 }
 
@@ -2035,8 +2098,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
        while (1) {
 #ifdef SUPPORT_HARD_LINKS
                if (preserve_hard_links && (ndx = get_hlink_num()) != -1) {
-                       flist = flist_for_ndx(ndx);
-                       assert(flist != NULL);
+                       flist = flist_for_ndx(ndx, "check_for_finished_files.1");
                        file = flist->files[ndx - flist->ndx_start];
                        assert(file->flags & FLAG_HLINKED);
                        finish_hard_link(file, f_name(file, fbuf), ndx, NULL, itemizing, code, -1);
@@ -2059,7 +2121,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
                        ignore_times++;
 
                        flist = cur_flist;
-                       cur_flist = flist_for_ndx(ndx);
+                       cur_flist = flist_for_ndx(ndx, "check_for_finished_files.2");
 
                        file = cur_flist->files[ndx - cur_flist->ndx_start];
                        if (solo_file)
@@ -2092,10 +2154,9 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
                if (first_flist->in_progress || first_flist->to_redo)
                        break;
 
-               if (!read_batch) {
-                       write_ndx(sock_f_out, NDX_DONE);
+               write_ndx(sock_f_out, NDX_DONE);
+               if (!read_batch)
                        maybe_flush_socket(1);
-               }
 
                if (delete_during == 2 || !dir_tweaking) {
                        /* Skip directory touch-up. */
@@ -2108,7 +2169,7 @@ void check_for_finished_files(int itemizing, enum logcode code, int check_redo)
 
 void generate_files(int f_out, const char *local_name)
 {
-       int i, ndx;
+       int i, ndx, next_loopchk = 0;
        char fbuf[MAXPATHLEN];
        int itemizing;
        enum logcode code;
@@ -2134,7 +2195,7 @@ void generate_files(int f_out, const char *local_name)
        solo_file = local_name;
        dir_tweaking = !(list_only || solo_file || dry_run);
        need_retouch_dir_times = preserve_times > 1;
-       lull_mod = allowed_lull * 5;
+       loopchk_limit = allowed_lull ? allowed_lull * 5 : 200;
        symlink_timeset_failed_flags = ITEM_REPORT_TIME
            | (protocol_version >= 30 || !am_server ? ITEM_REPORT_TIMEFAIL : 0);
        implied_dirs_are_missing = relative_paths && !implied_dirs && protocol_version < 30;
@@ -2179,7 +2240,10 @@ void generate_files(int f_out, const char *local_name)
 
                if (inc_recurse && cur_flist->parent_ndx >= 0) {
                        struct file_struct *fp = dir_flist->files[cur_flist->parent_ndx];
-                       f_name(fp, fbuf);
+                       if (solo_file)
+                               strlcpy(fbuf, solo_file, sizeof fbuf);
+                       else
+                               f_name(fp, fbuf);
                        ndx = cur_flist->ndx_start - 1;
                        recv_generator(fbuf, fp, ndx, itemizing, code, f_out);
                        if (delete_during && dry_run < 2 && !list_only
@@ -2215,10 +2279,13 @@ void generate_files(int f_out, const char *local_name)
 
                        check_for_finished_files(itemizing, code, 0);
 
-                       if (allowed_lull && !(i % lull_mod))
-                               maybe_send_keepalive();
-                       else if (!(i & 0xFF))
-                               maybe_flush_socket(0);
+                       if (i + cur_flist->ndx_start >= next_loopchk) {
+                               if (allowed_lull)
+                                       maybe_send_keepalive();
+                               else
+                                       maybe_flush_socket(0);
+                               next_loopchk += loopchk_limit;
+                       }
                }
 
                if (!inc_recurse) {
@@ -2286,7 +2353,7 @@ void generate_files(int f_out, const char *local_name)
                touch_up_dirs(dir_flist, -1);
 
        if (max_delete >= 0 && deletion_count > max_delete) {
-               rprintf(FINFO,
+               rprintf(FWARNING,
                        "Deletions stopped due to --max-delete limit (%d skipped)\n",
                        deletion_count - max_delete);
                io_error |= IOERR_DEL_LIMIT;