From 57edc4808f566fbaa58ec96bc7e543b1ccb92ab9 Mon Sep 17 00:00:00 2001 From: Matt McCutchen Date: Sat, 29 Jan 2011 19:25:53 -0800 Subject: [PATCH] Avoid changing file_extra_cnt during deletion. The I/O code can receive incremental file-list chunks during deletion, and their OPT_EXTRA fields would get corrupted when file_extra_cnt is incremented. Instead of temporarily enabling uid_ndx to find out whether the user owns a file, have make_file() set a flag for that purpose. Applied with a few minor tweaks by Wayne. Fixes bug 7936. --- delete.c | 10 +--------- flist.c | 7 +++++-- generator.c | 11 +---------- rsync.h | 1 + 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/delete.c b/delete.c index fcdf86bd..6be88d1e 100644 --- a/delete.c +++ b/delete.c @@ -28,7 +28,6 @@ extern int max_delete; extern char *backup_dir; extern char *backup_suffix; extern int backup_suffix_len; -extern uid_t our_uid; extern struct stats stats; int ignore_perishable = 0; @@ -98,7 +97,7 @@ static enum delret delete_dir_contents(char *fname, uint16 flags) } strlcpy(p, fp->basename, remainder); - if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid) + if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) do_chmod(fname, fp->mode | S_IWUSR); /* Save stack by recursing to ourself directly. */ if (S_ISDIR(fp->mode)) { @@ -143,19 +142,12 @@ enum delret delete_item(char *fbuf, uint16 mode, uint16 flags) do_chmod(fbuf, mode | S_IWUSR); if (S_ISDIR(mode) && !(flags & DEL_DIR_IS_EMPTY)) { - int save_uid_ndx = uid_ndx; /* This only happens on the first call to delete_item() since * delete_dir_contents() always calls us w/DEL_DIR_IS_EMPTY. */ - if (!uid_ndx) - uid_ndx = ++file_extra_cnt; ignore_perishable = 1; /* If DEL_RECURSE is not set, this just reports emptiness. */ ret = delete_dir_contents(fbuf, flags); ignore_perishable = 0; - if (!save_uid_ndx) { - --file_extra_cnt; - uid_ndx = 0; - } if (ret == DR_NOT_EMPTY || ret == DR_AT_LIMIT) goto check_ret; /* OK: try to delete the directory. */ diff --git a/flist.c b/flist.c index 60e00637..f90c286c 100644 --- a/flist.c +++ b/flist.c @@ -69,6 +69,7 @@ extern int sender_symlink_iconv; extern int output_needs_newline; extern int sender_keeps_checksum; extern int unsort_ndx; +extern uid_t our_uid; extern struct stats stats; extern char *filesfrom_host; extern char *usermap, *groupmap; @@ -1371,10 +1372,12 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } #endif file->mode = st.st_mode; - if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */ + if (preserve_uid) F_OWNER(file) = st.st_uid; - if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */ + if (preserve_gid) F_GROUP(file) = st.st_gid; + if (am_generator && st.st_uid == our_uid) + file->flags |= FLAG_OWNED_BY_US; if (basename != thisname) file->dirname = lastdir; diff --git a/generator.c b/generator.c index f2c4233e..d17e3b9e 100644 --- a/generator.c +++ b/generator.c @@ -276,7 +276,6 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev) struct file_list *dirlist; char delbuf[MAXPATHLEN]; int dlen, i; - int save_uid_ndx = uid_ndx; if (!fbuf) { change_local_filter_dir(NULL, 0, 0); @@ -308,9 +307,6 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev) return; } - if (!uid_ndx) - uid_ndx = ++file_extra_cnt; - dirlist = get_dirlist(fbuf, dlen, 0); /* If an item in dirlist is not found in flist, delete it @@ -330,7 +326,7 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev) * 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) + if (!(fp->mode & S_IWUSR) && !am_root && fp->flags & FLAG_OWNED_BY_US) flags |= DEL_NO_UID_WRITE; f_name(fp, delbuf); if (delete_during == 2) { @@ -342,11 +338,6 @@ static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev) } flist_free(dirlist); - - if (!save_uid_ndx) { - --file_extra_cnt; - uid_ndx = 0; - } } /* This deletes any files on the receiving side that are not present on the diff --git a/rsync.h b/rsync.h index c0bfaa99..2366f576 100644 --- a/rsync.h +++ b/rsync.h @@ -66,6 +66,7 @@ /* These flags are used in the live flist data. */ #define FLAG_TOP_DIR (1<<0) /* sender/receiver/generator */ +#define FLAG_OWNED_BY_US (1<<0) /* generator: set by make_file() for aux flists only */ #define FLAG_FILE_SENT (1<<1) /* sender/receiver/generator */ #define FLAG_DIR_CREATED (1<<1) /* generator */ #define FLAG_CONTENT_DIR (1<<2) /* sender/receiver/generator */ -- 2.34.1