📄 flist.c
字号:
/* Read the symlink data into the end of our double-sized * buffer and then convert it into the right spot. */ INIT_XBUF(inbuf, bp + alloc_len - linkname_len, linkname_len - 1, (size_t)-1); read_sbuf(f, inbuf.buf, inbuf.len); INIT_XBUF(outbuf, bp, 0, alloc_len); if (iconvbufs(ic_recv, &inbuf, &outbuf, 0) < 0) { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "[%s] cannot convert symlink data for: %s (%s)\n", who_am_i(), full_fname(thisname), strerror(errno)); bp = (char*)file->basename; *bp++ = '\0'; outbuf.len = 0; } bp[outbuf.len] = '\0'; } else#endif read_sbuf(f, bp, linkname_len - 1); if (sanitize_paths && !munge_symlinks && *bp) sanitize_path(bp, bp, "", lastdir_depth, SP_DEFAULT); } }#endif#ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && xflags & XMIT_HLINKED) { if (protocol_version >= 30) { if (xflags & XMIT_HLINK_FIRST) { F_HL_GNUM(file) = flist->ndx_start + flist->used; } else F_HL_GNUM(file) = first_hlink_ndx; } else { static int32 cnt = 0; struct ht_int64_node *np; int64 ino; int32 ndx; if (protocol_version < 26) { dev = read_int(f); ino = read_int(f); } else { if (!(xflags & XMIT_SAME_DEV_pre30)) dev = read_longint(f); ino = read_longint(f); } np = idev_find(dev, ino); ndx = (int32)(long)np->data - 1; if (ndx < 0) { ndx = cnt++; np->data = (void*)(long)cnt; } F_HL_GNUM(file) = ndx; } }#endif if (always_checksum && (S_ISREG(mode) || protocol_version < 28)) { if (S_ISREG(mode)) bp = F_SUM(file); else { /* Prior to 28, we get a useless set of nulls. */ bp = tmp_sum; } if (first_hlink_ndx >= flist->ndx_start) { struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start]; memcpy(bp, F_SUM(first), checksum_len); } else read_buf(f, bp, checksum_len); }#ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(mode)) receive_acl(file, f);#endif#ifdef SUPPORT_XATTRS if (preserve_xattrs) receive_xattr(file, f );#endif if (S_ISREG(mode) || S_ISLNK(mode)) stats.total_size += file_length; return file;}/* Create a file_struct for a named file by reading its stat() information * and performing extensive checks against global options. * * Returns a pointer to the new file struct, or NULL if there was an error * or this file should be excluded. * * Note: Any error (here or in send_file_name) that results in the omission of * an existent source file from the file list should set * "io_error |= IOERR_GENERAL" to avoid deletion of the file from the * destination if --delete is on. */struct file_struct *make_file(const char *fname, struct file_list *flist, STRUCT_STAT *stp, int flags, int filter_level){ static char *lastdir; static int lastdir_len = -1; struct file_struct *file; char thisname[MAXPATHLEN]; char linkname[MAXPATHLEN]; int alloc_len, basename_len, linkname_len; int extra_len = file_extra_cnt * EXTRA_LEN; const char *basename; alloc_pool_t *pool; STRUCT_STAT st; char *bp; if (strlcpy(thisname, fname, sizeof thisname) >= sizeof thisname) { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "skipping overly long name: %s\n", fname); return NULL; } clean_fname(thisname, 0); if (sanitize_paths) sanitize_path(thisname, thisname, "", 0, SP_DEFAULT); if (stp && S_ISDIR(stp->st_mode)) { st = *stp; /* Needed for "symlink/." with --relative. */ *linkname = '\0'; /* make IBM code checker happy */ } else if (readlink_stat(thisname, &st, linkname) != 0) { int save_errno = errno; /* See if file is excluded before reporting an error. */ if (filter_level != NO_FILTERS && (is_excluded(thisname, 0, filter_level) || is_excluded(thisname, 1, filter_level))) { if (ignore_perishable && save_errno != ENOENT) non_perishable_cnt++; return NULL; } if (save_errno == ENOENT) {#ifdef SUPPORT_LINKS /* When our options tell us to follow a symlink that * points nowhere, tell the user about the symlink * instead of giving a "vanished" message. We only * dereference a symlink if one of the --copy*links * options was specified, so there's no need for the * extra lstat() if one of these options isn't on. */ if ((copy_links || copy_unsafe_links || copy_dirlinks) && x_lstat(thisname, &st, NULL) == 0 && S_ISLNK(st.st_mode)) { io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "symlink has no referent: %s\n", full_fname(thisname)); } else#endif { enum logcode c = am_daemon && protocol_version < 28 ? FERROR : FWARNING; io_error |= IOERR_VANISHED; rprintf(c, "file has vanished: %s\n", full_fname(thisname)); } } else { io_error |= IOERR_GENERAL; rsyserr(FERROR_XFER, save_errno, "readlink_stat(%s) failed", full_fname(thisname)); } return NULL; } if (filter_level == NO_FILTERS) goto skip_filters; if (S_ISDIR(st.st_mode)) { if (!xfer_dirs) { rprintf(FINFO, "skipping directory %s\n", thisname); return NULL; } /* -x only affects dirs because we need to avoid recursing * into a mount-point directory, not to avoid copying a * symlinked file if -L (or similar) was specified. */ if (one_file_system && st.st_dev != filesystem_dev && BITS_SETnUNSET(flags, FLAG_CONTENT_DIR, FLAG_TOP_DIR)) { if (one_file_system > 1) { if (verbose > 1) { rprintf(FINFO, "[%s] skipping mount-point dir %s\n", who_am_i(), thisname); } return NULL; } flags |= FLAG_MOUNT_DIR; flags &= ~FLAG_CONTENT_DIR; } } else flags &= ~FLAG_CONTENT_DIR; if (is_excluded(thisname, S_ISDIR(st.st_mode) != 0, filter_level)) { if (ignore_perishable) non_perishable_cnt++; return NULL; } if (lp_ignore_nonreadable(module_id)) {#ifdef SUPPORT_LINKS if (!S_ISLNK(st.st_mode))#endif if (access(thisname, R_OK) != 0) return NULL; } skip_filters: /* Only divert a directory in the main transfer. */ if (flist) { if (flist->prev && S_ISDIR(st.st_mode) && flags & FLAG_DIVERT_DIRS) { /* Room for parent/sibling/next-child info. */ extra_len += DIRNODE_EXTRA_CNT * EXTRA_LEN; if (relative_paths) extra_len += PTR_EXTRA_CNT * EXTRA_LEN; pool = dir_flist->file_pool; } else pool = flist->file_pool; } 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", who_am_i(), thisname, filter_level); } if ((basename = strrchr(thisname, '/')) != NULL) { int len = basename++ - thisname; if (len != lastdir_len || memcmp(thisname, lastdir, len) != 0) { lastdir = new_array(char, len + 1); memcpy(lastdir, thisname, len); lastdir[len] = '\0'; lastdir_len = len; } } else basename = thisname; basename_len = strlen(basename) + 1; /* count the '\0' */#ifdef SUPPORT_LINKS linkname_len = S_ISLNK(st.st_mode) ? strlen(linkname) + 1 : 0;#else linkname_len = 0;#endif#if SIZEOF_CAPITAL_OFF_T >= 8 if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) extra_len += EXTRA_LEN;#endif#if EXTRA_ROUNDING > 0 if (extra_len & (EXTRA_ROUNDING * EXTRA_LEN)) extra_len = (extra_len | (EXTRA_ROUNDING * EXTRA_LEN)) + EXTRA_LEN;#endif alloc_len = FILE_STRUCT_LEN + extra_len + basename_len + linkname_len; if (pool) bp = pool_alloc(pool, alloc_len, "make_file"); else { if (!(bp = new_array(char, alloc_len))) out_of_memory("make_file"); } memset(bp, 0, extra_len + FILE_STRUCT_LEN); bp += extra_len; file = (struct file_struct *)bp; bp += FILE_STRUCT_LEN; memcpy(bp, basename, basename_len);#ifdef SUPPORT_HARD_LINKS if (preserve_hard_links && flist && flist->prev) { if (protocol_version >= 28 ? (!S_ISDIR(st.st_mode) && st.st_nlink > 1) : S_ISREG(st.st_mode)) { tmp_dev = (int64)st.st_dev + 1; tmp_ino = (int64)st.st_ino; } else tmp_dev = 0; }#endif#ifdef HAVE_STRUCT_STAT_ST_RDEV if (IS_DEVICE(st.st_mode) || IS_SPECIAL(st.st_mode)) { tmp_rdev = st.st_rdev; st.st_size = 0; }#endif file->flags = flags; file->modtime = st.st_mtime; file->len32 = (uint32)st.st_size;#if SIZEOF_CAPITAL_OFF_T >= 8 if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode)) { file->flags |= FLAG_LENGTH64; OPT_EXTRA(file, 0)->unum = (uint32)(st.st_size >> 32); }#endif file->mode = st.st_mode; if (uid_ndx) /* Check uid_ndx instead of preserve_uid for del support */ F_OWNER(file) = st.st_uid; 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) 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); if (am_sender) F_PATHNAME(file) = pathname; else if (!pool) F_DEPTH(file) = extra_len / EXTRA_LEN; if (basename_len == 0+1) { if (!pool) unmake_file(file); return NULL; } if (unsort_ndx) F_NDX(file) = dir_count; return file;}/* Only called for temporary file_struct entries created by make_file(). */void unmake_file(struct file_struct *file){ free(REQ_EXTRA(file, F_DEPTH(file)));}static struct file_struct *send_file_name(int f, struct file_list *flist, const char *fname, STRUCT_STAT *stp, int flags, int filter_level){ struct file_struct *file; file = make_file(fname, flist, stp, flags, filter_level); if (!file) return NULL; if (chmod_modes && !S_ISLNK(file->mode)) file->mode = tweak_mode(file->mode, chmod_modes); if (f >= 0) { char fbuf[MAXPATHLEN];#ifdef SUPPORT_LINKS const char *symlink_name; int symlink_len;#ifdef ICONV_OPTION char symlink_buf[MAXPATHLEN];#endif#endif#if defined SUPPORT_ACLS || defined SUPPORT_XATTRS stat_x sx;#endif#ifdef SUPPORT_LINKS if (preserve_links && S_ISLNK(file->mode)) { symlink_name = F_SYMLINK(file); symlink_len = strlen(symlink_name); } else { symlink_name = NULL; symlink_len = 0; }#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; fbuf[outbuf.len++] = '/'; } INIT_XBUF_STRLEN(inbuf, (char*)file->basename); if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) { convert_error: io_error |= IOERR_GENERAL; rprintf(FERROR_XFER, "[%s] cannot convert filename: %s (%s)\n", who_am_i(), f_name(file, fbuf), strerror(errno)); return NULL; } fbuf[outbuf.len] = '\0';#ifdef SUPPORT_LINKS if (symlink_len && sender_symlink_iconv) { INIT_XBUF(inbuf, (char*)symlink_name, symlink_len, (size_t)-1); INIT_CONST_XBUF(outbuf, symlink_buf); if (iconvbufs(ic_send, &inbuf, &outbuf, 0) < 0) { io_error |= IOERR_GENERAL; f_name(file, fbuf); rprintf(FERROR_XFER, "[%s] cannot convert symlink data for: %s (%s)\n", who_am_i(), full_fname(fbuf), strerror(errno)); return NULL; } symlink_buf[outbuf.len] = '\0'; symlink_name = symlink_buf; symlink_len = outbuf.len; }#endif } else#endif f_name(file, fbuf);#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; } }#endif#ifdef SUPPORT_XATTRS if (preserve_xattrs) { sx.xattr = NULL; if (get_xattr(fname, &sx) < 0) { io_error |= IOERR_GENERAL; return NULL; } }#endif send_file_entry(f, fbuf, file,#ifdef SUPPORT_LINKS symlink_name, symlink_len,#endif flist->used, flist->ndx_start);#ifdef SUPPORT_ACLS if (preserve_acls && !S_ISLNK(file->mode)) { send_acl(&sx, f); free_acl(&sx); }#endif#ifdef SUPPORT_XATTRS if (preserve_xattrs) { F_XATTR(file) = send_xattr(&sx, f); free_xattr(&sx); }#endif } maybe_emit_filelist_progress(flist->used + flist_count_offset); flist_expand(flist, 1); flist->files[flist->used++] = file; return file;}static void send_if_directory(int f, struct file_list *flist, struct file_struct *file, char *fbuf, unsigned int ol, int flags){ char is_dot_dir = fbuf[ol-1] == '.' && (ol == 1 || fbuf[ol-2] == '/'); if (S_ISDIR(file->mode) && !(file->flags & FLAG_MOUNT_DIR) && f_name(file, fbuf)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -