X-Git-Url: https://mattmccutchen.net/rsync/rsync.git/blobdiff_plain/d4d56eed8a2dfdd2cd78a19f9c1bae02496427e3..4e0fa131fe6a5d864bb6918ff32671484df132c9:/flist.c diff --git a/flist.c b/flist.c index 570c3b79..1c15d8c0 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-2008 Wayne Davison + * Copyright (C) 2002-2009 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 @@ -51,6 +51,7 @@ extern int preserve_links; extern int preserve_hard_links; extern int preserve_devices; extern int preserve_specials; +extern int delete_missing_args; extern int uid_ndx; extern int gid_ndx; extern int eol_nulls; @@ -72,6 +73,7 @@ extern int sender_keeps_checksum; extern int unsort_ndx; extern struct stats stats; extern char *filesfrom_host; +extern char *usermap, *groupmap; extern char curr_dir[MAXPATHLEN]; @@ -430,7 +432,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file, stats.num_symlinks++; else if (IS_DEVICE(file->mode)) stats.num_devices++; - else + else if (IS_SPECIAL(file->mode)) stats.num_specials++; xflags = 0; } @@ -792,7 +794,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, if (!(xflags & XMIT_SAME_MODE)) mode = from_wire_mode(read_int(f)); - if (chmod_modes && !S_ISLNK(mode)) + if (chmod_modes && !S_ISLNK(mode) && mode) mode = tweak_mode(mode, chmod_modes); if (preserve_uid && !(xflags & XMIT_SAME_UID)) { @@ -802,7 +804,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, uid = (uid_t)read_varint(f); if (xflags & XMIT_USER_NAME_FOLLOWS) uid = recv_user_name(f, uid); - else if (inc_recurse && am_root && !numeric_ids) + else if (inc_recurse && am_root && (!numeric_ids || usermap)) uid = match_uid(uid); } } @@ -814,7 +816,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist, gid_flags = 0; if (xflags & XMIT_GROUP_NAME_FOLLOWS) gid = recv_group_name(f, gid, &gid_flags); - else if (inc_recurse && (!am_root || !numeric_ids)) + else if (inc_recurse && (!am_root || !numeric_ids || groupmap)) gid = match_gid(gid, &gid_flags); } } @@ -1123,8 +1125,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, if (sanitize_paths) sanitize_path(thisname, thisname, "", 0, SP_DEFAULT); - if (stp && S_ISDIR(stp->st_mode)) { - st = *stp; /* Needed for "symlink/." with --relative. */ + if (stp && (S_ISDIR(stp->st_mode) || stp->st_mode == 0)) { + /* This is needed to handle a "symlink/." with a --relative + * dir, or a request to delete a specific file. */ + st = *stp; *linkname = '\0'; /* make IBM code checker happy */ } else if (readlink_stat(thisname, &st, linkname) != 0) { int save_errno = errno; @@ -1165,6 +1169,11 @@ struct file_struct *make_file(const char *fname, struct file_list *flist, full_fname(thisname)); } return NULL; + } else if (st.st_mode == 0) { + io_error |= IOERR_GENERAL; + rprintf(FINFO, "skipping file with bogus (zero) st_mode: %s\n", + full_fname(thisname)); + return NULL; } if (filter_level == NO_FILTERS) @@ -1363,7 +1372,7 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, if (!file) return NULL; - if (chmod_modes && !S_ISLNK(file->mode)) + if (chmod_modes && !S_ISLNK(file->mode) && file->mode) file->mode = tweak_mode(file->mode, chmod_modes); if (f >= 0) { @@ -1377,12 +1386,21 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, #endif #if defined SUPPORT_ACLS || defined SUPPORT_XATTRS stat_x sx; + init_stat_x(&sx); #endif #ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(file->mode)) { symlink_name = F_SYMLINK(file); symlink_len = strlen(symlink_name); + if (symlink_len == 0) { + io_error |= IOERR_GENERAL; + f_name(file, fbuf); + rprintf(FERROR_XFER, + "skipping symlink with 0-length value: %s\n", + full_fname(fbuf)); + return NULL; + } } else { symlink_name = NULL; symlink_len = 0; @@ -1440,7 +1458,6 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, #ifdef SUPPORT_ACLS 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) { io_error |= IOERR_GENERAL; return NULL; @@ -1449,7 +1466,6 @@ static struct file_struct *send_file_name(int f, struct file_list *flist, #endif #ifdef SUPPORT_XATTRS if (preserve_xattrs) { - sx.xattr = NULL; if (get_xattr(fname, &sx) < 0) { io_error |= IOERR_GENERAL; return NULL; @@ -1619,6 +1635,19 @@ static void add_dirs_to_tree(int parent_ndx, struct file_list *from_flist, DIR_NEXT_SIBLING(dp) = -1; } +static void interpret_stat_error(const char *fname, int is_dir) +{ + if (errno == ENOENT) { + io_error |= IOERR_VANISHED; + rprintf(FWARNING, "%s has vanished: %s\n", + is_dir ? "directory" : "file", full_fname(fname)); + } else { + io_error |= IOERR_GENERAL; + rsyserr(FERROR_XFER, errno, "link_stat %s failed", + full_fname(fname)); + } +} + /* This function is normally called by the sender, but the receiving side also * calls it from get_dirlist() with f set to -1 so that we just construct the * file list in memory without sending it over the wire. Also, get_dirlist() @@ -1638,6 +1667,11 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len, assert(flist != NULL); if (!(d = opendir(fbuf))) { + if (errno == ENOENT) { + if (am_sender) /* Can abuse this for vanished error w/ENOENT: */ + interpret_stat_error(fbuf, True); + return; + } io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, errno, "opendir %s failed", full_fname(fbuf)); return; @@ -1809,9 +1843,7 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist) if (one_file_system) { STRUCT_STAT st; if (link_stat(fbuf, &st, copy_dirlinks) != 0) { - io_error |= IOERR_GENERAL; - rsyserr(FERROR_XFER, errno, "link_stat %s failed", - full_fname(fbuf)); + interpret_stat_error(fbuf, True); return; } filesystem_dev = st.st_dev; @@ -1846,9 +1878,7 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist) if (name_type != NORMAL_NAME) { STRUCT_STAT st; if (link_stat(fbuf, &st, 1) != 0) { - io_error |= IOERR_GENERAL; - rsyserr(FERROR_XFER, errno, "link_stat %s failed", - full_fname(fbuf)); + interpret_stat_error(fbuf, True); continue; } send_file_name(f, flist, fbuf, &st, FLAG_TOP_DIR | flags, ALL_FILTERS); @@ -1913,7 +1943,7 @@ void send_extra_file_list(int f, int at_least) write_byte(f, 0); else { write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); - write_int(f, io_error); + write_varint(f, io_error); } if (need_unsorted_flist) { @@ -2147,10 +2177,15 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (link_stat(fbuf, &st, copy_dirlinks || name_type != NORMAL_NAME) != 0 || (name_type != DOTDIR_NAME && is_daemon_excluded(fbuf, S_ISDIR(st.st_mode))) || (relative_paths && path_is_daemon_excluded(fbuf, 1))) { - io_error |= IOERR_GENERAL; - rsyserr(FERROR_XFER, errno, "link_stat %s failed", - full_fname(fbuf)); - continue; + if (errno == ENOENT && delete_missing_args) { + /* Rsync will treat a mode of 0 as deleted. */ + memset(&st, 0, sizeof st); + } else { + io_error |= IOERR_GENERAL; + rsyserr(FERROR_XFER, errno, "link_stat %s failed", + full_fname(fbuf)); + continue; + } } /* A dot-dir should not be excluded! */ @@ -2216,7 +2251,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) write_byte(f, 0); else { write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST); - write_int(f, io_error); + write_varint(f, io_error); } #ifdef SUPPORT_HARD_LINKS @@ -2252,6 +2287,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) if (numeric_ids <= 0 && !inc_recurse) send_id_list(f); + set_msg_fd_in(-1); + /* send the io_error flag */ if (protocol_version < 30) write_int(f, ignore_errors ? 0 : io_error); @@ -2286,7 +2323,8 @@ struct file_list *send_file_list(int f, int argc, char *argv[]) * file-list to check if this is a 1-file xfer. */ send_extra_file_list(f, 1); } - } + } else + flist_eof = 1; return flist; } @@ -2303,6 +2341,10 @@ struct file_list *recv_file_list(int f) else if (inc_recurse && INFO_GTE(FLIST, 1) && !am_server) rprintf(FCLIENT, "receiving incremental file list\n"); rprintf(FLOG, "receiving file list\n"); + if (usermap) + parse_name_map(usermap, True); + if (groupmap) + parse_name_map(groupmap, False); } start_read = stats.total_read; @@ -2335,7 +2377,7 @@ struct file_list *recv_file_list(int f) rprintf(FERROR, "Invalid flist flag: %x\n", flags); exit_cleanup(RERR_PROTOCOL); } - err = read_int(f); + err = read_varint(f); if (!ignore_errors) io_error |= err; break; @@ -2408,8 +2450,10 @@ struct file_list *recv_file_list(int f) if (inc_recurse) flist_done_allocating(flist); - else if (f >= 0) + else if (f >= 0) { recv_id_list(f, flist); + flist_eof = 1; + } flist_sort_and_clean(flist, relative_paths);