📄 generator.c
字号:
fd_w = -1; copy_to = dest; } else { fd_w = open_tmpfile(buf, dest, file); if (fd_w < 0) return -1; copy_to = buf; } cleanup_set(copy_to, NULL, NULL, -1, -1); if (copy_file(src, copy_to, fd_w, file->mode, 0) < 0) { if (verbose) { rsyserr(FINFO, errno, "copy_file %s => %s", full_fname(src), copy_to); } /* Try to clean up. */ unlink(copy_to); cleanup_disable(); return -1; } partialptr = partial_dir ? partial_dir_fname(dest) : NULL; preserve_xattrs = 0; /* xattrs were copied with file */ ok = finish_transfer(dest, copy_to, src, partialptr, file, 1, 0); preserve_xattrs = save_preserve_xattrs; cleanup_disable(); return ok ? 0 : -1;}/* This is only called for regular files. We return -2 if we've finished * handling the file, -1 if no dest-linking occurred, or a non-negative * value if we found an alternate basis file. */static int try_dests_reg(struct file_struct *file, char *fname, int ndx, char *cmpbuf, stat_x *sxp, int itemizing, enum logcode code){ int best_match = -1; int match_level = 0; int j = 0; do { pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode)) continue; switch (match_level) { case 0: best_match = j; match_level = 1; /* FALL THROUGH */ case 1: if (!unchanged_file(cmpbuf, file, &sxp->st)) continue; best_match = j; match_level = 2; /* FALL THROUGH */ case 2: if (!unchanged_attrs(cmpbuf, file, sxp)) continue; best_match = j; match_level = 3; break; } break; } while (basis_dir[++j] != NULL); if (!match_level) return -1; if (j != best_match) { j = best_match; pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &sxp->st, 0) < 0) return -1; } if (match_level == 3 && !copy_dest) {#ifdef SUPPORT_HARD_LINKS if (link_dest) { if (!hard_link_one(file, fname, cmpbuf, 1)) goto try_a_copy; if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j); if (!maybe_ATTRS_REPORT && (verbose > 1 || stdout_format_has_i > 1)) { itemize(cmpbuf, file, ndx, 1, sxp, ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0, ""); } } else#endif if (itemizing) itemize(cmpbuf, file, ndx, 0, sxp, 0, 0, NULL); if (verbose > 1 && maybe_ATTRS_REPORT) rprintf(FCLIENT, "%s is uptodate\n", fname); return -2; } if (match_level >= 2) {#ifdef SUPPORT_HARD_LINKS try_a_copy: /* Copy the file locally. */#endif if (!dry_run && copy_altdest_file(cmpbuf, fname, file) < 0) return -1; if (itemizing) itemize(cmpbuf, file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL); if (maybe_ATTRS_REPORT && ((!itemizing && verbose && match_level == 2) || (verbose > 1 && match_level == 3))) { code = match_level == 3 ? FCLIENT : FINFO; rprintf(code, "%s%s\n", fname, match_level == 3 ? " is uptodate" : ""); }#ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, -1);#endif return -2; } return FNAMECMP_BASIS_DIR_LOW + j;}/* This is only called for non-regular files. We return -2 if we've finished * handling the file, or -1 if no dest-linking occurred, or a non-negative * value if we found an alternate basis file. */static int try_dests_non(struct file_struct *file, char *fname, int ndx, char *cmpbuf, stat_x *sxp, int itemizing, enum logcode code){ char lnk[MAXPATHLEN]; int best_match = -1; int match_level = 0; enum nonregtype type; uint32 *devp; int len, j = 0;#ifndef SUPPORT_LINKS if (S_ISLNK(file->mode)) return -1;#endif if (S_ISDIR(file->mode)) { type = TYPE_DIR; } else if (IS_SPECIAL(file->mode)) type = TYPE_SPECIAL; else if (IS_DEVICE(file->mode)) type = TYPE_DEVICE;#ifdef SUPPORT_LINKS else if (S_ISLNK(file->mode)) type = TYPE_SYMLINK;#endif else { rprintf(FERROR, "internal: try_dests_non() called with invalid mode (%o)\n", (int)file->mode); exit_cleanup(RERR_UNSUPPORTED); } do { pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &sxp->st, 0) < 0) continue; switch (type) { case TYPE_DIR: if (!S_ISDIR(sxp->st.st_mode)) continue; break; case TYPE_SPECIAL: if (!IS_SPECIAL(sxp->st.st_mode)) continue; break; case TYPE_DEVICE: if (!IS_DEVICE(sxp->st.st_mode)) continue; break;#ifdef SUPPORT_LINKS case TYPE_SYMLINK: if (!S_ISLNK(sxp->st.st_mode)) continue; break;#endif } if (match_level < 1) { match_level = 1; best_match = j; } switch (type) { case TYPE_DIR: break; case TYPE_SPECIAL: case TYPE_DEVICE: devp = F_RDEV_P(file); if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp))) continue; break;#ifdef SUPPORT_LINKS case TYPE_SYMLINK: if ((len = readlink(cmpbuf, lnk, MAXPATHLEN-1)) <= 0) continue; lnk[len] = '\0'; if (strcmp(lnk, F_SYMLINK(file)) != 0) continue; break;#endif } if (match_level < 2) { match_level = 2; best_match = j; } if (unchanged_attrs(cmpbuf, file, sxp)) { match_level = 3; best_match = j; break; } } while (basis_dir[++j] != NULL); if (!match_level) return -1; if (j != best_match) { j = best_match; pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname); if (link_stat(cmpbuf, &sxp->st, 0) < 0) return -1; } if (match_level == 3) {#ifdef SUPPORT_HARD_LINKS if (link_dest#ifndef CAN_HARDLINK_SYMLINK && !S_ISLNK(file->mode)#endif#ifndef CAN_HARDLINK_SPECIAL && !IS_SPECIAL(file->mode) && !IS_DEVICE(file->mode)#endif && !S_ISDIR(file->mode)) { if (do_link(cmpbuf, fname) < 0) { rsyserr(FERROR_XFER, errno, "failed to hard-link %s with %s", cmpbuf, fname); return j; } if (preserve_hard_links && F_IS_HLINKED(file)) finish_hard_link(file, fname, ndx, NULL, itemizing, code, -1); } else#endif match_level = 2; if (itemizing && stdout_format_has_i && (verbose > 1 || stdout_format_has_i > 1)) { int chg = compare_dest && type != TYPE_DIR ? 0 : ITEM_LOCAL_CHANGE + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0); char *lp = match_level == 3 ? "" : NULL; itemize(cmpbuf, file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp); } if (verbose > 1 && maybe_ATTRS_REPORT) { rprintf(FCLIENT, "%s%s is uptodate\n", fname, type == TYPE_DIR ? "/" : ""); } return -2; } return j;}static void list_file_entry(struct file_struct *f){ char permbuf[PERMSTRING_SIZE]; double len; if (!F_IS_ACTIVE(f)) { /* this can happen if duplicate names were removed */ return; } permstring(permbuf, f->mode); len = F_LENGTH(f); /* TODO: indicate '+' if the entry has an ACL. */#ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(f->mode)) { rprintf(FINFO, "%s %11.0f %s %s -> %s\n", permbuf, len, timestring(f->modtime), f_name(f, NULL), F_SYMLINK(f)); } else#endif { rprintf(FINFO, "%s %11.0f %s %s\n", permbuf, len, timestring(f->modtime), f_name(f, NULL)); }}static int phase = 0;static int dflt_perms;static int implied_dirs_are_missing;/* Helper for recv_generator's skip_dir and dry_missing_dir tests. */static BOOL is_below(struct file_struct *file, struct file_struct *subtree){ return F_DEPTH(file) > F_DEPTH(subtree) && (!implied_dirs_are_missing || f_name_has_prefix(file, subtree));}/* Acts on the indicated item in cur_flist whose name is fname. If a dir, * make sure it exists, and has the right permissions/timestamp info. For * all other non-regular files (symlinks, etc.) we create them here. For * regular files that have changed, we try to find a basis file and then * start sending checksums. The ndx is the file's unique index value. * * The fname parameter must point to a MAXPATHLEN buffer! (e.g it gets * passed to delete_item(), which can use it during a recursive delete.) * * Note that f_out is set to -1 when doing final directory-permission and * modification-time repair. */static void recv_generator(char *fname, struct file_struct *file, int ndx, int itemizing, enum logcode code, int f_out){ static const char *parent_dirname = ""; /* Missing dir not created due to --dry-run; will still be scanned. */ static struct file_struct *dry_missing_dir = NULL; /* Missing dir whose contents are skipped altogether due to * --ignore-non-existing, daemon exclude, or mkdir failure. */ static struct file_struct *skip_dir = NULL; static struct file_list *fuzzy_dirlist = NULL; static int need_fuzzy_dirlist = 0; struct file_struct *fuzzy_file = NULL; int fd = -1, f_copy = -1; stat_x sx, real_sx; STRUCT_STAT partial_st; struct file_struct *back_file = NULL; int statret, real_ret, stat_errno; char *fnamecmp, *partialptr, *backupptr = NULL; char fnamecmpbuf[MAXPATHLEN]; uchar fnamecmp_type; int del_opts = delete_mode || force_delete ? DEL_RECURSE : 0; int is_dir = !S_ISDIR(file->mode) ? 0 : inc_recurse && ndx != cur_flist->ndx_start - 1 ? -1 : 1; if (verbose > 2) rprintf(FINFO, "recv_generator(%s,%d)\n", fname, ndx); if (list_only) { if (is_dir < 0 || (is_dir && !implied_dirs && file->flags & FLAG_IMPLIED_DIR)) return; list_file_entry(file); return; } if (skip_dir) { if (is_below(file, skip_dir)) { if (is_dir) file->flags |= FLAG_MISSING_DIR;#ifdef SUPPORT_HARD_LINKS else if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out);#endif return; } skip_dir = NULL; } if (daemon_filter_list.head && (*fname != '.' || fname[1])) { if (check_filter(&daemon_filter_list, FLOG, fname, is_dir) < 0) { if (is_dir < 0) return;#ifdef SUPPORT_HARD_LINKS if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out);#endif rprintf(FERROR_XFER, "skipping daemon-excluded %s \"%s\"\n", is_dir ? "directory" : "file", fname); if (is_dir) goto skipping_dir_contents; return; } }#ifdef SUPPORT_ACLS sx.acc_acl = sx.def_acl = NULL;#endif#ifdef SUPPORT_XATTRS sx.xattr = NULL;#endif if (dry_run > 1 || (dry_missing_dir && is_below(file, dry_missing_dir))) { parent_is_dry_missing: if (fuzzy_dirlist) { flist_free(fuzzy_dirlist); fuzzy_dirlist = NULL; } parent_dirname = ""; statret = -1; stat_errno = ENOENT; } else { const char *dn = file->dirname ? file->dirname : "."; dry_missing_dir = NULL; if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) { if (relative_paths && !implied_dirs && do_stat(dn, &sx.st) < 0) { if (dry_run) goto parent_is_dry_missing; if (create_directory_path(fname) < 0) { rsyserr(FERROR_XFER, errno, "recv_generator: mkdir %s failed", full_fname(dn)); } } if (fuzzy_dirlist) { flist_free(fuzzy_dirlist); fuzzy_dirlist = NULL; } if (fuzzy_basis) need_fuzzy_dirlist = 1;#ifdef SUPPORT_ACLS if (!preserve_perms) dflt_perms = default_perms_for_dir(dn);#endif } parent_dirname = dn; if (need_fuzzy_dirlist && S_ISREG(file->mode)) { strlcpy(fnamecmpbuf, dn, sizeof fnamecmpbuf); fuzzy_dirlist = get_dirlist(fnamecmpbuf, -1, 1); need_fuzzy_dirlist = 0; } statret = link_stat(fname, &sx.st, keep_dirlinks && is_dir); stat_errno = errno; } if (ignore_non_existing > 0 && statret == -1 && stat_errno == ENOENT) { if (is_dir) { if (is_dir < 0) return; skip_dir = file; file->flags |= FLAG_MISSING_DIR; }#ifdef SUPPORT_HARD_LINKS else if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out);#endif if (verbose > 1) { rprintf(FINFO, "not creating new %s \"%s\"\n", is_dir ? "directory" : "file", fname); } return; } if (statret == 0 && !(sx.st.st_mode & S_IWUSR) && !am_root && sx.st.st_uid == our_uid) del_opts |= DEL_NO_UID_WRITE; if (ignore_existing > 0 && statret == 0 && (!is_dir || !S_ISDIR(sx.st.st_mode))) { if (verbose > 1 && is_dir >= 0) rprintf(FINFO, "%s exists\n", fname);#ifdef SUPPORT_HARD_LINKS if (F_IS_HLINKED(file)) handle_skipped_hlink(file, itemizing, code, f_out);#endif goto cleanup; } if (is_dir) { if (!implied_dirs && file->flags & FLAG_IMPLIED_DIR) goto cleanup; if (is_dir < 0) { /* In inc_recurse mode we want to make sure any missing * directories get created while we're still processing * the parent dir (which allows us to touch the parent * dir's mtime right away). We will handle the dir in * full later (right before we handle its contents). */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -