X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/0b52f94da727c4881b58c1cd6f2cf2a824e02b30..9793bbb3646cbaa816d074dc925a4f4f7d40089f:/flist.c diff --git a/flist.c b/flist.c index 20350459..cac390b4 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,46 @@ 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, FLOG, fname, is_dir) < 0) { + errno = ENOENT; + return 1; + } + return 0; +} + +static inline int path_is_daemon_excluded(char *path, int ignore_filename) +{ + if (daemon_filter_list.head && path) { + char *slash = path; + + while ((slash = strchr(slash+1, '/')) != NULL) { + int ret; + *slash = '\0'; + ret = check_filter(&daemon_filter_list, FLOG, path, 1); + *slash = '/'; + if (ret < 0) { + errno = ENOENT; + return 1; + } + } + + if (!ignore_filename + && check_filter(&daemon_filter_list, FLOG, path, 1) < 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,13 +288,12 @@ 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; if (filter_list.head - && check_filter(&filter_list, fname, is_dir) < 0) + && check_filter(&filter_list, FINFO, fname, is_dir) < 0) return 1; return 0; } @@ -340,7 +377,7 @@ int push_pathname(const char *dir, int len) return 1; } -static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ndx) +static void send_file_entry(int f, const char *fname, struct file_struct *file, int ndx, int first_ndx) { static time_t modtime; static mode_t mode; @@ -353,40 +390,10 @@ static void send_file_entry(int f, struct file_struct *file, int ndx, int first_ static gid_t gid; static const char *user_name, *group_name; static char lastname[MAXPATHLEN]; - char fname[MAXPATHLEN]; int first_hlink_ndx = -1; int l1, l2; int xflags; -#ifdef ICONV_OPTION - if (ic_send != (iconv_t)-1) { - xbuf outbuf, inbuf; - - INIT_CONST_XBUF(outbuf, fname); - - if (file->dirname) { - INIT_XBUF_STRLEN(inbuf, (char*)file->dirname); - outbuf.size -= 2; /* Reserve room for '/' & 1 more char. */ - if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) - goto convert_error; - outbuf.size += 2; - outbuf.buf[outbuf.len++] = '/'; - } - - INIT_XBUF_STRLEN(inbuf, (char*)file->basename); - if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) { - convert_error: - io_error |= IOERR_GENERAL; - rprintf(FINFO, - "[%s] cannot convert filename: %s (%s)\n", - who_am_i(), f_name(file, fname), strerror(errno)); - return; - } - outbuf.buf[outbuf.len] = '\0'; - } else -#endif - f_name(file, fname); - /* Initialize starting value of xflags. */ if (protocol_version >= 30 && S_ISDIR(file->mode)) { dir_count++; @@ -422,24 +429,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 +529,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 +541,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 { @@ -673,10 +680,11 @@ static struct file_struct *recv_file_entry(struct file_list *flist, } #endif - clean_fname(thisname, 0); + if (*thisname) + 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 +714,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 +753,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 +764,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 +825,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 +860,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 +872,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 +924,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 +936,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 +1027,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 +1128,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 +1183,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 +1211,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,22 +1266,14 @@ 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, - char *fname, STRUCT_STAT *stp, + const char *fname, STRUCT_STAT *stp, int flags, int filter_level) { struct file_struct *file; -#if defined SUPPORT_ACLS || defined SUPPORT_XATTRS - stat_x sx; -#endif file = make_file(fname, flist, stp, flags, filter_level); if (!file) @@ -1277,28 +1282,59 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, if (chmod_modes && !S_ISLNK(file->mode)) file->mode = tweak_mode(file->mode, chmod_modes); + if (f >= 0) { + char fbuf[MAXPATHLEN]; +#if defined SUPPORT_ACLS || defined SUPPORT_XATTRS + stat_x sx; +#endif + +#ifdef ICONV_OPTION + if (ic_send != (iconv_t)-1) { + xbuf outbuf, inbuf; + + INIT_CONST_XBUF(outbuf, fbuf); + + if (file->dirname) { + INIT_XBUF_STRLEN(inbuf, (char*)file->dirname); + outbuf.size -= 2; /* Reserve room for '/' & 1 more char. */ + if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) + goto convert_error; + outbuf.size += 2; + outbuf.buf[outbuf.len++] = '/'; + } + + INIT_XBUF_STRLEN(inbuf, (char*)file->basename); + if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) { + convert_error: + io_error |= IOERR_GENERAL; + rprintf(FINFO, + "[%s] cannot convert filename: %s (%s)\n", + who_am_i(), f_name(file, fbuf), strerror(errno)); + return NULL; + } + outbuf.buf[outbuf.len] = '\0'; + } else +#endif + f_name(file, fbuf); + #ifdef SUPPORT_ACLS - if (preserve_acls && !S_ISLNK(file->mode) && f >= 0) { - sx.st.st_mode = file->mode; - sx.acc_acl = sx.def_acl = NULL; - if (get_acl(fname, &sx) < 0) - return NULL; - } + if (preserve_acls && !S_ISLNK(file->mode)) { + sx.st.st_mode = file->mode; + sx.acc_acl = sx.def_acl = NULL; + if (get_acl(fname, &sx) < 0) + return NULL; + } #endif #ifdef SUPPORT_XATTRS - if (preserve_xattrs && f >= 0) { - sx.xattr = NULL; - if (get_xattr(fname, &sx) < 0) - return NULL; - } + if (preserve_xattrs) { + sx.xattr = NULL; + if (get_xattr(fname, &sx) < 0) + return NULL; + } #endif - maybe_emit_filelist_progress(flist->used + flist_count_offset); + send_file_entry(f, fbuf, file, flist->used, flist->ndx_start); - flist_expand(flist, 1); - flist->files[flist->used++] = file; - if (f >= 0) { - send_file_entry(f, file, flist->used - 1, flist->ndx_start); #ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { send_acl(&sx, f); @@ -1312,6 +1348,12 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, } #endif } + + maybe_emit_filelist_progress(flist->used + flist_count_offset); + + flist_expand(flist, 1); + flist->files[flist->used++] = file; + return file; } @@ -1784,6 +1826,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 +1868,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 +1924,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 +1935,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] == '/') { @@ -1927,6 +1979,12 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) dirlen = dir ? strlen(dir) : 0; if (dirlen != lastdir_len || memcmp(lastdir, dir, dirlen) != 0) { + if (path_is_daemon_excluded(dir, 0)) { + io_error |= IOERR_GENERAL; + rsyserr(FERROR, errno, "push_dir %s failed in %s", + full_fname(dir), curr_dir); + continue; + } if (!push_pathname(dir ? strdup(dir) : NULL, dirlen)) continue; lastdir = pathname; @@ -1937,7 +1995,9 @@ 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) + || (relative_paths && path_is_daemon_excluded(fbuf, 1))) { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "link_stat %s failed", full_fname(fbuf)); @@ -1984,15 +2044,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);