X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/022dec7aba633f8b4e40339d555cc7cae5399314..cc12c488aa71e66f4786fd60494d24e81e425868:/generator.c diff --git a/generator.c b/generator.c index e189dddd..c06ea0db 100644 --- a/generator.c +++ b/generator.c @@ -135,8 +135,12 @@ enum delret { DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_NOT_EMPTY }; -/* Forward declaration for delete_item(). */ +/* Forward declarations. */ static enum delret delete_dir_contents(char *fname, uint16 flags); +#ifdef SUPPORT_HARD_LINKS +static void handle_skipped_hlink(struct file_struct *file, int itemizing, + enum logcode code, int f_out); +#endif static int is_backup_file(char *fn) { @@ -279,7 +283,7 @@ static enum delret delete_dir_contents(char *fname, uint16 flags) for (j = dirlist->used; j--; ) { struct file_struct *fp = dirlist->files[j]; - if (fp->flags & FLAG_MOUNT_DIR) { + if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { if (verbose > 1) { rprintf(FINFO, "mount point, %s, pins parent directory\n", @@ -511,7 +515,7 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev) struct file_struct *fp = dirlist->files[i]; if (!F_IS_ACTIVE(fp)) continue; - if (fp->flags & FLAG_MOUNT_DIR) { + if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { if (verbose > 1) rprintf(FINFO, "cannot delete mount point: %s\n", f_name(fp, NULL)); @@ -1215,16 +1219,17 @@ static int dflt_perms; * regular files that have changed, we try to find a basis file and then * start sending checksums. The ndx is the file's unique index value. * - * When fname is non-null, it must point to a MAXPATHLEN buffer! + * The fname parameter must point to a MAXPATHLEN buffer! (e.g it gets + * passed to delete_item(), which can use it during a recursive delete.) * * Note that f_out is set to -1 when doing final directory-permission and * modification-time repair. */ static void recv_generator(char *fname, struct file_struct *file, int ndx, int itemizing, enum logcode code, int f_out) { - static int missing_below = -1, excluded_below = -1; + static int missing_below = -1; static const char *parent_dirname = ""; - static struct file_struct *missing_dir = NULL, *excluded_dir = NULL; + static struct file_struct *missing_dir = NULL; static struct file_list *fuzzy_dirlist = NULL; static int need_fuzzy_dirlist = 0; struct file_struct *fuzzy_file = NULL; @@ -1253,29 +1258,6 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, return; } - if (server_filter_list.head) { - int filtered = check_filter(&server_filter_list, fname, is_dir) < 0; - if (is_dir < 0 && filtered) - return; - if (excluded_below >= 0) { - if (F_DEPTH(file) > excluded_below - && (!implied_dirs_are_missing || f_name_has_prefix(file, excluded_dir))) - goto skipping; - excluded_below = -1; - } - if (filtered) { - if (is_dir) { - excluded_below = F_DEPTH(file); - excluded_dir = file; - } - skipping: - rprintf(FERROR_XFER, - "skipping daemon-excluded file \"%s\"\n", - fname); - return; - } - } - if (missing_below >= 0) { if (F_DEPTH(file) <= missing_below || (implied_dirs_are_missing && !f_name_has_prefix(file, missing_dir))) { @@ -1285,9 +1267,31 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, } else if (!dry_run) { if (is_dir) file->flags |= FLAG_MISSING_DIR; +#ifdef SUPPORT_HARD_LINKS + if (F_IS_HLINKED(file)) + handle_skipped_hlink(file, itemizing, code, f_out); +#endif + return; + } + } + + if (server_filter_list.head) { + if (check_filter(&server_filter_list, fname, is_dir) < 0) { + if (is_dir < 0) + return; +#ifdef SUPPORT_HARD_LINKS + if (F_IS_HLINKED(file)) + handle_skipped_hlink(file, itemizing, code, f_out); +#endif + rprintf(FERROR_XFER, + "skipping daemon-excluded %s \"%s\"\n", + is_dir ? "directory" : "file", fname); + if (is_dir) + goto skipping_dir_contents; return; } } + #ifdef SUPPORT_ACLS sx.acc_acl = sx.def_acl = NULL; #endif @@ -1347,6 +1351,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, } file->flags |= FLAG_MISSING_DIR; } +#ifdef SUPPORT_HARD_LINKS + else if (F_IS_HLINKED(file)) + handle_skipped_hlink(file, itemizing, code, f_out); +#endif if (verbose > 1) { rprintf(FINFO, "not creating new %s \"%s\"\n", is_dir ? "directory" : "file", fname); @@ -1362,6 +1370,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, && (!is_dir || !S_ISDIR(sx.st.st_mode))) { if (verbose > 1 && is_dir >= 0) rprintf(FINFO, "%s exists\n", fname); +#ifdef SUPPORT_HARD_LINKS + if (F_IS_HLINKED(file)) + handle_skipped_hlink(file, itemizing, code, f_out); +#endif goto cleanup; } @@ -1674,6 +1686,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, && cmp_time(sx.st.st_mtime, file->modtime) > 0) { if (verbose > 1) rprintf(FINFO, "%s is newer\n", fname); +#ifdef SUPPORT_HARD_LINKS + if (F_IS_HLINKED(file)) + handle_skipped_hlink(file, itemizing, code, f_out); +#endif goto cleanup; } @@ -1768,6 +1784,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, } if (append_mode > 0 && sx.st.st_size >= F_LENGTH(file)) { +#ifdef SUPPORT_HARD_LINKS + if (F_IS_HLINKED(file)) + handle_skipped_hlink(file, itemizing, code, f_out); +#endif goto cleanup; } @@ -1927,6 +1947,28 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, return; } +#ifdef SUPPORT_HARD_LINKS +static void handle_skipped_hlink(struct file_struct *file, int itemizing, + enum logcode code, int f_out) +{ + char fbuf[MAXPATHLEN]; + int new_last_ndx; + struct file_list *save_flist = cur_flist; + + /* If we skip the last item in a chain of links and there was a + * prior non-skipped hard-link waiting to finish, finish it now. */ + if ((new_last_ndx = skip_hard_link(file, &cur_flist)) < 0) + return; + + file = cur_flist->files[new_last_ndx - cur_flist->ndx_start]; + cur_flist->in_progress--; /* undo prior increment */ + f_name(file, fbuf); + recv_generator(fbuf, file, new_last_ndx, itemizing, code, f_out); + + cur_flist = save_flist; +} +#endif + static void touch_up_dirs(struct file_list *flist, int ndx) { static int counter = 0;