summaryrefslogtreecommitdiff
path: root/flist.c
diff options
context:
space:
mode:
Diffstat (limited to 'flist.c')
-rw-r--r--flist.c159
1 files changed, 115 insertions, 44 deletions
diff --git a/flist.c b/flist.c
index 499440cc..bbc028ba 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 <mbp@samba.org>
- * Copyright (C) 2002-2018 Wayne Davison
+ * Copyright (C) 2002-2020 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
@@ -55,6 +55,7 @@ extern int preserve_specials;
extern int delete_during;
extern int missing_args;
extern int eol_nulls;
+extern int atimes_ndx;
extern int relative_paths;
extern int implied_dirs;
extern int ignore_perishable;
@@ -100,6 +101,7 @@ int flist_cnt = 0; /* how many (non-tmp) file list objects exist */
int file_total = 0; /* total of all active items over all file-lists */
int file_old_total = 0; /* total of active items that will soon be gone */
int flist_eof = 0; /* all the file-lists are now known */
+int xfer_flags_as_varint = 0;
#define NORMAL_NAME 0
#define SLASH_ENDING_NAME 1
@@ -140,7 +142,6 @@ void init_flist(void)
rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n",
(int)FILE_STRUCT_LEN, (int)EXTRA_LEN);
}
- parse_checksum_choice(); /* Sets checksum_type && xfersum_type */
flist_csum_len = csum_len_for_type(checksum_type, 1);
show_filelist_progress = INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse;
@@ -379,7 +380,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
#endif
int ndx, int first_ndx)
{
- static time_t modtime;
+ static time_t modtime, atime;
static mode_t mode;
#ifdef SUPPORT_HARD_LINKS
static int64 dev;
@@ -479,14 +480,20 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
modtime = file->modtime;
if (NSEC_BUMP(file) && protocol_version >= 31)
xflags |= XMIT_MOD_NSEC;
+ if (atimes_ndx && !S_ISDIR(mode)) {
+ if (F_ATIME(file) == atime)
+ xflags |= XMIT_SAME_ATIME;
+ else
+ atime = F_ATIME(file);
+ }
#ifdef SUPPORT_HARD_LINKS
if (tmp_dev != -1) {
if (protocol_version >= 30) {
struct ht_int64_node *np = idev_find(tmp_dev, tmp_ino);
- first_hlink_ndx = (int32)(long)np->data - 1;
+ first_hlink_ndx = (int32)(long)np->data; /* is -1 when new */
if (first_hlink_ndx < 0) {
- np->data = (void*)(long)(first_ndx + ndx + 1);
+ np->data = (void*)(long)(first_ndx + ndx);
xflags |= XMIT_HLINK_FIRST;
}
if (DEBUG_GTE(HLINK, 1)) {
@@ -521,11 +528,14 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
if (l2 > 255)
xflags |= XMIT_LONG_NAME;
- /* We must make sure we don't send a zero flag byte or the
- * other end will terminate the flist transfer. Note that
- * the use of XMIT_TOP_DIR on a non-dir has no meaning, so
- * it's harmless way to add a bit to the first flag byte. */
- if (protocol_version >= 28) {
+ /* We must avoid sending a flag value of 0 (or an initial byte of
+ * 0 for the older xflags protocol) or it will signal the end of
+ * the list. Note that the use of XMIT_TOP_DIR on a non-dir has
+ * no meaning, so it's a harmless way to add a bit to the first
+ * flag byte. */
+ if (xfer_flags_as_varint)
+ write_varint(f, xflags ? xflags : XMIT_EXTENDED_FLAGS);
+ else if (protocol_version >= 28) {
if (!xflags && !S_ISDIR(mode))
xflags |= XMIT_TOP_DIR;
if ((xflags & 0xFF00) || !xflags) {
@@ -565,6 +575,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
write_varint(f, F_MOD_NSEC(file));
if (!(xflags & XMIT_SAME_MODE))
write_int(f, to_wire_mode(mode));
+ if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME))
+ write_varlong(f, atime, 4);
if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
if (protocol_version < 30)
write_int(f, uid);
@@ -652,7 +664,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
static struct file_struct *recv_file_entry(int f, struct file_list *flist, int xflags)
{
- static int64 modtime;
+ static int64 modtime, atime;
static mode_t mode;
#ifdef SUPPORT_HARD_LINKS
static int64 dev;
@@ -759,8 +771,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
struct file_struct *first = flist->files[first_hlink_ndx - flist->ndx_start];
file_length = F_LENGTH(first);
modtime = first->modtime;
- modtime_nsec = F_MOD_NSEC(first);
+ modtime_nsec = F_MOD_NSEC_or_0(first);
mode = first->mode;
+ if (atimes_ndx && !S_ISDIR(mode))
+ atime = F_ATIME(first);
if (preserve_uid)
uid = F_OWNER(first);
if (preserve_gid)
@@ -799,6 +813,16 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
modtime_nsec = 0;
if (!(xflags & XMIT_SAME_MODE))
mode = from_wire_mode(read_int(f));
+ if (atimes_ndx && !S_ISDIR(mode) && !(xflags & XMIT_SAME_ATIME)) {
+ atime = read_varlong(f, 4);
+#if SIZEOF_TIME_T < SIZEOF_INT64
+ if (!am_generator && (int64)(time_t)atime != atime) {
+ rprintf(FERROR_XFER,
+ "Access time value of %s truncated on receiver.\n",
+ lastname);
+ }
+#endif
+ }
if (chmod_modes && !S_ISLNK(mode) && mode)
mode = tweak_mode(mode, chmod_modes);
@@ -944,7 +968,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
#ifdef CAN_SET_NSEC
if (modtime_nsec) {
file->flags |= FLAG_MOD_NSEC;
- OPT_EXTRA(file, 0)->unum = modtime_nsec;
+ F_MOD_NSEC(file) = modtime_nsec;
}
#endif
file->len32 = (uint32)file_length;
@@ -955,7 +979,7 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
exit_cleanup(RERR_UNSUPPORTED);
#else
file->flags |= FLAG_LENGTH64;
- OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(file_length >> 32);
+ F_HIGH_LEN(file) = (uint32)(file_length >> 32);
#endif
}
#endif
@@ -966,6 +990,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
F_GROUP(file) = gid;
file->flags |= gid_flags;
}
+ if (atimes_ndx && !S_ISDIR(mode))
+ F_ATIME(file) = atime;
if (unsort_ndx)
F_NDX(file) = flist->used + flist->ndx_start;
@@ -1075,10 +1101,10 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
ino = read_longint(f);
}
np = idev_find(dev, ino);
- ndx = (int32)(long)np->data - 1;
+ ndx = (int32)(long)np->data; /* is -1 when new */
if (ndx < 0) {
- ndx = cnt++;
np->data = (void*)(long)cnt;
+ ndx = cnt++;
}
F_HL_GNUM(file) = ndx;
}
@@ -1346,14 +1372,14 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
#ifdef ST_MTIME_NSEC
if (st.ST_MTIME_NSEC && protocol_version >= 31) {
file->flags |= FLAG_MOD_NSEC;
- OPT_EXTRA(file, 0)->unum = st.ST_MTIME_NSEC;
+ F_MOD_NSEC(file) = st.ST_MTIME_NSEC;
}
#endif
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, NSEC_BUMP(file))->unum = (uint32)(st.st_size >> 32);
+ F_HIGH_LEN(file) = (uint32)(st.st_size >> 32);
}
#endif
file->mode = st.st_mode;
@@ -1363,6 +1389,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
F_GROUP(file) = st.st_gid;
if (am_generator && st.st_uid == our_uid)
file->flags |= FLAG_OWNED_BY_US;
+ if (atimes_ndx && !S_ISDIR(file->mode))
+ F_ATIME(file) = st.st_atime;
if (basename != thisname)
file->dirname = lastdir;
@@ -1392,6 +1420,20 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
return file;
}
+OFF_T get_device_size(int fd, const char *fname)
+{
+ OFF_T off = lseek(fd, 0, SEEK_END);
+
+ if (off == (OFF_T) -1) {
+ rsyserr(FERROR, errno, "failed to get device size via seek: %s", fname);
+ return 0;
+ }
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ rsyserr(FERROR, errno, "failed to seek device back to start: %s", fname);
+
+ return off;
+}
+
/* Only called for temporary file_struct entries created by make_file(). */
void unmake_file(struct file_struct *file)
{
@@ -1636,6 +1678,7 @@ static void add_dirs_to_tree(int parent_ndx, struct file_list *from_flist,
int32 *parent_dp = parent_ndx < 0 ? NULL
: F_DIR_NODE_P(dir_flist->sorted[parent_ndx]);
+ /* The sending side is adding entries to dir_flist in sorted order, so sorted & files are the same. */
flist_expand(dir_flist, dir_cnt);
dir_flist->sorted = dir_flist->files;
@@ -1703,6 +1746,8 @@ static void send_directory(int f, struct file_list *flist, char *fbuf, int len,
interpret_stat_error(fbuf, True);
return;
}
+ if (errno == ENOTDIR && (flags & FLAG_PERHAPS_DIR))
+ return;
io_error |= IOERR_GENERAL;
rsyserr(FERROR_XFER, errno, "opendir %s failed", full_fname(fbuf));
return;
@@ -1941,6 +1986,18 @@ static void send1extra(int f, struct file_struct *file, struct file_list *flist)
free(relname_list);
}
+static void write_end_of_flist(int f, int send_io_error)
+{
+ if (xfer_flags_as_varint) {
+ write_varint(f, 0);
+ write_varint(f, send_io_error ? io_error : 0);
+ } else if (send_io_error) {
+ write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
+ write_varint(f, io_error);
+ } else
+ write_byte(f, 0);
+}
+
void send_extra_file_list(int f, int at_least)
{
struct file_list *flist;
@@ -1970,7 +2027,7 @@ void send_extra_file_list(int f, int at_least)
else
dir_ndx = send_dir_ndx;
write_ndx(f, NDX_FLIST_OFFSET - dir_ndx);
- flist->parent_ndx = dir_ndx;
+ flist->parent_ndx = send_dir_ndx; /* the sending side must remember the sorted ndx value */
send1extra(f, file, flist);
prev_flags = file->flags;
@@ -1992,14 +2049,13 @@ void send_extra_file_list(int f, int at_least)
}
if (io_error == save_io_error || ignore_errors)
- write_byte(f, 0);
- else if (use_safe_inc_flist) {
- write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
- write_varint(f, io_error);
- } else {
+ write_end_of_flist(f, 0);
+ else if (use_safe_inc_flist)
+ write_end_of_flist(f, 1);
+ else {
if (delete_during)
fatal_unsafe_io_error();
- write_byte(f, 0);
+ write_end_of_flist(f, 0);
}
if (need_unsorted_flist) {
@@ -2328,14 +2384,13 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
/* Indicate end of file list */
if (io_error == 0 || ignore_errors)
- write_byte(f, 0);
- else if (use_safe_inc_flist) {
- write_shortint(f, XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST);
- write_varint(f, io_error);
- } else {
+ write_end_of_flist(f, 0);
+ else if (use_safe_inc_flist)
+ write_end_of_flist(f, 1);
+ else {
if (delete_during && inc_recurse)
fatal_unsafe_io_error();
- write_byte(f, 0);
+ write_end_of_flist(f, 0);
}
#ifdef SUPPORT_HARD_LINKS
@@ -2454,22 +2509,34 @@ struct file_list *recv_file_list(int f, int dir_ndx)
dstart = 0;
}
- while ((flags = read_byte(f)) != 0) {
+ while (1) {
struct file_struct *file;
- if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
- flags |= read_byte(f) << 8;
+ if (xfer_flags_as_varint) {
+ if ((flags = read_varint(f)) == 0) {
+ int err = read_varint(f);
+ if (!ignore_errors)
+ io_error |= err;
+ break;
+ }
+ } else {
+ if ((flags = read_byte(f)) == 0)
+ break;
+
+ if (protocol_version >= 28 && (flags & XMIT_EXTENDED_FLAGS))
+ flags |= read_byte(f) << 8;
- if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) {
- int err;
- if (!use_safe_inc_flist) {
- rprintf(FERROR, "Invalid flist flag: %x\n", flags);
- exit_cleanup(RERR_PROTOCOL);
+ if (flags == (XMIT_EXTENDED_FLAGS|XMIT_IO_ERROR_ENDLIST)) {
+ int err;
+ if (!use_safe_inc_flist) {
+ rprintf(FERROR, "Invalid flist flag: %x\n", flags);
+ exit_cleanup(RERR_PROTOCOL);
+ }
+ err = read_varint(f);
+ if (!ignore_errors)
+ io_error |= err;
+ break;
}
- err = read_varint(f);
- if (!ignore_errors)
- io_error |= err;
- break;
}
flist_expand(flist, 1);
@@ -3228,6 +3295,7 @@ struct file_list *get_dirlist(char *dirname, int dlen, int flags)
int save_xfer_dirs = xfer_dirs;
int save_prune_empty_dirs = prune_empty_dirs;
int senddir_fd = flags & GDL_IGNORE_FILTER_RULES ? -2 : -1;
+ int senddir_flags = FLAG_CONTENT_DIR;
if (dlen < 0) {
dlen = strlcpy(dirbuf, dirname, MAXPATHLEN);
@@ -3238,9 +3306,12 @@ struct file_list *get_dirlist(char *dirname, int dlen, int flags)
dirlist = flist_new(FLIST_TEMP, "get_dirlist");
+ if (flags & GDL_PERHAPS_DIR)
+ senddir_flags |= FLAG_PERHAPS_DIR;
+
recurse = 0;
xfer_dirs = 1;
- send_directory(senddir_fd, dirlist, dirname, dlen, FLAG_CONTENT_DIR);
+ send_directory(senddir_fd, dirlist, dirname, dlen, senddir_flags);
xfer_dirs = save_xfer_dirs;
recurse = save_recurse;
if (INFO_GTE(PROGRESS, 1))