X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/1c3344a105f656a45f6b46e1710c3fc4ab862a9a..02f0227e87c2922ce9dce075f4c1fad892ee58cc:/generator.c diff --git a/generator.c b/generator.c index e80daf2b..db1de189 100644 --- a/generator.c +++ b/generator.c @@ -36,6 +36,7 @@ extern int relative_paths; extern int implied_dirs; extern int keep_dirlinks; extern int preserve_acls; +extern int preserve_xattrs; extern int preserve_links; extern int preserve_devices; extern int preserve_specials; @@ -96,6 +97,9 @@ extern char *backup_suffix; extern int backup_suffix_len; extern struct file_list *cur_flist, *first_flist, *dir_flist; extern struct filter_list_struct server_filter_list; +#ifdef ICONV_OPTION +extern int ic_ndx; +#endif int ignore_perishable = 0; int non_perishable_cnt = 0; @@ -414,15 +418,14 @@ static void do_delayed_deletions(char *delbuf) * MAXPATHLEN buffer with the name of the directory in it (the functions we * call will append names onto the end, but the old dir value will be restored * on exit). */ -static void delete_in_dir(struct file_list *flist, char *fbuf, - struct file_struct *file, dev_t *fs_dev) +static void delete_in_dir(char *fbuf, struct file_struct *file, dev_t *fs_dev) { static int already_warned = 0; struct file_list *dirlist; char delbuf[MAXPATHLEN]; int dlen, i; - if (!flist) { + if (!fbuf) { change_local_filter_dir(NULL, 0, 0); return; } @@ -466,7 +469,7 @@ static void delete_in_dir(struct file_list *flist, char *fbuf, f_name(fp, NULL)); continue; } - if (flist_find(flist, fp) < 0) { + if (flist_find(cur_flist, fp) < 0) { f_name(fp, delbuf); if (delete_during == 2) { if (!remember_delete(fp, delbuf)) @@ -481,7 +484,7 @@ static void delete_in_dir(struct file_list *flist, char *fbuf, /* This deletes any files on the receiving side that are not present on the * sending side. This is used by --delete-before and --delete-after. */ -static void do_delete_pass(struct file_list *flist) +static void do_delete_pass(void) { char fbuf[MAXPATHLEN]; STRUCT_STAT st; @@ -491,8 +494,8 @@ static void do_delete_pass(struct file_list *flist) if (dry_run > 1 || list_only) return; - for (j = 0; j < flist->count; j++) { - struct file_struct *file = flist->files[j]; + for (j = 0; j < cur_flist->count; j++) { + struct file_struct *file = cur_flist->sorted[j]; if (!(file->flags & FLAG_XFER_DIR)) continue; @@ -505,9 +508,9 @@ static void do_delete_pass(struct file_list *flist) || !S_ISDIR(st.st_mode)) continue; - delete_in_dir(flist, fbuf, file, &st.st_dev); + delete_in_dir(fbuf, file, &st.st_dev); } - delete_in_dir(NULL, NULL, NULL, &dev_zero); + delete_in_dir(NULL, NULL, &dev_zero); if (do_progress && !am_server) rprintf(FINFO, " \r"); @@ -518,10 +521,10 @@ int unchanged_attrs(const char *fname, struct file_struct *file, statx *sxp) if (preserve_perms && !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS)) return 0; - if (am_root && preserve_uid && sxp->st.st_uid != F_UID(file)) + if (am_root && preserve_uid && sxp->st.st_uid != F_OWNER(file)) return 0; - if (preserve_gid && F_GID(file) != GID_NONE && sxp->st.st_gid != F_GID(file)) + if (preserve_gid && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != F_GROUP(file)) return 0; #ifdef SUPPORT_ACLS @@ -532,11 +535,19 @@ int unchanged_attrs(const char *fname, struct file_struct *file, statx *sxp) return 0; } #endif +#ifdef SUPPORT_XATTRS + if (preserve_xattrs) { + if (!XATTR_READY(*sxp)) + get_xattr(fname, sxp); + if (xattr_diff(file, sxp, 0)) + return 0; + } +#endif return 1; } -void itemize(const char *fname, struct file_struct *file, int ndx, int statret, +void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statret, statx *sxp, int32 iflags, uchar fnamecmp_type, const char *xname) { @@ -554,24 +565,37 @@ void itemize(const char *fname, struct file_struct *file, int ndx, int statret, iflags |= ITEM_REPORT_TIME; if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS)) iflags |= ITEM_REPORT_PERMS; - if (preserve_uid && am_root && F_UID(file) != sxp->st.st_uid) + if (preserve_uid && am_root && F_OWNER(file) != sxp->st.st_uid) iflags |= ITEM_REPORT_OWNER; - if (preserve_gid && F_GID(file) != GID_NONE - && sxp->st.st_gid != F_GID(file)) + if (preserve_gid && !(file->flags & FLAG_SKIP_GROUP) + && sxp->st.st_gid != F_GROUP(file)) iflags |= ITEM_REPORT_GROUP; #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { if (!ACL_READY(*sxp)) - get_acl(fname, sxp); + get_acl(fnamecmp, sxp); if (set_acl(NULL, file, sxp) == 0) iflags |= ITEM_REPORT_ACL; } #endif - } else +#ifdef SUPPORT_XATTRS + if (preserve_xattrs) { + if (!XATTR_READY(*sxp)) + get_xattr(fnamecmp, sxp); + if (xattr_diff(file, sxp, 1)) + iflags |= ITEM_REPORT_XATTR; + } +#endif + } else { +#ifdef SUPPORT_XATTRS + if (preserve_xattrs && xattr_diff(file, NULL, 1)) + iflags |= ITEM_REPORT_XATTR; +#endif iflags |= ITEM_IS_NEW; + } iflags &= 0xffff; - if ((iflags & SIGNIFICANT_ITEM_FLAGS || verbose > 1 + if ((iflags & (SIGNIFICANT_ITEM_FLAGS|ITEM_REPORT_XATTR) || verbose > 1 || stdout_format_has_i > 1 || (xname && *xname)) && !read_batch) { if (protocol_version >= 29) { if (ndx >= 0) @@ -581,6 +605,10 @@ void itemize(const char *fname, struct file_struct *file, int ndx, int statret, write_byte(sock_f_out, fnamecmp_type); 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); +#endif } else if (ndx >= 0) { enum logcode code = logfile_format_has_i ? FINFO : FCLIENT; log_item(code, file, &stats, iflags, xname); @@ -598,7 +626,7 @@ int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st) /* if always checksum is set then we use the checksum instead of the file time to determine whether to sync */ if (always_checksum > 0 && S_ISREG(st->st_mode)) { - char sum[MD4_SUM_LENGTH]; + char sum[MAX_DIGEST_LEN]; file_checksum(fn, sum, st->st_size); return memcmp(sum, F_SUM(file), checksum_len) == 0; } @@ -855,14 +883,14 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx, if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, &sxp->st, itemizing, code, j); if (itemizing && (verbose > 1 || stdout_format_has_i > 1)) { - itemize(fname, file, ndx, 1, sxp, + itemize(cmpbuf, file, ndx, 1, sxp, ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0, ""); } } else #endif if (itemizing) - itemize(fname, file, ndx, 0, sxp, 0, 0, NULL); + itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL); if (verbose > 1 && maybe_ATTRS_REPORT) rprintf(FCLIENT, "%s is uptodate\n", fname); return -2; @@ -879,9 +907,13 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx, } return -1; } + set_file_attrs(fname, file, NULL, cmpbuf, 0); if (itemizing) - itemize(fname, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL); - set_file_attrs(fname, file, NULL, 0); + itemize(cmpbuf, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL); +#ifdef SUPPORT_XATTRS + if (preserve_xattrs) + xattr_clear_locals(file); +#endif if (maybe_ATTRS_REPORT && ((!itemizing && verbose && match_level == 2) || (verbose > 1 && match_level == 3))) { @@ -1029,7 +1061,7 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx, : ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0); char *lp = match_level == 3 ? "" : NULL; - itemize(fname, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp); + itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp); } if (verbose > 1 && maybe_ATTRS_REPORT) { rprintf(FCLIENT, "%s%s is uptodate\n", @@ -1111,6 +1143,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, } #ifdef SUPPORT_ACLS sx.acc_acl = sx.def_acl = NULL; +#endif +#ifdef SUPPORT_XATTRS + sx.xattr = NULL; #endif if (dry_run > 1) { if (fuzzy_dirlist) { @@ -1224,7 +1259,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, goto cleanup; } } - if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, 0) + if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, NULL, 0) && verbose && code != FNONE && f_out != -1) rprintf(code, "%s/\n", fname); if (real_ret != 0 && one_file_system) @@ -1238,7 +1273,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, } else if (delete_during && f_out != -1 && !phase && dry_run < 2 && (file->flags & FLAG_XFER_DIR)) - delete_in_dir(cur_flist, fname, file, &real_sx.st.st_dev); + delete_in_dir(fname, file, &real_sx.st.st_dev); goto cleanup; } @@ -1278,9 +1313,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, else if ((len = readlink(fname, lnk, MAXPATHLEN-1)) > 0 && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') { /* The link is pointing to the right place. */ + set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); if (itemizing) itemize(fname, file, ndx, 0, &sx, 0, 0, NULL); - set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, &sx.st, itemizing, code, -1); @@ -1317,7 +1352,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, rsyserr(FERROR, errno, "symlink %s -> \"%s\" failed", full_fname(fname), sl); } else { - set_file_attrs(fname, file, NULL, 0); + set_file_attrs(fname, file, NULL, NULL, 0); if (itemizing) { itemize(fname, file, ndx, statret, &sx, ITEM_LOCAL_CHANGE, 0, NULL); @@ -1357,9 +1392,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT) && sx.st.st_rdev == rdev) { /* The device or special file is identical. */ + set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); if (itemizing) itemize(fname, file, ndx, 0, &sx, 0, 0, NULL); - set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, &sx.st, itemizing, code, -1); @@ -1399,7 +1434,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, rsyserr(FERROR, errno, "mknod %s failed", full_fname(fname)); } else { - set_file_attrs(fname, file, NULL, 0); + set_file_attrs(fname, file, NULL, NULL, 0); if (itemizing) { itemize(fname, file, ndx, statret, &sx, ITEM_LOCAL_CHANGE, 0, NULL); @@ -1529,9 +1564,9 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, do_unlink(partialptr); handle_partial_dir(partialptr, PDIR_DELETE); } + set_file_attrs(fname, file, &sx, NULL, maybe_ATTRS_REPORT); if (itemizing) itemize(fnamecmp, file, ndx, statret, &sx, 0, 0, NULL); - set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT); #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, &sx.st, itemizing, code, -1); @@ -1635,6 +1670,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, #ifdef SUPPORT_ACLS if (preserve_acls) free_acl(&real_sx); +#endif +#ifdef SUPPORT_XATTRS + if (preserve_xattrs) + free_xattr(&real_sx); #endif } @@ -1657,7 +1696,7 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, if (f_copy >= 0) { close(f_copy); - set_file_attrs(backupptr, back_file, NULL, 0); + set_file_attrs(backupptr, back_file, NULL, NULL, 0); if (verbose > 1) { rprintf(FINFO, "backed up %s to %s\n", fname, backupptr); @@ -1671,6 +1710,10 @@ static void recv_generator(char *fname, struct file_struct *file, int ndx, #ifdef SUPPORT_ACLS if (preserve_acls) free_acl(&sx); +#endif +#ifdef SUPPORT_XATTRS + if (preserve_xattrs) + free_xattr(&sx); #endif return; } @@ -1786,7 +1829,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; + int i, ndx; char fbuf[MAXPATHLEN]; int itemizing; enum logcode code; @@ -1819,7 +1862,7 @@ void generate_files(int f_out, const char *local_name) rprintf(FINFO, "generator starting pid=%ld\n", (long)getpid()); if (delete_before && !solo_file && cur_flist->count > 0) - do_delete_pass(cur_flist); + do_delete_pass(); if (delete_during == 2) { deldelay_size = BIGPATHBUFLEN * 4; deldelay_buf = new_array(char, deldelay_size); @@ -1855,21 +1898,27 @@ void generate_files(int f_out, const char *local_name) dirdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)); } else dirdev = MAKEDEV(0, 0); - delete_in_dir(cur_flist, f_name(fp, fbuf), fp, &dirdev); + delete_in_dir(f_name(fp, fbuf), fp, &dirdev); } } for (i = cur_flist->low; i <= cur_flist->high; i++) { - struct file_struct *file = cur_flist->files[i]; + struct file_struct *file = cur_flist->sorted[i]; if (!F_IS_ACTIVE(file)) continue; +#ifdef ICONV_OPTION + if (ic_ndx) + ndx = F_NDX(file); + else +#endif + ndx = i + cur_flist->ndx_start; + if (solo_file) strlcpy(fbuf, solo_file, sizeof fbuf); else f_name(file, fbuf); - recv_generator(fbuf, file, i + cur_flist->ndx_start, - itemizing, code, f_out); + recv_generator(fbuf, file, ndx, itemizing, code, f_out); /* We need to ensure that any dirs we create have * writeable permissions during the time we are putting @@ -1902,20 +1951,24 @@ void generate_files(int f_out, const char *local_name) break; } - while (!cur_flist->next && !flist_eof) { + while (1) { check_for_finished_files(itemizing, code, 1); + if (cur_flist->next || flist_eof) + break; wait_for_receiver(); } } while ((cur_flist = cur_flist->next) != NULL); if (delete_during) - delete_in_dir(NULL, NULL, NULL, &dev_zero); + delete_in_dir(NULL, NULL, &dev_zero); phase++; if (verbose > 2) rprintf(FINFO, "generate_files phase=%d\n", phase); - while (!msgdone_cnt) { + while (1) { check_for_finished_files(itemizing, code, 1); + if (msgdone_cnt) + break; wait_for_receiver(); } @@ -1929,8 +1982,10 @@ void generate_files(int f_out, const char *local_name) write_ndx(f_out, NDX_DONE); /* Read MSG_DONE for the redo phase (and any prior messages). */ - while (msgdone_cnt <= 1) { + while (1) { check_for_finished_files(itemizing, code, 0); + if (msgdone_cnt > 1) + break; wait_for_receiver(); } @@ -1949,11 +2004,11 @@ void generate_files(int f_out, const char *local_name) if (delete_during == 2) do_delayed_deletions(fbuf); if (delete_after && !solo_file && file_total > 0) - do_delete_pass(cur_flist); + do_delete_pass(); if ((need_retouch_dir_perms || need_retouch_dir_times) && dir_tweaking && (!inc_recurse || delete_during == 2)) - touch_up_dirs(inc_recurse ? dir_flist : cur_flist, -1); + touch_up_dirs(dir_flist, -1); if (max_delete >= 0 && deletion_count > max_delete) { rprintf(FINFO,