Added --atimes and --set-noatime options.

This commit is contained in:
Wayne Davison
2020-04-23 13:17:41 -07:00
parent 2b2a3c87b6
commit b936741032
17 changed files with 363 additions and 108 deletions

4
NEWS
View File

@@ -30,6 +30,10 @@ Changes since 3.1.3:
ENHANCEMENTS: ENHANCEMENTS:
- Improved the --atimes patch and promoted it to be in the release.
- Added --set-noatime option to open files using O_NOATIME.
- Improved the --write-devices patch and promoted it to be in the release. - Improved the --write-devices patch and promoted it to be in the release.
- Added openssl support to the rsync-ssl script via its renamed helper - Added openssl support to the rsync-ssl script via its renamed helper

View File

@@ -48,6 +48,7 @@ extern int protocol_version;
extern int protect_args; extern int protect_args;
extern int preserve_uid; extern int preserve_uid;
extern int preserve_gid; extern int preserve_gid;
extern int preserve_atimes;
extern int preserve_acls; extern int preserve_acls;
extern int preserve_xattrs; extern int preserve_xattrs;
extern int need_messages_from_generator; extern int need_messages_from_generator;
@@ -65,7 +66,7 @@ extern char *iconv_opt;
#endif #endif
/* These index values are for the file-list's extra-attribute array. */ /* These index values are for the file-list's extra-attribute array. */
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx; int pathname_ndx, depth_ndx, atimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ int receiver_symlink_times = 0; /* receiver can set the time on a symlink */
int sender_symlink_iconv = 0; /* sender should convert symlink content */ int sender_symlink_iconv = 0; /* sender should convert symlink content */
@@ -136,10 +137,17 @@ void set_allow_inc_recurse(void)
void setup_protocol(int f_out,int f_in) void setup_protocol(int f_out,int f_in)
{ {
if (am_sender) assert(file_extra_cnt == 0);
file_extra_cnt += PTR_EXTRA_CNT; assert(EXTRA64_CNT == 2 || EXTRA64_CNT == 1);
/* All int64 values must be set first so that they are guaranteed to be
* aligned for direct int64-pointer memory access. */
if (preserve_atimes)
atimes_ndx = (file_extra_cnt += EXTRA64_CNT);
if (am_sender) /* This is most likely in the in64 union as well. */
pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT);
else else
file_extra_cnt++; depth_ndx = ++file_extra_cnt;
if (preserve_uid) if (preserve_uid)
uid_ndx = ++file_extra_cnt; uid_ndx = ++file_extra_cnt;
if (preserve_gid) if (preserve_gid)

27
flist.c
View File

@@ -55,6 +55,7 @@ extern int preserve_specials;
extern int delete_during; extern int delete_during;
extern int missing_args; extern int missing_args;
extern int eol_nulls; extern int eol_nulls;
extern int atimes_ndx;
extern int relative_paths; extern int relative_paths;
extern int implied_dirs; extern int implied_dirs;
extern int ignore_perishable; extern int ignore_perishable;
@@ -379,7 +380,7 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
#endif #endif
int ndx, int first_ndx) int ndx, int first_ndx)
{ {
static time_t modtime; static time_t modtime, atime;
static mode_t mode; static mode_t mode;
#ifdef SUPPORT_HARD_LINKS #ifdef SUPPORT_HARD_LINKS
static int64 dev; static int64 dev;
@@ -479,6 +480,12 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
modtime = file->modtime; modtime = file->modtime;
if (NSEC_BUMP(file) && protocol_version >= 31) if (NSEC_BUMP(file) && protocol_version >= 31)
xflags |= XMIT_MOD_NSEC; 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 #ifdef SUPPORT_HARD_LINKS
if (tmp_dev != -1) { if (tmp_dev != -1) {
@@ -565,6 +572,8 @@ static void send_file_entry(int f, const char *fname, struct file_struct *file,
write_varint(f, F_MOD_NSEC(file)); write_varint(f, F_MOD_NSEC(file));
if (!(xflags & XMIT_SAME_MODE)) if (!(xflags & XMIT_SAME_MODE))
write_int(f, to_wire_mode(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 (preserve_uid && !(xflags & XMIT_SAME_UID)) {
if (protocol_version < 30) if (protocol_version < 30)
write_int(f, uid); write_int(f, uid);
@@ -652,7 +661,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 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; static mode_t mode;
#ifdef SUPPORT_HARD_LINKS #ifdef SUPPORT_HARD_LINKS
static int64 dev; static int64 dev;
@@ -799,6 +808,16 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
modtime_nsec = 0; modtime_nsec = 0;
if (!(xflags & XMIT_SAME_MODE)) if (!(xflags & XMIT_SAME_MODE))
mode = from_wire_mode(read_int(f)); 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) if (chmod_modes && !S_ISLNK(mode) && mode)
mode = tweak_mode(mode, chmod_modes); mode = tweak_mode(mode, chmod_modes);
@@ -966,6 +985,8 @@ static struct file_struct *recv_file_entry(int f, struct file_list *flist, int x
F_GROUP(file) = gid; F_GROUP(file) = gid;
file->flags |= gid_flags; file->flags |= gid_flags;
} }
if (atimes_ndx)
F_ATIME(file) = atime;
if (unsort_ndx) if (unsort_ndx)
F_NDX(file) = flist->used + flist->ndx_start; F_NDX(file) = flist->used + flist->ndx_start;
@@ -1363,6 +1384,8 @@ struct file_struct *make_file(const char *fname, struct file_list *flist,
F_GROUP(file) = st.st_gid; F_GROUP(file) = st.st_gid;
if (am_generator && st.st_uid == our_uid) if (am_generator && st.st_uid == our_uid)
file->flags |= FLAG_OWNED_BY_US; file->flags |= FLAG_OWNED_BY_US;
if (atimes_ndx)
F_ATIME(file) = st.st_atime;
if (basename != thisname) if (basename != thisname)
file->dirname = lastdir; file->dirname = lastdir;

View File

@@ -506,6 +506,9 @@ void itemize(const char *fnamecmp, struct file_struct *file, int ndx, int statre
: iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED) : iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !(iflags & ITEM_MATCHED)
&& (!(iflags & ITEM_XNAME_FOLLOWS) || *xname)) && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
iflags |= ITEM_REPORT_TIME; iflags |= ITEM_REPORT_TIME;
if (atimes_ndx && !S_ISDIR(file->mode) && !S_ISLNK(file->mode)
&& cmp_time(F_ATIME(file), 0, sxp->st.st_atime, 0) != 0)
iflags |= ITEM_REPORT_ATIME;
#if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST #if !defined HAVE_LCHMOD && !defined HAVE_SETATTRLIST
if (S_ISLNK(file->mode)) { if (S_ISLNK(file->mode)) {
; ;
@@ -916,6 +919,8 @@ static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
if (link_dest) { if (link_dest) {
if (!hard_link_one(file, fname, cmpbuf, 1)) if (!hard_link_one(file, fname, cmpbuf, 1))
goto try_a_copy; goto try_a_copy;
if (atimes_ndx)
set_file_attrs(fname, file, sxp, NULL, 0);
if (preserve_hard_links && F_IS_HLINKED(file)) if (preserve_hard_links && F_IS_HLINKED(file))
finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j); finish_hard_link(file, fname, ndx, &sxp->st, itemizing, code, j);
if (!maybe_ATTRS_REPORT && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) { if (!maybe_ATTRS_REPORT && (INFO_GTE(NAME, 2) || stdout_format_has_i > 1)) {
@@ -1120,35 +1125,40 @@ static int try_dests_non(struct file_struct *file, char *fname, int ndx,
static void list_file_entry(struct file_struct *f) static void list_file_entry(struct file_struct *f)
{ {
char permbuf[PERMSTRING_SIZE]; char permbuf[PERMSTRING_SIZE];
int64 len; const char *mtime_str = timestring(f->modtime);
int colwidth = human_readable ? 14 : 11; int size_width = human_readable ? 14 : 11;
int mtime_width = 1 + strlen(mtime_str);
int atime_width = atimes_ndx ? mtime_width : 0;
if (!F_IS_ACTIVE(f)) { if (!F_IS_ACTIVE(f)) {
/* this can happen if duplicate names were removed */ /* this can happen if duplicate names were removed */
return; return;
} }
permstring(permbuf, f->mode);
len = F_LENGTH(f);
/* TODO: indicate '+' if the entry has an ACL. */ /* TODO: indicate '+' if the entry has an ACL. */
if (missing_args == 2 && f->mode == 0) {
rprintf(FINFO, "%-*s %s\n",
10 + 1 + size_width + mtime_width + atime_width, "*missing",
f_name(f, NULL));
} else {
const char *atime_str = atimes_ndx && !S_ISDIR(f->mode) ? timestring(F_ATIME(f)) : "";
const char *arrow, *lnk;
permstring(permbuf, f->mode);
#ifdef SUPPORT_LINKS #ifdef SUPPORT_LINKS
if (preserve_links && S_ISLNK(f->mode)) { if (preserve_links && S_ISLNK(f->mode)) {
rprintf(FINFO, "%s %*s %s %s -> %s\n", arrow = " -> ";
permbuf, colwidth, human_num(len), lnk = F_SYMLINK(f);
timestring(f->modtime), f_name(f, NULL),
F_SYMLINK(f));
} else } else
#endif #endif
if (missing_args == 2 && f->mode == 0) { arrow = lnk = "";
rprintf(FINFO, "%-*s %s\n",
colwidth + 31, "*missing", rprintf(FINFO, "%s %*s %s%*s %s%s%s\n",
f_name(f, NULL)); permbuf, size_width, human_num(F_LENGTH(f)),
} else { timestring(f->modtime), atime_width, atime_str,
rprintf(FINFO, "%s %*s %s %s\n", f_name(f, NULL), arrow, lnk);
permbuf, colwidth, human_num(len),
timestring(f->modtime), f_name(f, NULL));
} }
} }
@@ -2064,8 +2074,13 @@ static void touch_up_dirs(struct file_list *flist, int ndx)
do_chmod(fname, file->mode); do_chmod(fname, file->mode);
if (need_retouch_dir_times) { if (need_retouch_dir_times) {
STRUCT_STAT st; STRUCT_STAT st;
if (link_stat(fname, &st, 0) == 0 && time_diff(&st, file)) if (link_stat(fname, &st, 0) == 0 && time_diff(&st, file)) {
set_modtime(fname, file->modtime, F_MOD_NSEC_or_0(file), file->mode); st.st_mtime = file->modtime;
#ifdef ST_MTIME_NSEC
st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file);
#endif
set_times(fname, &st);
}
} }
if (counter >= loopchk_limit) { if (counter >= loopchk_limit) {
if (allowed_lull) if (allowed_lull)

3
log.c
View File

@@ -716,7 +716,8 @@ static void log_formatted(enum logcode code, const char *format, const char *op,
c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p'; c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o'; c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g'; c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u'; c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.'
: S_ISLNK(file->mode) ? 'U' : 'u';
c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a'; c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x'; c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
c[11] = '\0'; c[11] = '\0';

View File

@@ -63,7 +63,9 @@ int preserve_specials = 0;
int preserve_uid = 0; int preserve_uid = 0;
int preserve_gid = 0; int preserve_gid = 0;
int preserve_times = 0; int preserve_times = 0;
int preserve_atimes = 0;
int update_only = 0; int update_only = 0;
int set_noatime = 0;
int cvs_exclude = 0; int cvs_exclude = 0;
int dry_run = 0; int dry_run = 0;
int do_xfers = 1; int do_xfers = 1;
@@ -711,6 +713,8 @@ void usage(enum logcode F)
rprintf(F," --specials preserve special files\n"); rprintf(F," --specials preserve special files\n");
rprintf(F," -D same as --devices --specials\n"); rprintf(F," -D same as --devices --specials\n");
rprintf(F," -t, --times preserve modification times\n"); rprintf(F," -t, --times preserve modification times\n");
rprintf(F," -U, --atimes preserve access (last-used) times\n");
rprintf(F," --set-noatime avoid changing the atime on accessed files\n");
rprintf(F," -O, --omit-dir-times omit directories from --times\n"); rprintf(F," -O, --omit-dir-times omit directories from --times\n");
rprintf(F," -J, --omit-link-times omit symlinks from --times\n"); rprintf(F," -J, --omit-link-times omit symlinks from --times\n");
rprintf(F," --super receiver attempts super-user activities\n"); rprintf(F," --super receiver attempts super-user activities\n");
@@ -872,6 +876,11 @@ static struct poptOption long_options[] = {
{"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 }, {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
{"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
{"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 }, {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
{"atimes", 'U', POPT_ARG_NONE, 0, 'U', 0, 0 },
{"no-atimes", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 },
{"no-U", 0, POPT_ARG_VAL, &preserve_atimes, 0, 0, 0 },
{"set-noatime", 0, POPT_ARG_VAL, &set_noatime, 1, 0, 0 },
{"no-set-noatime", 0, POPT_ARG_VAL, &set_noatime, 0, 0, 0 },
{"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 }, {"omit-dir-times", 'O', POPT_ARG_VAL, &omit_dir_times, 1, 0, 0 },
{"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, {"no-omit-dir-times",0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
{"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 }, {"no-O", 0, POPT_ARG_VAL, &omit_dir_times, 0, 0, 0 },
@@ -1543,6 +1552,11 @@ int parse_arguments(int *argc_p, const char ***argv_p)
itemize_changes++; itemize_changes++;
break; break;
case 'U':
if (++preserve_atimes > 1)
set_noatime = 1;
break;
case 'v': case 'v':
verbose++; verbose++;
break; break;
@@ -2493,6 +2507,11 @@ void server_options(char **args, int *argc_p)
argstr[x++] = 'D'; argstr[x++] = 'D';
if (preserve_times) if (preserve_times)
argstr[x++] = 't'; argstr[x++] = 't';
if (preserve_atimes) {
argstr[x++] = 'U';
if (preserve_atimes > 1)
argstr[x++] = 'U';
}
if (preserve_perms) if (preserve_perms)
argstr[x++] = 'p'; argstr[x++] = 'p';
else if (preserve_executability && am_sender) else if (preserve_executability && am_sender)
@@ -2831,6 +2850,9 @@ void server_options(char **args, int *argc_p)
if (preallocate_files && am_sender) if (preallocate_files && am_sender)
args[ac++] = "--preallocate"; args[ac++] = "--preallocate";
if (set_noatime && preserve_atimes <= 1)
args[ac++] = "--set-noatime";
if (ac > MAX_SERVER_ARGS) { /* Not possible... */ if (ac > MAX_SERVER_ARGS) { /* Not possible... */
rprintf(FERROR, "argc overflow in server_options().\n"); rprintf(FERROR, "argc overflow in server_options().\n");
exit_cleanup(RERR_MALLOC); exit_cleanup(RERR_MALLOC);

53
rsync.c
View File

@@ -63,6 +63,15 @@ iconv_t ic_chck = (iconv_t)-1;
iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1; iconv_t ic_send = (iconv_t)-1, ic_recv = (iconv_t)-1;
# endif # endif
#define UPDATED_OWNER (1<<0)
#define UPDATED_GROUP (1<<1)
#define UPDATED_MTIME (1<<2)
#define UPDATED_ATIME (1<<3)
#define UPDATED_ACLS (1<<4)
#define UPDATED_MODE (1<<5)
#define UPDATED_TIMES (UPDATED_MTIME|UPDATED_ATIME)
static const char *default_charset(void) static const char *default_charset(void)
{ {
# if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET # if defined HAVE_LIBCHARSET_H && defined HAVE_LOCALE_CHARSET
@@ -540,7 +549,10 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
keep_dirlinks && S_ISDIR(sxp->st.st_mode)); keep_dirlinks && S_ISDIR(sxp->st.st_mode));
} }
} }
updated = 1; if (change_uid)
updated |= UPDATED_OWNER;
if (change_gid)
updated |= UPDATED_GROUP;
} }
#ifdef SUPPORT_XATTRS #ifdef SUPPORT_XATTRS
@@ -553,24 +565,45 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
if (!preserve_times if (!preserve_times
|| (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode)) || (!(preserve_times & PRESERVE_DIR_TIMES) && S_ISDIR(sxp->st.st_mode))
|| (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode))) || (!(preserve_times & PRESERVE_LINK_TIMES) && S_ISLNK(sxp->st.st_mode)))
flags |= ATTRS_SKIP_MTIME; flags |= ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME;
else if (sxp != &sx2)
memcpy(&sx2.st, &sxp->st, sizeof (sx2.st));
if (!atimes_ndx || S_ISDIR(sxp->st.st_mode))
flags |= ATTRS_SKIP_ATIME;
if (!(flags & ATTRS_SKIP_MTIME) if (!(flags & ATTRS_SKIP_MTIME)
&& (sxp->st.st_mtime != file->modtime && (sxp->st.st_mtime != file->modtime
#ifdef ST_MTIME_NSEC #ifdef ST_MTIME_NSEC
|| (flags & ATTRS_SET_NANO && NSEC_BUMP(file) && (uint32)sxp->st.ST_MTIME_NSEC != F_MOD_NSEC(file)) || (flags & ATTRS_SET_NANO && NSEC_BUMP(file) && (uint32)sxp->st.ST_MTIME_NSEC != F_MOD_NSEC(file))
#endif #endif
)) { )) {
int ret = set_modtime(fname, file->modtime, F_MOD_NSEC_or_0(file), sxp->st.st_mode); sx2.st.st_mtime = file->modtime;
#ifdef ST_MTIME_NSEC
sx2.st.ST_MTIME_NSEC = F_MOD_NSEC_or_0(file);
#endif
updated |= UPDATED_MTIME;
}
if (!(flags & ATTRS_SKIP_ATIME)) {
time_t file_atime = F_ATIME(file);
if (cmp_time(sxp->st.st_atime, 0, file_atime, 0) != 0) {
sx2.st.st_atime = file_atime;
#ifdef ST_ATIME_NSEC
sx2.st.ST_ATIME_NSEC = 0;
#endif
updated |= UPDATED_ATIME;
}
}
if (updated & UPDATED_TIMES) {
int ret = set_times(fname, &sx2.st);
if (ret < 0) { if (ret < 0) {
rsyserr(FERROR_XFER, errno, "failed to set times on %s", rsyserr(FERROR_XFER, errno, "failed to set times on %s",
full_fname(fname)); full_fname(fname));
goto cleanup; goto cleanup;
} }
if (ret == 0) /* ret == 1 if symlink could not be set */ if (ret > 0) { /* ret == 1 if symlink could not be set */
updated = 1; updated &= ~UPDATED_TIMES;
else
file->flags |= FLAG_TIME_FAILED; file->flags |= FLAG_TIME_FAILED;
} }
}
#ifdef SUPPORT_ACLS #ifdef SUPPORT_ACLS
/* It's OK to call set_acl() now, even for a dir, as the generator /* It's OK to call set_acl() now, even for a dir, as the generator
@@ -581,7 +614,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
* need to chmod(). */ * need to chmod(). */
if (preserve_acls && !S_ISLNK(new_mode)) { if (preserve_acls && !S_ISLNK(new_mode)) {
if (set_acl(fname, file, sxp, new_mode) > 0) if (set_acl(fname, file, sxp, new_mode) > 0)
updated = 1; updated |= UPDATED_ACLS;
} }
#endif #endif
@@ -595,7 +628,7 @@ int set_file_attrs(const char *fname, struct file_struct *file, stat_x *sxp,
goto cleanup; goto cleanup;
} }
if (ret == 0) /* ret == 1 if symlink could not be set */ if (ret == 0) /* ret == 1 if symlink could not be set */
updated = 1; updated |= UPDATED_MODE;
} }
#endif #endif
@@ -676,7 +709,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
/* Change permissions before putting the file into place. */ /* Change permissions before putting the file into place. */
set_file_attrs(fnametmp, file, NULL, fnamecmp, set_file_attrs(fnametmp, file, NULL, fnamecmp,
ok_to_set_time ? ATTRS_SET_NANO : ATTRS_SKIP_MTIME); ok_to_set_time ? ATTRS_SET_NANO : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME);
/* move tmp file over real file */ /* move tmp file over real file */
if (DEBUG_GTE(RECV, 1)) if (DEBUG_GTE(RECV, 1))
@@ -701,7 +734,7 @@ int finish_transfer(const char *fname, const char *fnametmp,
do_set_file_attrs: do_set_file_attrs:
set_file_attrs(fnametmp, file, NULL, fnamecmp, set_file_attrs(fnametmp, file, NULL, fnamecmp,
ok_to_set_time ? ATTRS_SET_NANO : ATTRS_SKIP_MTIME); ok_to_set_time ? ATTRS_SET_NANO : ATTRS_SKIP_MTIME | ATTRS_SKIP_ATIME);
if (temp_copy_name) { if (temp_copy_name) {
if (do_rename(fnametmp, fname) < 0) { if (do_rename(fnametmp, fname) < 0) {

43
rsync.h
View File

@@ -62,6 +62,7 @@
#define XMIT_HLINK_FIRST (1<<12) /* protocols 30 - now (HLINKED files only) */ #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) (also protocol 30 w/'f' compat flag) */ #define XMIT_IO_ERROR_ENDLIST (1<<12) /* protocols 31*- now (w/XMIT_EXTENDED_FLAGS) (also protocol 30 w/'f' compat flag) */
#define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */ #define XMIT_MOD_NSEC (1<<13) /* protocols 31 - now */
#define XMIT_SAME_ATIME (1<<14) /* protocols ?? - now */
/* These flags are used in the live flist data. */ /* These flags are used in the live flist data. */
@@ -168,6 +169,7 @@
#define ATTRS_REPORT (1<<0) #define ATTRS_REPORT (1<<0)
#define ATTRS_SKIP_MTIME (1<<1) #define ATTRS_SKIP_MTIME (1<<1)
#define ATTRS_SET_NANO (1<<2) #define ATTRS_SET_NANO (1<<2)
#define ATTRS_SKIP_ATIME (1<<3)
#define FULL_FLUSH 1 #define FULL_FLUSH 1
#define NORMAL_FLUSH 0 #define NORMAL_FLUSH 0
@@ -394,10 +396,13 @@ enum delret {
#ifdef CAN_SET_NSEC #ifdef CAN_SET_NSEC
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC #ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
#define ST_MTIME_NSEC st_mtim.tv_nsec #define ST_MTIME_NSEC st_mtim.tv_nsec
#define ST_ATIME_NSEC st_atim.tv_nsec
#elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC) #elif defined(HAVE_STRUCT_STAT_ST_MTIMENSEC)
#define ST_MTIME_NSEC st_mtimensec #define ST_MTIME_NSEC st_mtimensec
#define ST_ATIME_NSEC st_atimensec
#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
#define ST_MTIME_NSEC st_mtimespec.tv_nsec #define ST_MTIME_NSEC st_mtimespec.tv_nsec
#define ST_ATIME_NSEC st_atimespec.tv_nsec
#endif #endif
#endif #endif
@@ -700,9 +705,29 @@ struct ht_int64_node {
#endif #endif
#endif #endif
#if SIZEOF_CHARP == 4
# define PTRS_ARE_32 1
# define PTR_EXTRA_CNT 1
#elif SIZEOF_CHARP == 8
# define PTRS_ARE_64 1
# define PTR_EXTRA_CNT EXTRA64_CNT
#else
# error Character pointers are not 4 or 8 bytes.
#endif
union file_extras { union file_extras {
int32 num; int32 num;
uint32 unum; uint32 unum;
#ifdef PTRS_ARE_32
const char* ptr;
#endif
};
union file_extras64 {
int64 num;
#ifdef PTRS_ARE_64
const char* ptr;
#endif
}; };
struct file_struct { struct file_struct {
@@ -716,6 +741,9 @@ struct file_struct {
extern int file_extra_cnt; extern int file_extra_cnt;
extern int inc_recurse; extern int inc_recurse;
extern int atimes_ndx;
extern int pathname_ndx;
extern int depth_ndx;
extern int uid_ndx; extern int uid_ndx;
extern int gid_ndx; extern int gid_ndx;
extern int acls_ndx; extern int acls_ndx;
@@ -723,14 +751,18 @@ extern int xattrs_ndx;
#define FILE_STRUCT_LEN (offsetof(struct file_struct, basename)) #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename))
#define EXTRA_LEN (sizeof (union file_extras)) #define EXTRA_LEN (sizeof (union file_extras))
#define PTR_EXTRA_CNT ((sizeof (char *) + EXTRA_LEN - 1) / EXTRA_LEN)
#define DEV_EXTRA_CNT 2 #define DEV_EXTRA_CNT 2
#define DIRNODE_EXTRA_CNT 3 #define DIRNODE_EXTRA_CNT 3
#define EXTRA64_CNT ((sizeof (union file_extras64) + EXTRA_LEN - 1) / EXTRA_LEN)
#define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN) #define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN)
#define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (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 OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump))
/* These are guaranteed to be allocated first in the array so that they
* are aligned for direct int64-pointer access. */
#define REQ_EXTRA64(f,ndx) ((union file_extras64*)REQ_EXTRA(f,ndx))
#define NSEC_BUMP(f) ((f)->flags & FLAG_MOD_NSEC ? 1 : 0) #define NSEC_BUMP(f) ((f)->flags & FLAG_MOD_NSEC ? 1 : 0)
#define LEN64_BUMP(f) ((f)->flags & FLAG_LENGTH64 ? 1 : 0) #define LEN64_BUMP(f) ((f)->flags & FLAG_LENGTH64 ? 1 : 0)
#define START_BUMP(f) (NSEC_BUMP(f) + LEN64_BUMP(f)) #define START_BUMP(f) (NSEC_BUMP(f) + LEN64_BUMP(f))
@@ -752,10 +784,14 @@ extern int xattrs_ndx;
#define F_SYMLINK(f) ((f)->basename + strlen((f)->basename) + 1) #define F_SYMLINK(f) ((f)->basename + strlen((f)->basename) + 1)
/* The sending side always has this available: */ /* The sending side always has this available: */
#define F_PATHNAME(f) (*(const char**)REQ_EXTRA(f, PTR_EXTRA_CNT)) #ifdef PTRS_ARE_32
#define F_PATHNAME(f) REQ_EXTRA(f, pathname_ndx)->ptr
#else
#define F_PATHNAME(f) REQ_EXTRA64(f, pathname_ndx)->ptr
#endif
/* The receiving side always has this available: */ /* The receiving side always has this available: */
#define F_DEPTH(f) REQ_EXTRA(f, 1)->num #define F_DEPTH(f) REQ_EXTRA(f, depth_ndx)->num
/* When the associated option is on, all entries will have these present: */ /* When the associated option is on, all entries will have these present: */
#define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum #define F_OWNER(f) REQ_EXTRA(f, uid_ndx)->unum
@@ -763,6 +799,7 @@ extern int xattrs_ndx;
#define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num #define F_ACL(f) REQ_EXTRA(f, acls_ndx)->num
#define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num #define F_XATTR(f) REQ_EXTRA(f, xattrs_ndx)->num
#define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num #define F_NDX(f) REQ_EXTRA(f, unsort_ndx)->num
#define F_ATIME(f) REQ_EXTRA64(f, atimes_ndx)->num
/* These items are per-entry optional: */ /* These items are per-entry optional: */
#define F_HL_GNUM(f) OPT_EXTRA(f, START_BUMP(f))->num /* non-dirs */ #define F_HL_GNUM(f) OPT_EXTRA(f, START_BUMP(f))->num /* non-dirs */

View File

@@ -378,6 +378,8 @@ to the detailed description below for a complete description. verb(
--specials preserve special files --specials preserve special files
-D same as --devices --specials -D same as --devices --specials
-t, --times preserve modification times -t, --times preserve modification times
-U, --atimes preserve access (use) times
--set-noatime avoid changing the atime on accessed files
-O, --omit-dir-times omit directories from --times -O, --omit-dir-times omit directories from --times
-J, --omit-link-times omit symlinks from --times -J, --omit-link-times omit symlinks from --times
--super receiver attempts super-user activities --super receiver attempts super-user activities
@@ -1240,6 +1242,25 @@ cause the next transfer to behave as if it used bf(-I), causing all files to be
updated (though rsync's delta-transfer algorithm will make the update fairly efficient updated (though rsync's delta-transfer algorithm will make the update fairly efficient
if the files haven't actually changed, you're much better off using bf(-t)). if the files haven't actually changed, you're much better off using bf(-t)).
dit(bf(-U, --atimes)) This tells rsync to set the access (use) times of the
destination files to the same value as the source files.
If repeated, it also sets the bf(--set-noatime) option, which can help you
to make the sending and receiving systems have the same access times on the
transferred files without needing to run rsync an extra time after a file is
transferred.
Note that some older rsync versions (prior to 3.1.4) may have been built with
a pre-release bf(--atimes) patch that does not imply bf(--set-noatime) when
this option is repeated.
dit(bf(--set-noatime)) This tells rsync to open files with the O_NOATIME
flag (on systems that support it) to avoid changing the access time of the
files that are being transferred. If your OS does not support the O_NOATIME
flag then rsync will silently ignore this option. Note also that some
filesystems are mounted to avoid updating the atime on read access even
without the O_NOATIME flag being set.
dit(bf(-O, --omit-dir-times)) This tells rsync to omit directories when dit(bf(-O, --omit-dir-times)) This tells rsync to omit directories when
it is preserving modification times (see bf(--times)). If NFS is sharing it is preserving modification times (see bf(--times)). If NFS is sharing
the directories on the receiving side, it is a good idea to use bf(-O). the directories on the receiving side, it is a good idea to use bf(-O).
@@ -2263,7 +2284,10 @@ quote(itemization(
sender's value (requires bf(--owner) and super-user privileges). sender's value (requires bf(--owner) and super-user privileges).
it() A bf(g) means the group is different and is being updated to the it() A bf(g) means the group is different and is being updated to the
sender's value (requires bf(--group) and the authority to set the group). sender's value (requires bf(--group) and the authority to set the group).
it() The bf(u) slot is reserved for future use. it() A bf(u) means the access (use) time is different and is being updated to
the sender's value (requires bf(--atimes)). An alternate value of bf(U)
means that the access time will be set to the transfer time, which happens
when a symlink or directory is updated.
it() The bf(a) means that the ACL information changed. it() The bf(a) means that the ACL information changed.
it() The bf(x) means that the extended attribute information changed. it() The bf(x) means that the extended attribute information changed.
)) ))

View File

@@ -42,6 +42,7 @@ extern int inplace;
extern int preallocate_files; extern int preallocate_files;
extern int preserve_perms; extern int preserve_perms;
extern int preserve_executability; extern int preserve_executability;
extern int set_noatime;
#ifndef S_BLKSIZE #ifndef S_BLKSIZE
# if defined hpux || defined __hpux__ || defined __hpux # if defined hpux || defined __hpux__ || defined __hpux
@@ -202,6 +203,11 @@ int do_open(const char *pathname, int flags, mode_t mode)
RETURN_ERROR_IF_RO_OR_LO; RETURN_ERROR_IF_RO_OR_LO;
} }
#ifdef O_NOATIME
if (set_noatime)
flags |= O_NOATIME;
#endif
return open(pathname, flags | O_BINARY, mode); return open(pathname, flags | O_BINARY, mode);
} }
@@ -380,54 +386,78 @@ int do_setattrlist_times(const char *fname, time_t modtime, uint32 mod_nsec)
#endif #endif
#ifdef HAVE_UTIMENSAT #ifdef HAVE_UTIMENSAT
int do_utimensat(const char *fname, time_t modtime, uint32 mod_nsec) int do_utimensat(const char *fname, STRUCT_STAT *stp)
{ {
struct timespec t[2]; struct timespec t[2];
if (dry_run) return 0; if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO; RETURN_ERROR_IF_RO_OR_LO;
t[0].tv_sec = 0; t[0].tv_sec = stp->st_atime;
t[0].tv_nsec = UTIME_NOW; #ifdef ST_ATIME_NSEC
t[1].tv_sec = modtime; t[0].tv_nsec = stp->ST_ATIME_NSEC;
t[1].tv_nsec = mod_nsec; #else
t[0].tv_nsec = 0;
#endif
t[1].tv_sec = stp->st_mtime;
#ifdef ST_MTIME_NSEC
t[1].tv_nsec = stp->ST_MTIME_NSEC;
#else
t[1].tv_nsec = 0;
#endif
return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW); return utimensat(AT_FDCWD, fname, t, AT_SYMLINK_NOFOLLOW);
} }
#endif #endif
#ifdef HAVE_LUTIMES #ifdef HAVE_LUTIMES
int do_lutimes(const char *fname, time_t modtime, uint32 mod_nsec) int do_lutimes(const char *fname, STRUCT_STAT *stp)
{ {
struct timeval t[2]; struct timeval t[2];
if (dry_run) return 0; if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO; RETURN_ERROR_IF_RO_OR_LO;
t[0].tv_sec = time(NULL); t[0].tv_sec = stp->st_atime;
#ifdef ST_ATIME_NSEC
t[0].tv_usec = stp->ST_ATIME_NSEC / 1000;
#else
t[0].tv_usec = 0; t[0].tv_usec = 0;
t[1].tv_sec = modtime; #endif
t[1].tv_usec = mod_nsec / 1000; t[1].tv_sec = stp->st_mtime;
#ifdef ST_MTIME_NSEC
t[1].tv_usec = stp->ST_MTIME_NSEC / 1000;
#else
t[1].tv_usec = 0;
#endif
return lutimes(fname, t); return lutimes(fname, t);
} }
#endif #endif
#ifdef HAVE_UTIMES #ifdef HAVE_UTIMES
int do_utimes(const char *fname, time_t modtime, uint32 mod_nsec) int do_utimes(const char *fname, STRUCT_STAT *stp)
{ {
struct timeval t[2]; struct timeval t[2];
if (dry_run) return 0; if (dry_run) return 0;
RETURN_ERROR_IF_RO_OR_LO; RETURN_ERROR_IF_RO_OR_LO;
t[0].tv_sec = time(NULL); t[0].tv_sec = stp->st_atime;
#ifdef ST_ATIME_NSEC
t[0].tv_usec = stp->ST_ATIME_NSEC / 1000;
#else
t[0].tv_usec = 0; t[0].tv_usec = 0;
t[1].tv_sec = modtime; #endif
t[1].tv_usec = mod_nsec / 1000; t[1].tv_sec = stp->st_mtime;
#ifdef ST_MTIME_NSEC
t[1].tv_usec = stp->ST_MTIME_NSEC / 1000;
#else
t[1].tv_usec = 0;
#endif
return utimes(fname, t); return utimes(fname, t);
} }
#elif defined HAVE_UTIME #elif defined HAVE_UTIME
int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec)) int do_utime(const char *fname, STRUCT_STAT *stp)
{ {
#ifdef HAVE_STRUCT_UTIMBUF #ifdef HAVE_STRUCT_UTIMBUF
struct utimbuf tbuf; struct utimbuf tbuf;
@@ -439,12 +469,12 @@ int do_utime(const char *fname, time_t modtime, UNUSED(uint32 mod_nsec))
RETURN_ERROR_IF_RO_OR_LO; RETURN_ERROR_IF_RO_OR_LO;
# ifdef HAVE_STRUCT_UTIMBUF # ifdef HAVE_STRUCT_UTIMBUF
tbuf.actime = time(NULL); tbuf.actime = stp->st_atime;
tbuf.modtime = modtime; tbuf.modtime = stp->st_mtime;
return utime(fname, &tbuf); return utime(fname, &tbuf);
# else # else
t[0] = time(NULL); t[0] = stp->st_atime;
t[1] = modtime; t[1] = stp->st_mtime;
return utime(fname, t); return utime(fname, t);
# endif # endif
} }

View File

@@ -31,6 +31,7 @@ int module_dirlen = 0;
int preserve_acls = 0; int preserve_acls = 0;
int preserve_times = 0; int preserve_times = 0;
int preserve_xattrs = 0; int preserve_xattrs = 0;
int set_noatime = 0;
char *partial_dir; char *partial_dir;
char *module_dir; char *module_dir;
filter_rule_list daemon_filter_list; filter_rule_list daemon_filter_list;

17
testsuite/atimes.test Normal file
View File

@@ -0,0 +1,17 @@
#! /bin/sh
# Test rsync copying atimes
. "$suitedir/rsync.fns"
mkdir "$fromdir"
touch "$fromdir/foo"
touch -a -t 200102031717.42 "$fromdir/foo"
TLS_ARGS=--atimes
checkit "$RSYNC -rtUgvvv \"$fromdir/\" \"$todir/\"" "$fromdir" "$todir"
# The script would have aborted on error, so getting here means we've won.
exit 0

View File

@@ -27,7 +27,7 @@ outfile="$scratchdir/rsync.out"
SSH="src/support/lsh.sh --no-cd" SSH="src/support/lsh.sh --no-cd"
FILE_REPL='s/^\([^d][^ ]*\) *\(..........[0-9]\) /\1 \2 /' FILE_REPL='s/^\([^d][^ ]*\) *\(..........[0-9]\) /\1 \2 /'
DIR_REPL='s/^\(d[^ ]*\) *[0-9][.,0-9]* /\1 DIR /' DIR_REPL='s/^\(d[^ ]*\) *[0-9][.,0-9]* /\1 DIR /'
LS_REPL='s;[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9];####/##/## ##:##:##;' LS_REPL='s;[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] ;####/##/## ##:##:## ;g'
build_rsyncd_conf build_rsyncd_conf
@@ -91,3 +91,12 @@ drwxr-xr-x DIR ####/##/## ##:##:## foo
EOT EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed" diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
$RSYNC -rU localhost::test-from/f* \
| sed "$FILE_REPL" | sed "$DIR_REPL" | sed "$LS_REPL" \
| tee "$outfile"
cat <<EOT >"$chkfile"
drwxr-xr-x DIR ####/##/## ##:##:## foo
-rw-r--r-- 4 ####/##/## ##:##:## ####/##/## ##:##:## foo/one
EOT
diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"

View File

@@ -219,6 +219,14 @@ checkit() {
# We can just write everything to stdout/stderr, because the # We can just write everything to stdout/stderr, because the
# wrapper hides it unless there is a problem. # wrapper hides it unless there is a problem.
case "x$TLS_ARGS" in
*--atimes*)
( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
;;
*)
;;
esac
echo "Running: \"$1\"" echo "Running: \"$1\""
eval "$1" eval "$1"
status=$? status=$?
@@ -226,10 +234,17 @@ checkit() {
failed="$failed status=$status" failed="$failed status=$status"
fi fi
case "x$TLS_ARGS" in
*--atimes*)
;;
*)
( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
;;
esac
echo "-------------" echo "-------------"
echo "check how the directory listings compare with diff:" echo "check how the directory listings compare with diff:"
echo "" echo ""
( cd "$2" && rsync_ls_lR . ) > "$tmpdir/ls-from"
( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to" ( cd "$3" && rsync_ls_lR . ) > "$tmpdir/ls-to"
diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed="$failed dir-diff" diff $diffopt "$tmpdir/ls-from" "$tmpdir/ls-to" || failed="$failed dir-diff"

76
tls.c
View File

@@ -52,6 +52,7 @@ int nsec_times = 0;
int preserve_perms = 0; int preserve_perms = 0;
int preserve_executability = 0; int preserve_executability = 0;
int preallocate_files = 0; int preallocate_files = 0;
int set_noatime = 0;
int inplace = 0; int inplace = 0;
#ifdef SUPPORT_XATTRS #ifdef SUPPORT_XATTRS
@@ -111,6 +112,8 @@ static int stat_xattr(const char *fname, STRUCT_STAT *fst)
#endif #endif
static int display_atimes = 0;
static void failed(char const *what, char const *where) static void failed(char const *what, char const *where)
{ {
fprintf(stderr, PROGRAM ": %s %s: %s\n", fprintf(stderr, PROGRAM ": %s %s: %s\n",
@@ -118,13 +121,38 @@ static void failed(char const *what, char const *where)
exit(1); exit(1);
} }
static void storetime(char *dest, size_t destsize, time_t t, int nsecs)
{
if (t) {
int len;
struct tm *mt = gmtime(&t);
len = snprintf(dest, destsize,
" %04d-%02d-%02d %02d:%02d:%02d",
(int)mt->tm_year + 1900,
(int)mt->tm_mon + 1,
(int)mt->tm_mday,
(int)mt->tm_hour,
(int)mt->tm_min,
(int)mt->tm_sec);
if (nsecs >= 0 && len >= 0)
snprintf(dest + len, destsize - len, ".%09d", nsecs);
} else {
int has_nsecs = nsecs >= 0 ? 1 : 0;
int len = MIN(20 + 10*has_nsecs, (int)destsize - 1);
memset(dest, ' ', len);
dest[len] = '\0';
}
}
static void list_file(const char *fname) static void list_file(const char *fname)
{ {
STRUCT_STAT buf; STRUCT_STAT buf;
char permbuf[PERMSTRING_SIZE]; char permbuf[PERMSTRING_SIZE];
struct tm *mt; char mtimebuf[50];
char datebuf[50]; char atimebuf[50];
char linkbuf[4096]; char linkbuf[4096];
int nsecs;
if (do_lstat(fname, &buf) < 0) if (do_lstat(fname, &buf) < 0)
failed("stat", fname); failed("stat", fname);
@@ -150,58 +178,47 @@ static void list_file(const char *fname)
buf.st_uid = buf.st_gid = 0; buf.st_uid = buf.st_gid = 0;
strlcpy(linkbuf, " -> ", sizeof linkbuf); strlcpy(linkbuf, " -> ", sizeof linkbuf);
/* const-cast required for silly UNICOS headers */ /* const-cast required for silly UNICOS headers */
len = do_readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4); len = do_readlink((char*)fname, linkbuf+4, sizeof linkbuf - 4);
if (len == -1) if (len == -1)
failed("do_readlink", fname); failed("do_readlink", fname);
else else
/* it's not nul-terminated */ /* it's not nul-terminated */
linkbuf[4+len] = 0; linkbuf[4+len] = 0;
} else { } else {
linkbuf[0] = 0; linkbuf[0] = '\0';
} }
permstring(permbuf, buf.st_mode); permstring(permbuf, buf.st_mode);
if (buf.st_mtime) {
int len;
mt = gmtime(&buf.st_mtime);
len = snprintf(datebuf, sizeof datebuf,
"%04d-%02d-%02d %02d:%02d:%02d",
(int)mt->tm_year + 1900,
(int)mt->tm_mon + 1,
(int)mt->tm_mday,
(int)mt->tm_hour,
(int)mt->tm_min,
(int)mt->tm_sec);
#ifdef ST_MTIME_NSEC #ifdef ST_MTIME_NSEC
if (nsec_times) { if (nsec_times)
snprintf(datebuf + len, sizeof datebuf - len, nsecs = (int)buf.ST_MTIME_NSEC;
".%09d", (int)buf.ST_MTIME_NSEC); else
}
#endif #endif
} else { nsecs = -1;
int len = MIN(19 + 9*nsec_times, (int)sizeof datebuf - 1); storetime(mtimebuf, sizeof mtimebuf, buf.st_mtime, nsecs);
memset(datebuf, ' ', len); if (display_atimes)
datebuf[len] = '\0'; storetime(atimebuf, sizeof atimebuf, S_ISDIR(buf.st_mode) ? 0 : buf.st_atime, -1);
} else
atimebuf[0] = '\0';
/* TODO: Perhaps escape special characters in fname? */ /* TODO: Perhaps escape special characters in fname? */
printf("%s ", permbuf); printf("%s ", permbuf);
if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) { if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
printf("%5ld,%6ld", printf("%5ld,%6ld",
(long)major(buf.st_rdev), (long)major(buf.st_rdev),
(long)minor(buf.st_rdev)); (long)minor(buf.st_rdev));
} else } else
printf("%15s", do_big_num(buf.st_size, 1, NULL)); printf("%15s", do_big_num(buf.st_size, 1, NULL));
printf(" %6ld.%-6ld %6ld %s %s%s\n",
printf(" %6ld.%-6ld %6ld%s%s %s%s\n",
(long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink, (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
datebuf, fname, linkbuf); mtimebuf, atimebuf, fname, linkbuf);
} }
static struct poptOption long_options[] = { static struct poptOption long_options[] = {
/* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
{"atimes", 'U', POPT_ARG_NONE, &display_atimes, 0, 0, 0},
{"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 }, {"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 },
{"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 }, {"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 },
#ifdef SUPPORT_XATTRS #ifdef SUPPORT_XATTRS
@@ -220,6 +237,7 @@ static void NORETURN tls_usage(int ret)
fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n"); fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n");
fprintf(F,"Trivial file listing program for portably checking rsync\n"); fprintf(F,"Trivial file listing program for portably checking rsync\n");
fprintf(F,"\nOptions:\n"); fprintf(F,"\nOptions:\n");
fprintf(F," -U, --atimes display access (last-used) times\n");
fprintf(F," -l, --link-times display the time on a symlink\n"); fprintf(F," -l, --link-times display the time on a symlink\n");
fprintf(F," -L, --link-owner display the owner+group on a symlink\n"); fprintf(F," -L, --link-owner display the owner+group on a symlink\n");
#ifdef SUPPORT_XATTRS #ifdef SUPPORT_XATTRS

View File

@@ -29,6 +29,7 @@ int list_only = 0;
int preserve_perms = 0; int preserve_perms = 0;
int preserve_executability = 0; int preserve_executability = 0;
int preallocate_files = 0; int preallocate_files = 0;
int set_noatime = 0;
int inplace = 0; int inplace = 0;
int int

35
util.c
View File

@@ -117,14 +117,15 @@ void print_child_argv(const char *prefix, char **cmd)
/* This returns 0 for success, 1 for a symlink if symlink time-setting /* This returns 0 for success, 1 for a symlink if symlink time-setting
* is not possible, or -1 for any other error. */ * is not possible, or -1 for any other error. */
int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode) int set_times(const char *fname, STRUCT_STAT *stp)
{ {
static int switch_step = 0; static int switch_step = 0;
if (DEBUG_GTE(TIME, 1)) { if (DEBUG_GTE(TIME, 1)) {
rprintf(FINFO, "set modtime of %s to (%ld) %s", rprintf(FINFO,
fname, (long)modtime, "set modtime, atime of %s to (%ld) %s, (%ld) %s\n",
asctime(localtime(&modtime))); fname, (long)stp->st_mtime,
timestring(stp->st_mtime), (long)stp->st_atime, timestring(stp->st_atime));
} }
switch (switch_step) { switch (switch_step) {
@@ -139,7 +140,7 @@ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode)
#ifdef HAVE_UTIMENSAT #ifdef HAVE_UTIMENSAT
#include "case_N.h" #include "case_N.h"
if (do_utimensat(fname, modtime, mod_nsec) == 0) if (do_utimensat(fname, stp) == 0)
break; break;
if (errno != ENOSYS) if (errno != ENOSYS)
return -1; return -1;
@@ -148,7 +149,7 @@ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode)
#ifdef HAVE_LUTIMES #ifdef HAVE_LUTIMES
#include "case_N.h" #include "case_N.h"
if (do_lutimes(fname, modtime, mod_nsec) == 0) if (do_lutimes(fname, stp) == 0)
break; break;
if (errno != ENOSYS) if (errno != ENOSYS)
return -1; return -1;
@@ -159,16 +160,16 @@ int set_modtime(const char *fname, time_t modtime, uint32 mod_nsec, mode_t mode)
switch_step++; switch_step++;
if (preserve_times & PRESERVE_LINK_TIMES) { if (preserve_times & PRESERVE_LINK_TIMES) {
preserve_times &= ~PRESERVE_LINK_TIMES; preserve_times &= ~PRESERVE_LINK_TIMES;
if (S_ISLNK(mode)) if (S_ISLNK(stp->st_mode))
return 1; return 1;
} }
#include "case_N.h" #include "case_N.h"
#ifdef HAVE_UTIMES #ifdef HAVE_UTIMES
if (do_utimes(fname, modtime, mod_nsec) == 0) if (do_utimes(fname, stp) == 0)
break; break;
#else #else
if (do_utime(fname, modtime, mod_nsec) == 0) if (do_utime(fname, stp) == 0)
break; break;
#endif #endif
@@ -1332,18 +1333,14 @@ int unsafe_symlink(const char *dest, const char *src)
/* Return the date and time as a string. Some callers tweak returned buf. */ /* Return the date and time as a string. Some callers tweak returned buf. */
char *timestring(time_t t) char *timestring(time_t t)
{ {
static char TimeBuf[200]; static int ndx = 0;
static char buffers[4][20]; /* We support 4 simultaneous timestring results. */
char *TimeBuf = buffers[ndx = (ndx + 1) % 4];
struct tm *tm = localtime(&t); struct tm *tm = localtime(&t);
char *p;
#ifdef HAVE_STRFTIME snprintf(TimeBuf, sizeof buffers[0], "%4d/%02d/%02d %02d:%02d:%02d",
strftime(TimeBuf, sizeof TimeBuf - 1, "%Y/%m/%d %H:%M:%S", tm); (int)tm->tm_year + 1900, (int)tm->tm_mon + 1, (int)tm->tm_mday,
#else (int)tm->tm_hour, (int)tm->tm_min, (int)tm->tm_sec);
strlcpy(TimeBuf, asctime(tm), sizeof TimeBuf);
#endif
if ((p = strchr(TimeBuf, '\n')) != NULL)
*p = '\0';
return TimeBuf; return TimeBuf;
} }