* Copyright (C) 1996 Andrew Tridgell
* Copyright (C) 1996 Paul Mackerras
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2002-2020 Wayne Davison
+ * Copyright (C) 2002-2022 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
extern int am_generator;
extern int inc_recurse;
extern int always_checksum;
-extern int checksum_type;
extern int module_id;
extern int ignore_errors;
extern int numeric_ids;
extern int xfer_dirs;
extern int filesfrom_fd;
extern int one_file_system;
+extern int copy_devices;
extern int copy_dirlinks;
extern int preserve_uid;
extern int preserve_gid;
extern int missing_args;
extern int eol_nulls;
extern int atimes_ndx;
+extern int crtimes_ndx;
extern int relative_paths;
extern int implied_dirs;
extern int ignore_perishable;
extern int sender_symlink_iconv;
extern int output_needs_newline;
extern int sender_keeps_checksum;
+extern int trust_sender_filter;
extern int unsort_ndx;
extern uid_t our_uid;
extern struct stats stats;
extern char *filesfrom_host;
extern char *usermap, *groupmap;
+extern struct name_num_item *file_sum_nni;
+
extern char curr_dir[MAXPATHLEN];
extern struct chmod_mode_struct *chmod_modes;
-extern filter_rule_list filter_list;
-extern filter_rule_list daemon_filter_list;
+extern filter_rule_list filter_list, implied_filter_list, daemon_filter_list;
#ifdef ICONV_OPTION
extern int filesfrom_convert;
rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n",
(int)FILE_STRUCT_LEN, (int)EXTRA_LEN);
}
- flist_csum_len = csum_len_for_type(checksum_type, 1);
+ /* Note that this isn't identical to file_sum_len in the case of CSUM_MD4_ARCHAIC: */
+ flist_csum_len = csum_len_for_type(file_sum_nni->num, 1);
show_filelist_progress = INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
}
flist->malloced = FLIST_START;
else if (flist->malloced >= FLIST_LINEAR)
flist->malloced += FLIST_LINEAR;
+ else if (flist->malloced < FLIST_START_LARGE/16)
+ flist->malloced *= 4;
else
flist->malloced *= 2;
new_ptr = realloc_array(flist->files, struct file_struct *, flist->malloced);
- if (DEBUG_GTE(FLIST, 1) && flist->malloced != FLIST_START) {
+ if (DEBUG_GTE(FLIST, 1) && flist->files) {
rprintf(FCLIENT, "[%s] expand file_list pointer array to %s bytes, did%s move\n",
who_am_i(),
big_num(sizeof flist->files[0] * flist->malloced),
int ndx, int first_ndx)
{
static time_t modtime, atime;
+#ifdef SUPPORT_CRTIMES
+ static time_t crtime;
+#endif
static mode_t mode;
#ifdef SUPPORT_HARD_LINKS
static int64 dev;
if (protocol_version < 28)
xflags |= XMIT_SAME_RDEV_pre28;
else {
- rdev = MAKEDEV(major(rdev), 0);
+ rdev = MAKEDEV(rdev_major, 0);
xflags |= XMIT_SAME_RDEV_MAJOR;
if (protocol_version < 30)
xflags |= XMIT_RDEV_MINOR_8_pre30;
else
atime = F_ATIME(file);
}
+#ifdef SUPPORT_CRTIMES
+ if (crtimes_ndx) {
+ crtime = F_CRTIME(file);
+ if (crtime == modtime)
+ xflags |= XMIT_CRTIME_EQ_MTIME;
+ }
+#endif
#ifdef SUPPORT_HARD_LINKS
if (tmp_dev != -1) {
}
if (xflags & XMIT_MOD_NSEC)
write_varint(f, F_MOD_NSEC(file));
+#ifdef SUPPORT_CRTIMES
+ if (crtimes_ndx && !(xflags & XMIT_CRTIME_EQ_MTIME))
+ write_varlong(f, crtime, 4);
+#endif
if (!(xflags & XMIT_SAME_MODE))
write_int(f, to_wire_mode(mode));
if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME))
static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
{
static int64 modtime, atime;
+#ifdef SUPPORT_CRTIMES
+ static time_t crtime;
+#endif
static mode_t mode;
#ifdef SUPPORT_HARD_LINKS
static int64 dev;
int alloc_len, basename_len, linkname_len;
int extra_len = file_extra_cnt * EXTRA_LEN;
int first_hlink_ndx = -1;
+ char real_ISREG_entry;
int64 file_length;
#ifdef CAN_SET_NSEC
uint32 modtime_nsec;
if (*thisname
&& (clean_fname(thisname, CFN_REFUSE_DOT_DOT_DIRS) < 0 || (!relative_paths && *thisname == '/'))) {
rprintf(FERROR, "ABORTING due to unsafe pathname from sender: %s\n", thisname);
- exit_cleanup(RERR_PROTOCOL);
+ exit_cleanup(RERR_UNSUPPORTED);
}
if (sanitize_paths)
mode = first->mode;
if (atimes_ndx && !S_ISDIR(mode))
atime = F_ATIME(first);
+#ifdef SUPPORT_CRTIMES
+ if (crtimes_ndx)
+ crtime = F_CRTIME(first);
+#endif
if (preserve_uid)
uid = F_OWNER(first);
if (preserve_gid)
gid = F_GROUP(first);
if (preserve_devices && IS_DEVICE(mode)) {
uint32 *devp = F_RDEV_P(first);
- rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
+ rdev_major = DEV_MAJOR(devp);
+ rdev = MAKEDEV(rdev_major, DEV_MINOR(devp));
extra_len += DEV_EXTRA_CNT * EXTRA_LEN;
}
if (preserve_links && S_ISLNK(mode))
linkname_len = strlen(F_SYMLINK(first)) + 1;
else
linkname_len = 0;
+ real_ISREG_entry = S_ISREG(mode) ? 1 : 0;
goto create_object;
}
}
}
#endif
} else
- modtime = read_int(f);
+ modtime = read_uint(f);
}
if (xflags & XMIT_MOD_NSEC)
#ifndef CAN_SET_NSEC
modtime_nsec = read_varint(f);
else
modtime_nsec = 0;
+#endif
+#ifdef SUPPORT_CRTIMES
+ if (crtimes_ndx) {
+ if (xflags & XMIT_CRTIME_EQ_MTIME)
+ crtime = modtime;
+ else
+ crtime = read_varlong(f, 4);
+#if SIZEOF_TIME_T < SIZEOF_INT64
+ if (!am_generator && (int64)(time_t)crtime != crtime) {
+ rprintf(FERROR_XFER,
+ "Create time value of %s truncated on receiver.\n",
+ lastname);
+ }
+#endif
+ }
#endif
if (!(xflags & XMIT_SAME_MODE))
mode = from_wire_mode(read_int(f));
#endif
linkname_len = 0;
+ if (copy_devices && IS_DEVICE(mode)) {
+ /* This is impossible in the official release, but some pre-release patches
+ * didn't convert the device into a file before sending, so we'll do it here
+ * (even though the length is typically 0 and any checksum data is zeros). */
+ mode = S_IFREG | (mode & ACCESSPERMS);
+ modtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */
+ real_ISREG_entry = 0;
+ } else
+ real_ISREG_entry = S_ISREG(mode) ? 1 : 0;
+
#ifdef SUPPORT_HARD_LINKS
create_object:
if (preserve_hard_links) {
- if (protocol_version < 28 && S_ISREG(mode))
+ if (protocol_version < 28 && real_ISREG_entry)
xflags |= XMIT_HLINKED;
if (xflags & XMIT_HLINKED)
extra_len += (inc_recurse+1) * EXTRA_LEN;
exit_cleanup(RERR_UNSUPPORTED);
}
+ if (*thisname == '/' ? thisname[1] != '.' || thisname[2] != '\0' : *thisname != '.' || thisname[1] != '\0') {
+ int filt_flags = S_ISDIR(mode) ? NAME_IS_DIR : NAME_IS_FILE;
+ if (!trust_sender_filter /* a per-dir filter rule means we must trust the sender's filtering */
+ && filter_list.head && check_server_filter(&filter_list, FINFO, thisname, filt_flags) < 0) {
+ rprintf(FERROR, "ERROR: rejecting excluded file-list name: %s\n", thisname);
+ exit_cleanup(RERR_UNSUPPORTED);
+ }
+ if (implied_filter_list.head && check_filter(&implied_filter_list, FINFO, thisname, filt_flags) <= 0) {
+ rprintf(FERROR, "ERROR: rejecting unrequested file-list name: %s\n", thisname);
+ exit_cleanup(RERR_UNSUPPORTED);
+ }
+ }
+
if (inc_recurse && S_ISDIR(mode)) {
if (one_file_system) {
/* Room to save the dir's device for -x */
}
if (atimes_ndx && !S_ISDIR(mode))
F_ATIME(file) = atime;
+#ifdef SUPPORT_CRTIMES
+ if (crtimes_ndx)
+ F_CRTIME(file) = crtime;
+#endif
if (unsort_ndx)
F_NDX(file) = flist->used + flist->ndx_start;
}
#endif
- if (always_checksum && (S_ISREG(mode) || protocol_version < 28)) {
- if (S_ISREG(mode))
+ if (always_checksum && (real_ISREG_entry || protocol_version < 28)) {
+ if (real_ISREG_entry)
bp = F_SUM(file);
else {
/* Prior to 28, we get a useless set of nulls. */
linkname_len = 0;
#endif
+ if (copy_devices && am_sender && IS_DEVICE(st.st_mode)) {
+ if (st.st_size == 0) {
+ int fd = do_open(fname, O_RDONLY, 0);
+ if (fd >= 0) {
+ st.st_size = get_device_size(fd, fname);
+ close(fd);
+ }
+ }
+ st.st_mode = S_IFREG | (st.st_mode & ACCESSPERMS);
+ st.st_mtime = time(NULL); /* The mtime on the device is not up-to-date, so set it to "now". */
+ }
+
#ifdef ST_MTIME_NSEC
if (st.ST_MTIME_NSEC && protocol_version >= 31)
extra_len += EXTRA_LEN;
file->flags |= FLAG_OWNED_BY_US;
if (atimes_ndx && !S_ISDIR(file->mode))
F_ATIME(file) = st.st_atime;
+#ifdef SUPPORT_CRTIMES
+ if (crtimes_ndx)
+ F_CRTIME(file) = get_create_time(fname, &st);
+#endif
if (basename != thisname)
file->dirname = lastdir;
#endif
flist = cur_flist = flist_new(0, "send_file_list");
+ flist_expand(flist, FLIST_START_LARGE);
if (inc_recurse) {
dir_flist = flist_new(FLIST_TEMP, "send_file_list");
+ flist_expand(dir_flist, FLIST_START_LARGE);
flags |= FLAG_DIVERT_DIRS;
} else
dir_flist = cur_flist;
#endif
flist = flist_new(0, "recv_file_list");
+ flist_expand(flist, FLIST_START_LARGE);
if (inc_recurse) {
- if (flist->ndx_start == 1)
+ if (flist->ndx_start == 1) {
dir_flist = flist_new(FLIST_TEMP, "recv_file_list");
+ flist_expand(dir_flist, FLIST_START_LARGE);
+ }
dstart = dir_flist->used;
} else {
dir_flist = flist;
rprintf(FERROR,
"ABORTING due to invalid path from sender: %s/%s\n",
cur_dir, file->basename);
- exit_cleanup(RERR_PROTOCOL);
+ exit_cleanup(RERR_UNSUPPORTED);
}
good_dirname = cur_dir;
}