📄 generator.c
字号:
struct file_list *dirlist; char delbuf[MAXPATHLEN]; int dlen, i; int save_uid_ndx = uid_ndx; if (!fbuf) { change_local_filter_dir(NULL, 0, 0); return; } if (verbose > 2) rprintf(FINFO, "delete_in_dir(%s)\n", fbuf); if (allowed_lull) maybe_send_keepalive(); if (io_error && !ignore_errors) { if (already_warned) return; rprintf(FINFO, "IO error encountered -- skipping file deletion\n"); already_warned = 1; return; } dlen = strlen(fbuf); change_local_filter_dir(fbuf, dlen, F_DEPTH(file)); if (one_file_system) { if (file->flags & FLAG_TOP_DIR) filesystem_dev = *fs_dev; else if (filesystem_dev != *fs_dev) return; } if (!uid_ndx) uid_ndx = ++file_extra_cnt; dirlist = get_dirlist(fbuf, dlen, 0); /* If an item in dirlist is not found in flist, delete it * from the filesystem. */ for (i = dirlist->used; i--; ) { struct file_struct *fp = dirlist->files[i]; if (!F_IS_ACTIVE(fp)) continue; if (fp->flags & FLAG_MOUNT_DIR && S_ISDIR(fp->mode)) { if (verbose > 1) rprintf(FINFO, "cannot delete mount point: %s\n", f_name(fp, NULL)); continue; } /* Here we want to match regardless of file type. Replacement * of a file with one of another type is handled separately by * a delete_item call with a DEL_MAKE_ROOM flag. */ if (flist_find_ignore_dirness(cur_flist, fp) < 0) { int flags = DEL_RECURSE; if (!(fp->mode & S_IWUSR) && !am_root && (uid_t)F_OWNER(fp) == our_uid) flags |= DEL_NO_UID_WRITE; f_name(fp, delbuf); if (delete_during == 2) { if (!remember_delete(fp, delbuf, flags)) break; } else delete_item(delbuf, fp->mode, flags); } } flist_free(dirlist); if (!save_uid_ndx) { --file_extra_cnt; uid_ndx = 0; }}/* 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(void){ char fbuf[MAXPATHLEN]; STRUCT_STAT st; int j; /* dry_run is incremented when the destination doesn't exist yet. */ if (dry_run > 1 || list_only) return; for (j = 0; j < cur_flist->used; j++) { struct file_struct *file = cur_flist->sorted[j]; f_name(file, fbuf); if (!(file->flags & FLAG_CONTENT_DIR)) { change_local_filter_dir(fbuf, strlen(fbuf), F_DEPTH(file)); continue; } if (verbose > 1 && file->flags & FLAG_TOP_DIR) rprintf(FINFO, "deleting in %s\n", fbuf); if (link_stat(fbuf, &st, keep_dirlinks) < 0 || !S_ISDIR(st.st_mode)) continue; delete_in_dir(fbuf, file, &st.st_dev); } delete_in_dir(NULL, NULL, &dev_zero); if (do_progress && !am_server) rprintf(FINFO, " \r");}int unchanged_attrs(const char *fname, struct file_struct *file, stat_x *sxp){#if !defined HAVE_LUTIMES || !defined HAVE_UTIMES if (S_ISLNK(file->mode)) { ; } else#endif if (preserve_times && cmp_time(sxp->st.st_mtime, file->modtime) != 0) return 0; if (preserve_perms) { if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS)) return 0; } else if (preserve_executability && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0))) return 0; if (am_root && uid_ndx && sxp->st.st_uid != (uid_t)F_OWNER(file)) return 0; if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file)) return 0;#ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { if (!ACL_READY(*sxp)) get_acl(fname, sxp); if (set_acl(NULL, file, sxp) == 0) 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 *fnamecmp, struct file_struct *file, int ndx, int statret, stat_x *sxp, int32 iflags, uchar fnamecmp_type, const char *xname){ if (statret >= 0) { /* A from-dest-dir statret can == 1! */ int keep_time = !preserve_times ? 0 : S_ISDIR(file->mode) ? preserve_times > 1 :#if defined HAVE_LUTIMES && defined HAVE_UTIMES 1;#else !S_ISLNK(file->mode);#endif if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size) iflags |= ITEM_REPORT_SIZE; if (file->flags & FLAG_TIME_FAILED) { /* symlinks only */ if (iflags & ITEM_LOCAL_CHANGE) iflags |= symlink_timeset_failed_flags; } else if (keep_time ? cmp_time(file->modtime, sxp->st.st_mtime) != 0 : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED) && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname)) iflags |= ITEM_REPORT_TIME;#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST if (S_ISLNK(file->mode)) { ; } else#endif if (preserve_perms) { if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS)) iflags |= ITEM_REPORT_PERMS; } else if (preserve_executability && ((sxp->st.st_mode & 0111 ? 1 : 0) ^ (file->mode & 0111 ? 1 : 0))) iflags |= ITEM_REPORT_PERMS; if (uid_ndx && am_root && (uid_t)F_OWNER(file) != sxp->st.st_uid) iflags |= ITEM_REPORT_OWNER; if (gid_ndx && !(file->flags & FLAG_SKIP_GROUP) && sxp->st.st_gid != (gid_t)F_GROUP(file)) iflags |= ITEM_REPORT_GROUP;#ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { if (!ACL_READY(*sxp)) get_acl(fnamecmp, sxp); if (set_acl(NULL, file, sxp) == 0) iflags |= ITEM_REPORT_ACL; }#endif#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|ITEM_REPORT_XATTR) || verbose > 1 || stdout_format_has_i > 1 || (xname && *xname)) && !read_batch) { if (protocol_version >= 29) { if (ndx >= 0) write_ndx(sock_f_out, ndx); write_shortint(sock_f_out, iflags); if (iflags & ITEM_BASIS_TYPE_FOLLOWS) write_byte(sock_f_out, fnamecmp_type); if (iflags & ITEM_XNAME_FOLLOWS) write_vstring(sock_f_out, xname, strlen(xname));#ifdef SUPPORT_XATTRS if (preserve_xattrs && !dry_run && iflags & (ITEM_REPORT_XATTR|ITEM_TRANSFER)) { send_xattr_request(NULL, file, iflags & ITEM_REPORT_XATTR ? sock_f_out : -1); }#endif } else if (ndx >= 0) { enum logcode code = logfile_format_has_i ? FINFO : FCLIENT; log_item(code, file, &stats, iflags, xname); } }}/* Perform our quick-check heuristic for determining if a file is unchanged. */int unchanged_file(char *fn, struct file_struct *file, STRUCT_STAT *st){ if (st->st_size != F_LENGTH(file)) return 0; /* 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[MAX_DIGEST_LEN]; file_checksum(fn, sum, st->st_size); return memcmp(sum, F_SUM(file), checksum_len) == 0; } if (size_only > 0) return 1; if (ignore_times) return 0; return cmp_time(st->st_mtime, file->modtime) == 0;}/* * set (initialize) the size entries in the per-file sum_struct * calculating dynamic block and checksum sizes. * * This is only called from generate_and_send_sums() but is a separate * function to encapsulate the logic. * * The block size is a rounded square root of file length. * * The checksum size is determined according to: * blocksum_bits = BLOCKSUM_BIAS + 2*log2(file_len) - log2(block_len) * provided by Donovan Baarda which gives a probability of rsync * algorithm corrupting data and falling back using the whole md4 * checksums. * * This might be made one of several selectable heuristics. */static void sum_sizes_sqroot(struct sum_struct *sum, int64 len){ int32 blength; int s2length; int64 l; if (block_size) blength = block_size; else if (len <= BLOCK_SIZE * BLOCK_SIZE) blength = BLOCK_SIZE; else { int32 max_blength = protocol_version < 30 ? OLD_MAX_BLOCK_SIZE : MAX_BLOCK_SIZE; int32 c; int cnt; for (c = 1, l = len, cnt = 0; l >>= 2; c <<= 1, cnt++) {} if (c < 0 || c >= max_blength) blength = max_blength; else { blength = 0; do { blength |= c; if (len < (int64)blength * blength) blength &= ~c; c >>= 1; } while (c >= 8); /* round to multiple of 8 */ blength = MAX(blength, BLOCK_SIZE); } } if (protocol_version < 27) { s2length = csum_length; } else if (csum_length == SUM_LENGTH) { s2length = SUM_LENGTH; } else { int32 c; int b = BLOCKSUM_BIAS; for (l = len; l >>= 1; b += 2) {} for (c = blength; (c >>= 1) && b; b--) {} /* add a bit, subtract rollsum, round up. */ s2length = (b + 1 - 32 + 7) / 8; /* --optimize in compiler-- */ s2length = MAX(s2length, csum_length); s2length = MIN(s2length, SUM_LENGTH); } sum->flength = len; sum->blength = blength; sum->s2length = s2length; sum->remainder = (int32)(len % blength); sum->count = (int32)(l = (len / blength) + (sum->remainder != 0)); if ((int64)sum->count != l) sum->count = -1; if (sum->count && verbose > 2) { rprintf(FINFO, "count=%.0f rem=%ld blength=%ld s2length=%d flength=%.0f\n", (double)sum->count, (long)sum->remainder, (long)sum->blength, sum->s2length, (double)sum->flength); }}/* * Generate and send a stream of signatures/checksums that describe a buffer * * Generate approximately one checksum every block_len bytes. */static int generate_and_send_sums(int fd, OFF_T len, int f_out, int f_copy){ int32 i; struct map_struct *mapbuf; struct sum_struct sum; OFF_T offset = 0; sum_sizes_sqroot(&sum, len); if (sum.count < 0) return -1; write_sum_head(f_out, &sum); if (append_mode > 0 && f_copy < 0) return 0; if (len > 0) mapbuf = map_file(fd, len, MAX_MAP_SIZE, sum.blength); else mapbuf = NULL; for (i = 0; i < sum.count; i++) { int32 n1 = (int32)MIN(len, (OFF_T)sum.blength); char *map = map_ptr(mapbuf, offset, n1); char sum2[SUM_LENGTH]; uint32 sum1; len -= n1; offset += n1; if (f_copy >= 0) { full_write(f_copy, map, n1); if (append_mode > 0) continue; } sum1 = get_checksum1(map, n1); get_checksum2(map, n1, sum2); if (verbose > 3) { rprintf(FINFO, "chunk[%.0f] offset=%.0f len=%ld sum1=%08lx\n", (double)i, (double)offset - n1, (long)n1, (unsigned long)sum1); } write_int(f_out, sum1); write_buf(f_out, sum2, sum.s2length); } if (mapbuf) unmap_file(mapbuf); return 0;}/* Try to find a filename in the same dir as "fname" with a similar name. */static int find_fuzzy(struct file_struct *file, struct file_list *dirlist){ int fname_len, fname_suf_len; const char *fname_suf, *fname = file->basename; uint32 lowest_dist = 25 << 16; /* ignore a distance greater than 25 */ int j, lowest_j = -1; fname_len = strlen(fname); fname_suf = find_filename_suffix(fname, fname_len, &fname_suf_len); for (j = 0; j < dirlist->used; j++) { struct file_struct *fp = dirlist->files[j]; const char *suf, *name; int len, suf_len; uint32 dist; if (!S_ISREG(fp->mode) || !F_LENGTH(fp) || fp->flags & FLAG_FILE_SENT) continue; name = fp->basename; if (F_LENGTH(fp) == F_LENGTH(file) && cmp_time(fp->modtime, file->modtime) == 0) { if (verbose > 4) { rprintf(FINFO, "fuzzy size/modtime match for %s\n", name); } return j; } len = strlen(name); suf = find_filename_suffix(name, len, &suf_len); dist = fuzzy_distance(name, len, fname, fname_len); /* Add some extra weight to how well the suffixes match. */ dist += fuzzy_distance(suf, suf_len, fname_suf, fname_suf_len) * 10; if (verbose > 4) { rprintf(FINFO, "fuzzy distance for %s = %d.%05d\n", name, (int)(dist>>16), (int)(dist&0xFFFF)); } if (dist <= lowest_dist) { lowest_dist = dist; lowest_j = j; } } return lowest_j;}/* Copy a file found in our --copy-dest handling. */static int copy_altdest_file(const char *src, const char *dest, struct file_struct *file){ char buf[MAXPATHLEN]; const char *copy_to, *partialptr; int save_preserve_xattrs = preserve_xattrs; int ok, fd_w; if (inplace) { /* Let copy_file open the destination in place. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -