X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/21897ecbedeec3fbcaf2cbed895df6d11d811ba9..d48810ba5b0b8d09b272092a70da1255c2346ab8:/flist.c diff --git a/flist.c b/flist.c index a0970216..dce55c7b 100644 --- a/flist.c +++ b/flist.c @@ -4,7 +4,7 @@ * Copyright (C) 1996 Andrew Tridgell * Copyright (C) 1996 Paul Mackerras * Copyright (C) 2001, 2002 Martin Pool - * Copyright (C) 2002-2007 Wayne Davison + * Copyright (C) 2002-2008 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 @@ -44,6 +44,8 @@ extern int filesfrom_fd; extern int one_file_system; extern int copy_dirlinks; extern int keep_dirlinks; +extern int preserve_uid; +extern int preserve_gid; extern int preserve_acls; extern int preserve_xattrs; extern int preserve_links; @@ -74,7 +76,7 @@ extern char curr_dir[MAXPATHLEN]; extern struct chmod_mode_struct *chmod_modes; extern struct filter_list_struct filter_list; -extern struct filter_list_struct server_filter_list; +extern struct filter_list_struct daemon_filter_list; #ifdef ICONV_OPTION extern int filesfrom_convert; @@ -230,10 +232,20 @@ int link_stat(const char *path, STRUCT_STAT *stp, int follow_dirlinks) #endif } +static inline int is_daemon_excluded(const char *fname, int is_dir) +{ + if (daemon_filter_list.head + && check_filter(&daemon_filter_list, fname, is_dir) < 0) { + errno = ENOENT; + return 1; + } + return 0; +} + /* This function is used to check if a file should be included/excluded * from the list of files based on its name and type etc. The value of * filter_level is set to either SERVER_FILTERS or ALL_FILTERS. */ -static int is_excluded(char *fname, int is_dir, int filter_level) +static int is_excluded(const char *fname, int is_dir, int filter_level) { #if 0 /* This currently never happens, so avoid a useless compare. */ if (filter_level == NO_FILTERS) @@ -250,8 +262,7 @@ static int is_excluded(char *fname, int is_dir, int filter_level) return 0; } } - if (server_filter_list.head - && check_filter(&server_filter_list, fname, is_dir) < 0) + if (is_daemon_excluded(fname, is_dir)) return 1; if (filter_level != ALL_FILTERS) return 0; @@ -422,24 +433,24 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ } } else if (protocol_version < 28) rdev = MAKEDEV(0, 0); - if (uid_ndx) { + if (preserve_uid) { if ((uid_t)F_OWNER(file) == uid && *lastname) xflags |= XMIT_SAME_UID; else { uid = F_OWNER(file); - if (uid_ndx && !numeric_ids) { + if (!numeric_ids) { user_name = add_uid(uid); if (inc_recurse && user_name) xflags |= XMIT_USER_NAME_FOLLOWS; } } } - if (gid_ndx) { + if (preserve_gid) { if ((gid_t)F_GROUP(file) == gid && *lastname) xflags |= XMIT_SAME_GID; else { gid = F_GROUP(file); - if (gid_ndx && !numeric_ids) { + if (!numeric_ids) { group_name = add_gid(gid); if (inc_recurse && group_name) xflags |= XMIT_GROUP_NAME_FOLLOWS; @@ -522,7 +533,7 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ } if (!(xflags & XMIT_SAME_MODE)) write_int(f, to_wire_mode(mode)); - if (uid_ndx && !(xflags & XMIT_SAME_UID)) { + if (preserve_uid && !(xflags & XMIT_SAME_UID)) { if (protocol_version < 30) write_int(f, uid); else { @@ -534,7 +545,7 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ } } } - if (gid_ndx && !(xflags & XMIT_SAME_GID)) { + if (preserve_gid && !(xflags & XMIT_SAME_GID)) { if (protocol_version < 30) write_int(f, gid); else { @@ -676,7 +687,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, clean_fname(thisname, 0); if (sanitize_paths) - sanitize_path(thisname, thisname, "", 0); + sanitize_path(thisname, thisname, "", 0, SP_DEFAULT); if ((basename = strrchr(thisname, '/')) != NULL) { int len = basename++ - thisname; @@ -706,9 +717,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist, file_length = F_LENGTH(first); modtime = first->modtime; mode = first->mode; - if (uid_ndx) + if (preserve_uid) uid = F_OWNER(first); - if (gid_ndx) + if (preserve_gid) gid = F_GROUP(first); if ((preserve_devices && IS_DEVICE(mode)) || (preserve_specials && IS_SPECIAL(mode))) { @@ -745,7 +756,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, if (chmod_modes && !S_ISLNK(mode)) mode = tweak_mode(mode, chmod_modes); - if (uid_ndx && !(xflags & XMIT_SAME_UID)) { + if (preserve_uid && !(xflags & XMIT_SAME_UID)) { if (protocol_version < 30) uid = (uid_t)read_int(f); else { @@ -756,7 +767,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, uid = match_uid(uid); } } - if (gid_ndx && !(xflags & XMIT_SAME_GID)) { + if (preserve_gid && !(xflags & XMIT_SAME_GID)) { if (protocol_version < 30) gid = (gid_t)read_int(f); else { @@ -817,9 +828,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist, #endif #ifdef SUPPORT_ACLS - /* We need one or two index int32s when we're preserving ACLs. */ - if (preserve_acls) - extra_len += (S_ISDIR(mode) ? 2 : 1) * EXTRA_LEN; + /* Directories need an extra int32 for the default ACL. */ + if (preserve_acls && S_ISDIR(mode)) + extra_len += EXTRA_LEN; #endif if (always_checksum && S_ISREG(mode)) @@ -852,7 +863,6 @@ static struct file_struct *recv_file_entry(struct file_list *flist, bp += FILE_STRUCT_LEN; memcpy(bp, basename, basename_len); - bp += basename_len + linkname_len; /* skip space for symlink too */ #ifdef SUPPORT_HARD_LINKS if (xflags & XMIT_HLINKED) @@ -865,9 +875,9 @@ static struct file_struct *recv_file_entry(struct file_list *flist, OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32); } file->mode = mode; - if (uid_ndx) + if (preserve_uid) F_OWNER(file) = uid; - if (gid_ndx) { + if (preserve_gid) { F_GROUP(file) = gid; file->flags |= gid_flags; } @@ -917,7 +927,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, #ifdef SUPPORT_LINKS if (linkname_len) { - bp = (char*)file->basename + basename_len; + bp += basename_len; if (first_hlink_ndx >= flist->ndx_start) { struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start]; memcpy(bp, F_SYMLINK(first), linkname_len); @@ -929,7 +939,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, } else { read_sbuf(f, bp, linkname_len - 1); if (sanitize_paths) - sanitize_path(bp, bp, "", lastdir_depth); + sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT); } } #endif @@ -1020,7 +1030,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, } clean_fname(thisname, 0); if (sanitize_paths) - sanitize_path(thisname, thisname, "", 0); + sanitize_path(thisname, thisname, "", 0, SP_DEFAULT); if (stp && S_ISDIR(stp->st_mode)) { st = *stp; /* Needed for "symlink/." with --relative. */ @@ -1121,8 +1131,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, pool = dir_flist->file_pool; } else pool = flist->file_pool; - } else + } else { +#ifdef SUPPORT_ACLS + /* Directories need an extra int32 for the default ACL. */ + if (preserve_acls && S_ISDIR(st.st_mode)) + extra_len += EXTRA_LEN; +#endif pool = NULL; + } if (verbose > 2) { rprintf(FINFO, "[%s] make_file(%s,*,%d)\n", @@ -1170,7 +1186,6 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, bp += FILE_STRUCT_LEN; memcpy(bp, basename, basename_len); - bp += basename_len + linkname_len; /* skip space for symlink too */ #ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && flist && flist->prev) { @@ -1199,25 +1214,26 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32); } file->mode = st.st_mode; - if (uid_ndx) + if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */ F_OWNER(file) = st.st_uid; - if (gid_ndx) + if (gid_ndx) /* Check gid_ndx instead of preserve_gid for del support */ F_GROUP(file) = st.st_gid; if (basename != thisname) file->dirname = lastdir; #ifdef SUPPORT_LINKS - if (linkname_len) { - bp = (char*)file->basename + basename_len; - memcpy(bp, linkname, linkname_len); - } + if (linkname_len) + memcpy(bp + basename_len, linkname, linkname_len); #endif if (always_checksum && am_sender && S_ISREG(st.st_mode)) file_checksum(thisname, tmp_sum, st.st_size); - F_PATHNAME(file) = pathname; + if (am_sender) + F_PATHNAME(file) = pathname; + else if (!pool) + F_DEPTH(file) = extra_len / EXTRA_LEN; /* This code is only used by the receiver when it is building * a list of files for a delete pass. */ @@ -1253,12 +1269,7 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, /* Only called for temporary file_struct entries created by make_file(). */ void unmake_file(struct file_struct *file) { - int extra_cnt = file_extra_cnt + LEN64_BUMP(file); -#if EXTRA_ROUNDING > 0 - if (extra_cnt & EXTRA_ROUNDING) - extra_cnt = (extra_cnt | EXTRA_ROUNDING) + 1; -#endif - free(REQ_EXTRA(file, extra_cnt)); + free(REQ_EXTRA(file, F_DEPTH(file))); } static struct file_struct *send_file_name(int f, struct file_list *flist, @@ -1784,6 +1795,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) | (filesfrom_convert ? RL_CONVERT : 0) #endif | (eol_nulls || reading_remotely ? RL_EOL_NULLS : 0); + int implied_dot_dir = 0; rprintf(FLOG, "building file list\n"); if (show_filelist_p()) @@ -1825,13 +1837,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (use_ff_fd) { if (read_line(filesfrom_fd, fbuf, sizeof fbuf, rl_flags) == 0) break; - sanitize_path(fbuf, fbuf, "", 0); + sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS); } else { if (argc-- == 0) break; strlcpy(fbuf, *argv++, MAXPATHLEN); if (sanitize_paths) - sanitize_path(fbuf, fbuf, "", 0); + sanitize_path(fbuf, fbuf, "", 0, SP_KEEP_DOT_DIRS); } len = strlen(fbuf); @@ -1881,8 +1893,10 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) *p = '\0'; if (p == fbuf) dir = "/"; - else + else { dir = fbuf; + clean_fname(dir, 0); + } fn = p + 3; while (*fn == '/') fn++; @@ -1890,8 +1904,15 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) *--fn = '\0'; /* ensure room for '.' */ } else fn = fbuf; - len = clean_fname(fn, CFN_KEEP_LEADING_DOT_DIR - | CFN_KEEP_TRAILING_SLASH + /* A leading ./ can be used in relative mode to affect + * the dest dir without its name being in the path. */ + if (*fn == '.' && fn[1] == '/' && !implied_dot_dir) { + send_file_name(f, flist, ".", NULL, + (flags | FLAG_IMPLIED_DIR) & ~FLAG_CONTENT_DIR, + ALL_FILTERS); + implied_dot_dir = 1; + } + len = clean_fname(fn, CFN_KEEP_TRAILING_SLASH | CFN_DROP_TRAILING_DOT_DIR); if (len == 1) { if (fn[0] == '/') { @@ -1937,7 +1958,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (fn != fbuf) memmove(fbuf, fn, len + 1); - if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0) { + if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0 + || is_daemon_excluded(fbuf, S_ISDIR(st.st_mode) != 0)) { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "link_stat %s failed", full_fname(fbuf)); @@ -1984,15 +2006,17 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) int top_flags = FLAG_TOP_DIR | FLAG_CONTENT_DIR | flags; file = send_file_name(f, flist, fbuf, &st, top_flags, ALL_FILTERS); + if (!file) + continue; if (inc_recurse) { - if (name_type == DOT_NAME && file) { + if (name_type == DOT_NAME) { if (send_dir_depth < 0) { send_dir_depth = 0; change_local_filter_dir(fbuf, len, send_dir_depth); } send_directory(f, flist, fbuf, len, flags); } - } else if (file) + } else send_if_directory(f, flist, file, fbuf, len, flags); } else send_file_name(f, flist, fbuf, &st, flags, ALL_FILTERS); @@ -2037,7 +2061,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) flist_sort_and_clean(flist, 0); file_total += flist->used; - if (!numeric_ids && !inc_recurse) + if (numeric_ids <= 0 && !inc_recurse) send_id_list(f); /* send the io_error flag */