X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/c6fadc0ee1ab74ee0193a86cbe9095813d8efce4..b0cacef14b62dae31f044a0b580ee35b0a2bfbe3:/generator.c diff --git a/generator.c b/generator.c index 67baed2d..ffd8ab71 100644 --- a/generator.c +++ b/generator.c @@ -93,17 +93,21 @@ extern int backup_suffix_len; extern struct file_list *the_file_list; extern struct filter_list_struct server_filter_list; +int ignore_perishable = 0; +int non_perishable_cnt = 0; + static int deletion_count = 0; /* used to implement --max-delete */ -/* For calling delete_item() */ +/* For calling delete_item() and delete_dir_contents(). */ #define DEL_RECURSE (1<<1) /* recurse */ +#define DEL_DIR_IS_EMPTY (1<<2) /* internal delete_FUNCTIONS use only */ enum nonregtype { TYPE_DIR, TYPE_SPECIAL, TYPE_DEVICE, TYPE_SYMLINK }; enum delret { - DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_PINNED, DR_NOT_EMPTY + DR_SUCCESS = 0, DR_FAILURE, DR_AT_LIMIT, DR_NOT_EMPTY }; /* Forward declaration for delete_item(). */ @@ -133,10 +137,12 @@ static enum delret delete_item(char *fname, int mode, char *replace, int flags) fname, mode, flags); } - if (S_ISDIR(mode) && flags & DEL_RECURSE) { + if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { + ignore_perishable = 1; + /* If DEL_RECURSE is not set, this just reports emptiness. */ ret = delete_dir_contents(fname, flags); - if (ret == DR_PINNED || ret == DR_NOT_EMPTY - || ret == DR_AT_LIMIT) + ignore_perishable = 0; + if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT) goto check_ret; /* OK: try to delete the directory. */ } @@ -161,7 +167,7 @@ static enum delret delete_item(char *fname, int mode, char *replace, int flags) ret = DR_SUCCESS; } else { if (S_ISDIR(mode) && errno == ENOTEMPTY) { - rprintf(FINFO, "non-empty directory, %s, not deleted\n", + rprintf(FINFO, "cannot delete non-empty directory: %s\n", fname); ret = DR_NOT_EMPTY; } else if (errno != ENOENT) { @@ -182,30 +188,47 @@ static enum delret delete_item(char *fname, int mode, char *replace, int flags) return ret; } -/* Prep directory is to be deleted, so delete all its contents. Note - * that fname must point to a MAXPATHLEN buffer! (The buffer is used - * for recursion, but returned unchanged.) +/* The directory is about to be deleted: if DEL_RECURSE is given, delete all + * its contents, otherwise just checks for content. Returns DR_SUCCESS or + * DR_NOT_EMPTY. Note that fname must point to a MAXPATHLEN buffer! (The + * buffer is used for recursion, but returned unchanged.) */ static enum delret delete_dir_contents(char *fname, int flags) { struct file_list *dirlist; - enum delret ret, result; + enum delret ret; unsigned remainder; void *save_filters; int j, dlen; char *p; + if (verbose > 3) { + rprintf(FINFO, "delete_dir_contents(%s) flags=%d\n", + fname, flags); + } + dlen = strlen(fname); save_filters = push_local_filters(fname, dlen); + non_perishable_cnt = 0; dirlist = get_dirlist(fname, dlen, 0); + ret = non_perishable_cnt ? DR_NOT_EMPTY : DR_SUCCESS; + + if (!dirlist->count) + goto done; + + if (!(flags & DEL_RECURSE)) { + ret = DR_NOT_EMPTY; + goto done; + } p = fname + dlen; if (dlen != 1 || *fname != '/') *p++ = '/'; remainder = MAXPATHLEN - (p - fname); - ret = DR_SUCCESS; + /* We do our own recursion, so make delete_item() non-recursive. */ + flags = (flags & ~DEL_RECURSE) | DEL_DIR_IS_EMPTY; for (j = dirlist->count; j--; ) { struct file_struct *fp = dirlist->files[j]; @@ -216,21 +239,29 @@ static enum delret delete_dir_contents(char *fname, int flags) "mount point, %s, pins parent directory\n", f_name(fp, NULL)); } - ret = DR_PINNED; + ret = DR_NOT_EMPTY; continue; } strlcpy(p, fp->basename, remainder); - result = delete_item(fname, fp->mode, NULL, flags); - if (result != DR_SUCCESS && ret == DR_SUCCESS) - ret = result == DR_PINNED ? result : DR_NOT_EMPTY; + /* Save stack by recursing to ourself directly. */ + if (S_ISDIR(fp->mode) + && delete_dir_contents(fname, flags | DEL_RECURSE) != DR_SUCCESS) + ret = DR_NOT_EMPTY; + if (delete_item(fname, fp->mode, NULL, flags) != DR_SUCCESS) + ret = DR_NOT_EMPTY; } fname[dlen] = '\0'; - pop_local_filters(save_filters); + done: flist_free(dirlist); + pop_local_filters(save_filters); + if (ret == DR_NOT_EMPTY) { + rprintf(FINFO, "cannot delete non-empty directory: %s\n", + fname); + } return ret; } @@ -301,7 +332,7 @@ static void delete_in_dir(struct file_list *flist, char *fbuf, continue; if (fp->flags & FLAG_MOUNT_POINT) { if (verbose > 1) - rprintf(FINFO, "mount point %s not deleted\n", + rprintf(FINFO, "cannot delete mount point: %s\n", f_name(fp, NULL)); continue; } @@ -364,7 +395,7 @@ int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st) } void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st, - int32 iflags, uchar fnamecmp_type, char *xname) + int32 iflags, uchar fnamecmp_type, const char *xname) { if (statret >= 0) { /* A from-dest-dir statret can == 1! */ int keep_time = !preserve_times ? 0 @@ -495,8 +526,8 @@ static void sum_sizes_sqroot(struct sum_struct *sum, int64 len) sum->flength = len; sum->blength = blength; sum->s2length = s2length; - sum->remainder = len % blength; - sum->count = len / blength + (sum->remainder != 0); + sum->remainder = (int32)(len % blength); + sum->count = (int32)(len / blength) + (sum->remainder != 0); if (sum->count && verbose > 2) { rprintf(FINFO, @@ -888,7 +919,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, enum logcode code, int f_out) { static int missing_below = -1, excluded_below = -1; - static char *parent_dirname = ""; + static const char *parent_dirname = ""; static struct file_list *fuzzy_dirlist = NULL; static int need_fuzzy_dirlist = 0; struct file_struct *fuzzy_file = NULL; @@ -953,7 +984,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, statret = -1; stat_errno = ENOENT; } else { - char *dn = file->dirname ? file->dirname : "."; + const char *dn = file->dirname ? file->dirname : "."; if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) { if (relative_paths && !implied_dirs && do_stat(dn, &st) < 0 @@ -972,7 +1003,8 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, parent_dirname = dn; if (need_fuzzy_dirlist && S_ISREG(file->mode)) { - fuzzy_dirlist = get_dirlist(dn, -1, 1); + strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf); + fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, 1); need_fuzzy_dirlist = 0; }