Commit 1a2e41af authored by Wayne Davison's avatar Wayne Davison

Add support for transferring & setting nsec time values.

parent accc091f
......@@ -370,7 +370,18 @@ AC_TYPE_SIGNAL
AC_TYPE_UID_T
AC_CHECK_TYPES([mode_t,off_t,size_t,pid_t,id_t])
AC_TYPE_GETGROUPS
AC_CHECK_MEMBERS([struct stat.st_rdev])
AC_CHECK_MEMBERS([struct stat.st_rdev,
struct stat.st_mtimensec,
struct stat.st_mtim.tv_nsec],,,[
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif])
TYPE_SOCKLEN_T
......@@ -563,7 +574,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strdup chown chmod lchmod mknod mkfifo \
setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
strerror putenv iconv_open locale_charset nl_langinfo getxattr \
extattr_get_link sigaction sigprocmask setattrlist getgrouplist \
initgroups)
initgroups utimensat)
dnl cygwin iconv.h defines iconv_open as libiconv_open
if test x"$ac_cv_func_iconv_open" != x"yes"; then
......
......@@ -87,6 +87,14 @@ extern int filesfrom_convert;
extern iconv_t ic_send, ic_recv;
#endif
#ifdef HAVE_UTIMENSAT
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
#define ST_MTIME_NSEC st_mtim.tv_nsec
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
#define ST_MTIME_NSEC st_mtimensec
#endif
#endif
#define PTR_SIZE (sizeof (struct file_struct *))
int io_error;
......@@ -495,6 +503,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
xflags |= XMIT_SAME_TIME;
else
modtime = file->modtime;
if (NSEC_BUMP(file) && protocol_version >= 31)
xflags |= XMIT_MOD_NSEC;
#ifdef SUPPORT_HARD_LINKS
if (tmp_dev != 0) {
......@@ -577,6 +587,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
else
write_int(f, modtime);
}
if (xflags & XMIT_MOD_NSEC)
write_varint(f, F_MOD_NSEC(file));
if (!(xflags & XMIT_SAME_MODE))
write_int(f, to_wire_mode(mode));
if (preserve_uid && !(xflags & XMIT_SAME_UID)) {
......@@ -685,6 +697,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
int extra_len = file_extra_cnt * EXTRA_LEN;
int first_hlink_ndx = -1;
int64 file_length;
uint32 modtime_nsec;
const char *basename;
struct file_struct *file;
alloc_pool_t *pool;
......@@ -768,6 +781,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
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);
mode = first->mode;
if (preserve_uid)
uid = F_OWNER(first);
......@@ -801,6 +815,10 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
} else
modtime = read_int(f);
}
if (xflags & XMIT_MOD_NSEC)
modtime_nsec = read_varint(f);
else
modtime_nsec = 0;
if (!(xflags & XMIT_SAME_MODE))
mode = from_wire_mode(read_int(f));
......@@ -898,6 +916,10 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
#if SIZEOF_INT64 >= 8
if (file_length > 0xFFFFFFFFu && S_ISREG(mode))
extra_len += EXTRA_LEN;
#endif
#ifdef HAVE_UTIMENSAT
if (modtime_nsec)
extra_len += EXTRA_LEN;
#endif
if (file_length < 0) {
rprintf(FERROR, "Offset underflow: file-length is negative\n");
......@@ -934,6 +956,12 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
file->flags |= FLAG_HLINKED;
#endif
file->modtime = (time_t)modtime;
#ifdef HAVE_UTIMENSAT
if (modtime_nsec) {
file->flags |= FLAG_MOD_NSEC;
OPT_EXTRA(file, 0)->unum = modtime_nsec;
}
#endif
file->len32 = (uint32)file_length;
#if SIZEOF_INT64 >= 8
if (file_length > 0xFFFFFFFFu && S_ISREG(mode)) {
......@@ -942,7 +970,7 @@ static struct file_struct *recv_file_entry(struct file_list *flist,
exit_cleanup(RERR_UNSUPPORTED);
#else
file->flags |= FLAG_LENGTH64;
OPT_EXTRA(file, 0)->unum = (uint32)(file_length >> 32);
OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(file_length >> 32);
#endif
}
#endif
......@@ -1272,6 +1300,10 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
linkname_len = 0;
#endif
#ifdef ST_MTIME_NSEC
if (st.ST_MTIME_NSEC && protocol_version >= 31)
extra_len += EXTRA_LEN;
#endif
#if SIZEOF_CAPITAL_OFF_T >= 8
if (st.st_size > 0xFFFFFFFFu && S_ISREG(st.st_mode))
extra_len += EXTRA_LEN;
......@@ -1326,11 +1358,17 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
file->flags = flags;
file->modtime = st.st_mtime;
#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;
}
#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, 0)->unum = (uint32)(st.st_size >> 32);
OPT_EXTRA(file, NSEC_BUMP(file))->unum = (uint32)(st.st_size >> 32);
}
#endif
file->mode = st.st_mode;
......
......@@ -1923,7 +1923,7 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
STRUCT_STAT st;
if (link_stat(fname, &st, 0) == 0
&& cmp_time(st.st_mtime, file->modtime) != 0)
set_modtime(fname, file->modtime, file->mode);
set_modtime(fname, file->modtime, F_MOD_NSEC(file), file->mode);
}
if (counter >= loopchk_limit) {
if (allowed_lull)
......
......@@ -435,7 +435,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
flags |= ATTRS_SKIP_MTIME;
if (!(flags & ATTRS_SKIP_MTIME)
&& cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
int ret = set_modtime(fname, file->modtime, sxp->st.st_mode);
int ret = set_modtime(fname, file->modtime, F_MOD_NSEC(file), sxp->st.st_mode);
if (ret < 0) {
rsyserr(FERROR_XFER, errno, "failed to set times on %s",
full_fname(fname));
......
......@@ -61,6 +61,7 @@
#define XMIT_GROUP_NAME_FOLLOWS (1<<11) /* protocols 30 - now */
#define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */
#define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31 - now (w/XMIT_EXTENDED_FLAGS) */
#define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */
/* These flags are used in the live flist data. */
......@@ -80,6 +81,7 @@
#define FLAG_LENGTH64 (1<<9) /* sender/receiver/generator */
#define FLAG_SKIP_GROUP (1<<10) /* receiver/generator */
#define FLAG_TIME_FAILED (1<<11)/* generator */
#define FLAG_MOD_NSEC (1<<12) /* sender/receiver/generator */
/* These flags are passed to functions but not stored. */
......@@ -96,7 +98,7 @@
/* This is used when working on a new protocol version in CVS, and should
* be a new non-zero value for each CVS change that affects the protocol.
* It must ALWAYS be 0 when the protocol goes final (and NEVER before)! */
#define SUBPROTOCOL_VERSION 6
#define SUBPROTOCOL_VERSION 7
/* We refuse to interoperate with versions that are not in this range.
* Note that we assume we'll work with later versions: the onus is on
......@@ -359,7 +361,7 @@ enum delret {
#include <utime.h>
#endif
#ifdef HAVE_LUTIMES
#if defined HAVE_UTIMENSAT || defined HAVE_LUTIMES
#define CAN_SET_SYMLINK_TIMES 1
#endif
......@@ -674,7 +676,9 @@ extern int xattrs_ndx;
#define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx))
#define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump))
#define NSEC_BUMP(f) ((f)->flags & FLAG_MOD_NSEC ? 1 : 0)
#define LEN64_BUMP(f) ((f)->flags & FLAG_LENGTH64 ? 1 : 0)
#define START_BUMP(f) (NSEC_BUMP(f) + LEN64_BUMP(f))
#define HLINK_BUMP(f) ((f)->flags & (FLAG_HLINKED|FLAG_HLINK_DONE) ? inc_recurse+1 : 0)
#define ACL_BUMP(f) (acls_ndx ? 1 : 0)
......@@ -686,6 +690,8 @@ extern int xattrs_ndx;
? (int64)OPT_EXTRA(f, 0)->unum << 32 : 0))
#endif
#define F_MOD_NSEC(f) ((f)->flags & FLAG_MOD_NSEC ? OPT_EXTRA(f, LEN64_BUMP(f))->unum : 0)
/* If there is a symlink string, it is always right after the basename */
#define F_SYMLINK(f) ((f)->basename + strlen((f)->basename) + 1)
......@@ -703,22 +709,21 @@ extern int xattrs_ndx;
#define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num
/* These items are per-entry optional: */
#define F_HL_GNUM(f) OPT_EXTRA(f, LEN64_BUMP(f))->num /* non-dirs */
#define F_HL_PREV(f) OPT_EXTRA(f, LEN64_BUMP(f)+inc_recurse)->num /* non-dirs */
#define F_DIR_NODE_P(f) (&OPT_EXTRA(f, LEN64_BUMP(f) \
#define F_HL_GNUM(f) OPT_EXTRA(f, START_BUMP(f))->num /* non-dirs */
#define F_HL_PREV(f) OPT_EXTRA(f, START_BUMP(f)+inc_recurse)->num /* non-dirs */
#define F_DIR_NODE_P(f) (&OPT_EXTRA(f, START_BUMP(f) \
+ DIRNODE_EXTRA_CNT - 1)->num) /* sender dirs */
#define F_DIR_RELNAMES_P(f) (&OPT_EXTRA(f, LEN64_BUMP(f) + DIRNODE_EXTRA_CNT \
#define F_DIR_RELNAMES_P(f) (&OPT_EXTRA(f, START_BUMP(f) + DIRNODE_EXTRA_CNT \
+ PTR_EXTRA_CNT - 1)->num) /* sender dirs */
#define F_DIR_DEFACL(f) OPT_EXTRA(f, LEN64_BUMP(f))->unum /* receiver dirs */
#define F_DIR_DEV_P(f) (&OPT_EXTRA(f, LEN64_BUMP(f) + ACL_BUMP(f) \
#define F_DIR_DEFACL(f) OPT_EXTRA(f, START_BUMP(f))->unum /* receiver dirs */
#define F_DIR_DEV_P(f) (&OPT_EXTRA(f, START_BUMP(f) + ACL_BUMP(f) \
+ DEV_EXTRA_CNT - 1)->unum) /* receiver dirs */
/* This optional item might follow an F_HL_*() item.
* (Note: a device doesn't need to check LEN64_BUMP(f).) */
#define F_RDEV_P(f) (&OPT_EXTRA(f, HLINK_BUMP(f) + DEV_EXTRA_CNT - 1)->unum)
/* This optional item might follow an F_HL_*() item. */
#define F_RDEV_P(f) (&OPT_EXTRA(f, START_BUMP(f) + HLINK_BUMP(f) + DEV_EXTRA_CNT - 1)->unum)
/* The sum is only present on regular files. */
#define F_SUM(f) ((char*)OPT_EXTRA(f, LEN64_BUMP(f) + HLINK_BUMP(f) \
#define F_SUM(f) ((char*)OPT_EXTRA(f, START_BUMP(f) + HLINK_BUMP(f) \
+ SUM_EXTRA_CNT - 1))
/* Some utility defines: */
......
......@@ -48,10 +48,19 @@ int read_only = 1;
int list_only = 0;
int link_times = 0;
int link_owner = 0;
int nsec_times = 0;
int preserve_perms = 0;
int preserve_executability = 0;
char number_separator;
#ifdef HAVE_UTIMENSAT
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
#define ST_MTIME_NSEC st_mtim.tv_nsec
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
#define ST_MTIME_NSEC st_mtimensec
#endif
#endif
#ifdef SUPPORT_XATTRS
#ifdef HAVE_LINUX_XATTRS
......@@ -161,9 +170,10 @@ static void list_file(const char *fname)
permstring(permbuf, buf.st_mode);
if (buf.st_mtime) {
int len;
mt = gmtime(&buf.st_mtime);
snprintf(datebuf, sizeof datebuf,
len = snprintf(datebuf, sizeof datebuf,
"%04d-%02d-%02d %02d:%02d:%02d",
(int)mt->tm_year + 1900,
(int)mt->tm_mon + 1,
......@@ -171,8 +181,17 @@ static void list_file(const char *fname)
(int)mt->tm_hour,
(int)mt->tm_min,
(int)mt->tm_sec);
} else
strlcpy(datebuf, " ", sizeof datebuf);
#ifdef ST_MTIME_NSEC
if (nsec_times) {
snprintf(datebuf + len, sizeof datebuf - len,
".%09d", (int)buf.ST_MTIME_NSEC);
}
#endif
} else {
int len = MIN(19 + 9*nsec_times, (int)sizeof datebuf - 1);
memset(datebuf, ' ', len);
datebuf[len] = '\0';
}
/* TODO: Perhaps escape special characters in fname? */
......@@ -194,6 +213,9 @@ static struct poptOption long_options[] = {
{"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 },
#ifdef SUPPORT_XATTRS
{"fake-super", 'f', POPT_ARG_VAL, &am_root, -1, 0, 0 },
#endif
#ifdef ST_MTIME_NSEC
{"nsec", 's', POPT_ARG_NONE, &nsec_times, 0, 0, 0 },
#endif
{"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 },
{0,0,0,0,0,0,0}
......
......@@ -123,7 +123,7 @@ NORETURN void overflow_exit(const char *str)
exit_cleanup(RERR_MALLOC);
}
int set_modtime(const char *fname, time_t modtime, mode_t mode)
int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode)
{
#ifndef CAN_SET_SYMLINK_TIMES
if (S_ISLNK(mode))
......@@ -140,12 +140,21 @@ int set_modtime(const char *fname, time_t modtime, mode_t mode)
return 0;
{
#if defined HAVE_UTIMES || defined HAVE_LUTIMES
#ifdef HAVE_UTIMENSAT
struct timespec t[2];
t[0].tv_sec = 0;
t[0].tv_nsec = UTIME_NOW;
t[1].tv_sec = modtime;
t[1].tv_nsec = mod_nsec;
if (utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW) < 0)
return S_ISLNK(mode) && errno == ENOSYS ? 1 : -1;
return 0;
#elif defined HAVE_UTIMES || defined HAVE_LUTIMES
struct timeval t[2];
t[0].tv_sec = time(NULL);
t[0].tv_usec = 0;
t[1].tv_sec = modtime;
t[1].tv_usec = 0;
t[1].tv_usec = mod_nsec / 1000;
# ifdef HAVE_LUTIMES
if (lutimes(fname, t) < 0)
return S_ISLNK(mode) && errno == ENOSYS ? 1 : -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment