Don't filter time stamps through the resolution supported
by struct stat; keep them to full nanosecond resolution. This affects behavior only on older hosts or file systems that have lower-resolution time stamps. * src/common.h (OLDER_STAT_TIME): Parenthesize arg. (OLDER_TAR_STAT_TIME): New macro. (code_timespec): New function. (BILLION, LOG10_BILLION, TIMESPEC_STRSIZE_BOUND): New constants. * src/compare.c (diff_file): Use full time stamp resolution. * src/create.c (start_header, dump_file0): Likewise. (start_header, dump_file0): Adjust to new structure layout. (dump_regular_finish): Simplify by using timespec_cmp. * src/extract.c (struct delayed_set_stat): Don't store stat info that we don't need, to save space. All uses changed. (struct delayed_set_stat, struct delayed_link, file_newer_p): (create_placeholder_file, extract_link, apply_delayed_links): Use full time stamp resolution. (check_time): Use code_timespec rather than rolling our own code. (set_stat, delay_set_stat): Arg now points to tar_stat_info to avoid losing time information. All callers changed. * src/list.c (read_and, decode_header, print_heaeder): Use full time stamp resolution. * src/misc.c (code_timespec): New function. * src/tar.h (struct tar_stat_info): Record atime, mtime, ctime separately, for benefit of hosts with lower resolution. * src/update.c (update_archive): Use full time stamp resolution. * src/xheader.c (code_time): Use new code_timespec function to simplify code. (atime_coder, atime_decoder, ctime_coder, ctime_decoder): (mtime_coder, mtime_decoder): Use full time stamp resolution. Report time stamps to full resolution in environment. Report memory allocation failures rather than ignoring them. * src/system.c (time_to_env): New function. (oct_to_env, str_to_env, chr_to_env): Report memory allocation failures. (stat_to_env): Report full resolution in time stamps.
This commit is contained in:
39
ChangeLog
39
ChangeLog
@@ -1,3 +1,42 @@
|
||||
2005-09-16 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Don't filter time stamps through the resolution supported
|
||||
by struct stat; keep them to full nanosecond resolution.
|
||||
This affects behavior only on older hosts or file systems
|
||||
that have lower-resolution time stamps.
|
||||
* src/common.h (OLDER_STAT_TIME): Parenthesize arg.
|
||||
(OLDER_TAR_STAT_TIME): New macro.
|
||||
(code_timespec): New function.
|
||||
(BILLION, LOG10_BILLION, TIMESPEC_STRSIZE_BOUND): New constants.
|
||||
* src/compare.c (diff_file): Use full time stamp resolution.
|
||||
* src/create.c (start_header, dump_file0): Likewise.
|
||||
(start_header, dump_file0): Adjust to new structure layout.
|
||||
(dump_regular_finish): Simplify by using timespec_cmp.
|
||||
* src/extract.c (struct delayed_set_stat): Don't store stat info
|
||||
that we don't need, to save space. All uses changed.
|
||||
(struct delayed_set_stat, struct delayed_link, file_newer_p):
|
||||
(create_placeholder_file, extract_link, apply_delayed_links):
|
||||
Use full time stamp resolution.
|
||||
(check_time): Use code_timespec rather than rolling our own code.
|
||||
(set_stat, delay_set_stat): Arg now points to tar_stat_info to
|
||||
avoid losing time information. All callers changed.
|
||||
* src/list.c (read_and, decode_header, print_heaeder):
|
||||
Use full time stamp resolution.
|
||||
* src/misc.c (code_timespec): New function.
|
||||
* src/tar.h (struct tar_stat_info): Record atime, mtime, ctime
|
||||
separately, for benefit of hosts with lower resolution.
|
||||
* src/update.c (update_archive): Use full time stamp resolution.
|
||||
* src/xheader.c (code_time): Use new code_timespec function
|
||||
to simplify code.
|
||||
(atime_coder, atime_decoder, ctime_coder, ctime_decoder):
|
||||
(mtime_coder, mtime_decoder): Use full time stamp resolution.
|
||||
|
||||
Report time stamps to full resolution in environment.
|
||||
Report memory allocation failures rather than ignoring them.
|
||||
* src/system.c (time_to_env): New function.
|
||||
(oct_to_env, str_to_env, chr_to_env): Report memory allocation failures.
|
||||
(stat_to_env): Report full resolution in time stamps.
|
||||
|
||||
2005-09-16 Paul Eggert <eggert@cs.ucla.edu>
|
||||
|
||||
Merge changes from gnulib for file system sub-second time stamps.
|
||||
|
||||
10
src/common.h
10
src/common.h
@@ -189,7 +189,11 @@ GLOBAL struct timespec newer_mtime_option;
|
||||
/* Return true if the struct stat ST's M time is less than
|
||||
newer_mtime_option. */
|
||||
#define OLDER_STAT_TIME(st, m) \
|
||||
(timespec_cmp (get_stat_##m##time (&st), newer_mtime_option) < 0)
|
||||
(timespec_cmp (get_stat_##m##time (&(st)), newer_mtime_option) < 0)
|
||||
|
||||
/* Likewise, for struct tar_stat_info ST. */
|
||||
#define OLDER_TAR_STAT_TIME(st, m) \
|
||||
(timespec_cmp ((st).m##time, newer_mtime_option) < 0)
|
||||
|
||||
/* Zero if there is no recursion, otherwise FNM_LEADING_DIR. */
|
||||
GLOBAL int recursion_option;
|
||||
@@ -490,6 +494,10 @@ char *quote_copy_string (const char *);
|
||||
int unquote_string (char *);
|
||||
|
||||
void code_ns_fraction (int, char *);
|
||||
char const *code_timespec (struct timespec, char *);
|
||||
enum { BILLION = 1000000000, LOG10_BILLION = 9 };
|
||||
enum { TIMESPEC_STRSIZE_BOUND =
|
||||
UINTMAX_STRSIZE_BOUND + LOG10_BILLION + sizeof "-." - 1 };
|
||||
|
||||
size_t dot_dot_prefix_len (char const *);
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ diff_file (void)
|
||||
if (!sys_compare_gid (&stat_data, ¤t_stat_info.stat))
|
||||
report_difference (¤t_stat_info, _("Gid differs"));
|
||||
|
||||
if (stat_data.st_mtime != current_stat_info.stat.st_mtime)
|
||||
if (timespec_cmp (get_stat_mtime (&stat_data), current_stat_info.mtime))
|
||||
report_difference (¤t_stat_info, _("Mod time differs"));
|
||||
if (current_header->header.typeflag != GNUTYPE_SPARSE &&
|
||||
stat_data.st_size != current_stat_info.stat.st_size)
|
||||
|
||||
23
src/create.c
23
src/create.c
@@ -353,7 +353,7 @@ string_to_chars (char const *str, char *p, size_t s)
|
||||
/* A file is considered dumpable if it is sparse and both --sparse and --totals
|
||||
are specified.
|
||||
Otherwise, it is dumpable unless any of the following conditions occur:
|
||||
|
||||
|
||||
a) it is empty *and* world-readable, or
|
||||
b) current archive is /dev/null */
|
||||
|
||||
@@ -698,7 +698,7 @@ start_header (struct tar_stat_info *st)
|
||||
}
|
||||
|
||||
{
|
||||
struct timespec mtime = get_stat_mtime (&st->stat);
|
||||
struct timespec mtime = st->mtime;
|
||||
if (archive_format == POSIX_FORMAT)
|
||||
{
|
||||
if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec
|
||||
@@ -747,8 +747,8 @@ start_header (struct tar_stat_info *st)
|
||||
else if (incremental_option)
|
||||
if (archive_format == OLDGNU_FORMAT || archive_format == GNU_FORMAT)
|
||||
{
|
||||
TIME_TO_CHARS (st->stat.st_atime, header->oldgnu_header.atime);
|
||||
TIME_TO_CHARS (st->stat.st_ctime, header->oldgnu_header.ctime);
|
||||
TIME_TO_CHARS (st->atime.tv_sec, header->oldgnu_header.atime);
|
||||
TIME_TO_CHARS (st->ctime.tv_sec, header->oldgnu_header.ctime);
|
||||
}
|
||||
|
||||
header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
|
||||
@@ -954,9 +954,8 @@ dump_regular_finish (int fd, struct tar_stat_info *st,
|
||||
{
|
||||
stat_diag (st->orig_file_name);
|
||||
}
|
||||
else if (final_stat.st_ctime != original_ctime.tv_sec
|
||||
|| (get_stat_ctime (&final_stat).tv_nsec
|
||||
!= original_ctime.tv_nsec))
|
||||
else if (timespec_cmp (get_stat_ctime (&final_stat), original_ctime)
|
||||
!= 0)
|
||||
{
|
||||
WARN ((0, 0, _("%s: file changed as we read it"),
|
||||
quotearg_colon (st->orig_file_name)));
|
||||
@@ -1408,9 +1407,9 @@ dump_file0 (struct tar_stat_info *st, char *p,
|
||||
return;
|
||||
}
|
||||
st->archive_file_size = st->stat.st_size;
|
||||
original_ctime = get_stat_ctime (&st->stat);
|
||||
restore_times[0] = get_stat_atime (&st->stat);
|
||||
restore_times[1] = get_stat_mtime (&st->stat);
|
||||
st->atime = restore_times[0] = get_stat_atime (&st->stat);
|
||||
st->mtime = restore_times[1] = get_stat_mtime (&st->stat);
|
||||
st->ctime = original_ctime = get_stat_ctime (&st->stat);
|
||||
|
||||
#ifdef S_ISHIDDEN
|
||||
if (S_ISHIDDEN (st->stat.st_mode))
|
||||
@@ -1433,8 +1432,8 @@ dump_file0 (struct tar_stat_info *st, char *p,
|
||||
|
||||
if (!(incremental_option && !is_individual_file (p))
|
||||
&& !S_ISDIR (st->stat.st_mode)
|
||||
&& OLDER_STAT_TIME (st->stat, m)
|
||||
&& (!after_date_option || OLDER_STAT_TIME (st->stat, c)))
|
||||
&& OLDER_TAR_STAT_TIME (*st, m)
|
||||
&& (!after_date_option || OLDER_TAR_STAT_TIME (*st, c)))
|
||||
{
|
||||
if (!incremental_option && verbose_option)
|
||||
WARN ((0, 0, _("%s: file is unchanged; not dumped"),
|
||||
|
||||
121
src/extract.c
121
src/extract.c
@@ -57,7 +57,13 @@ enum permstatus
|
||||
struct delayed_set_stat
|
||||
{
|
||||
struct delayed_set_stat *next;
|
||||
struct stat stat_info;
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
mode_t mode;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
struct timespec atime;
|
||||
struct timespec mtime;
|
||||
size_t file_name_len;
|
||||
mode_t invert_permissions;
|
||||
enum permstatus permstatus;
|
||||
@@ -76,7 +82,7 @@ struct delayed_link
|
||||
/* The device, inode number and last-modified time of the placeholder. */
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
time_t mtime;
|
||||
struct timespec mtime;
|
||||
|
||||
/* True if the link is symbolic. */
|
||||
bool is_symlink;
|
||||
@@ -206,23 +212,23 @@ check_time (char const *file_name, struct timespec t)
|
||||
gettime (&now);
|
||||
if (timespec_cmp (now, t) < 0)
|
||||
{
|
||||
unsigned long int ds = t.tv_sec - now.tv_sec;
|
||||
int dns = t.tv_nsec - now.tv_nsec;
|
||||
char dnsbuf[sizeof ".FFFFFFFFF"];
|
||||
if (dns < 0)
|
||||
char buf[TIMESPEC_STRSIZE_BOUND];
|
||||
struct timespec diff;
|
||||
diff.tv_sec = t.tv_sec - now.tv_sec;
|
||||
diff.tv_nsec = t.tv_nsec - now.tv_nsec;
|
||||
if (diff.tv_nsec < 0)
|
||||
{
|
||||
dns += 1000000000;
|
||||
ds--;
|
||||
diff.tv_nsec += BILLION;
|
||||
diff.tv_sec--;
|
||||
}
|
||||
code_ns_fraction (dns, dnsbuf);
|
||||
WARN ((0, 0, _("%s: time stamp %s is %lu%s s in the future"),
|
||||
file_name, tartime (t, true), ds, dnsbuf));
|
||||
WARN ((0, 0, _("%s: time stamp %s is %s s in the future"),
|
||||
file_name, tartime (t, true), code_timespec (diff, buf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore stat attributes (owner, group, mode and times) for
|
||||
FILE_NAME, using information given in *STAT_INFO.
|
||||
FILE_NAME, using information given in *ST.
|
||||
If CUR_INFO is nonzero, *CUR_INFO is the
|
||||
file's currernt status.
|
||||
If not restoring permissions, invert the
|
||||
@@ -237,7 +243,7 @@ check_time (char const *file_name, struct timespec t)
|
||||
|
||||
static void
|
||||
set_stat (char const *file_name,
|
||||
struct stat const *stat_info,
|
||||
struct tar_stat_info const *st,
|
||||
struct stat const *cur_info,
|
||||
mode_t invert_permissions, enum permstatus permstatus,
|
||||
char typeflag)
|
||||
@@ -256,8 +262,8 @@ set_stat (char const *file_name,
|
||||
/* FIXME: incremental_option should set ctime too, but how? */
|
||||
|
||||
struct timespec ts[2];
|
||||
ts[0] = incremental_option ? get_stat_atime (stat_info) : start_time;
|
||||
ts[1] = get_stat_mtime (stat_info);
|
||||
ts[0] = incremental_option ? st->atime : start_time;
|
||||
ts[1] = st->mtime;
|
||||
|
||||
if (utimens (file_name, ts) != 0)
|
||||
utime_error (file_name);
|
||||
@@ -272,7 +278,7 @@ set_stat (char const *file_name,
|
||||
done, it is not possible anymore to change file permissions, so we
|
||||
have to set permissions prior to possibly giving files away. */
|
||||
|
||||
set_mode (file_name, stat_info, cur_info,
|
||||
set_mode (file_name, &st->stat, cur_info,
|
||||
invert_permissions, permstatus, typeflag);
|
||||
}
|
||||
|
||||
@@ -286,48 +292,54 @@ set_stat (char const *file_name,
|
||||
if (typeflag == SYMTYPE)
|
||||
{
|
||||
#if HAVE_LCHOWN
|
||||
if (lchown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
|
||||
if (lchown (file_name, st->stat.st_uid, st->stat.st_gid) < 0)
|
||||
chown_error_details (file_name,
|
||||
stat_info->st_uid, stat_info->st_gid);
|
||||
st->stat.st_uid, st->stat.st_gid);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
|
||||
if (chown (file_name, st->stat.st_uid, st->stat.st_gid) < 0)
|
||||
chown_error_details (file_name,
|
||||
stat_info->st_uid, stat_info->st_gid);
|
||||
st->stat.st_uid, st->stat.st_gid);
|
||||
|
||||
/* On a few systems, and in particular, those allowing to give files
|
||||
away, changing the owner or group destroys the suid or sgid bits.
|
||||
So let's attempt setting these bits once more. */
|
||||
if (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX))
|
||||
set_mode (file_name, stat_info, 0,
|
||||
if (st->stat.st_mode & (S_ISUID | S_ISGID | S_ISVTX))
|
||||
set_mode (file_name, &st->stat, 0,
|
||||
invert_permissions, permstatus, typeflag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember to restore stat attributes (owner, group, mode and times)
|
||||
for the directory FILE_NAME, using information given in *STAT_INFO,
|
||||
for the directory FILE_NAME, using information given in *ST,
|
||||
once we stop extracting files into that directory.
|
||||
If not restoring permissions, remember to invert the
|
||||
INVERT_PERMISSIONS bits from the file's current permissions.
|
||||
PERMSTATUS specifies the status of the file's permissions. */
|
||||
static void
|
||||
delay_set_stat (char const *file_name, struct stat const *stat_info,
|
||||
delay_set_stat (char const *file_name, struct tar_stat_info const *st,
|
||||
mode_t invert_permissions, enum permstatus permstatus)
|
||||
{
|
||||
size_t file_name_len = strlen (file_name);
|
||||
struct delayed_set_stat *data =
|
||||
xmalloc (offsetof (struct delayed_set_stat, file_name)
|
||||
+ file_name_len + 1);
|
||||
data->next = delayed_set_stat_head;
|
||||
data->dev = st->stat.st_dev;
|
||||
data->ino = st->stat.st_ino;
|
||||
data->mode = st->stat.st_mode;
|
||||
data->uid = st->stat.st_uid;
|
||||
data->gid = st->stat.st_gid;
|
||||
data->atime = st->atime;
|
||||
data->mtime = st->mtime;
|
||||
data->file_name_len = file_name_len;
|
||||
strcpy (data->file_name, file_name);
|
||||
data->invert_permissions = invert_permissions;
|
||||
data->permstatus = permstatus;
|
||||
data->after_links = 0;
|
||||
data->stat_info = *stat_info;
|
||||
data->next = delayed_set_stat_head;
|
||||
strcpy (data->file_name, file_name);
|
||||
delayed_set_stat_head = data;
|
||||
}
|
||||
|
||||
@@ -352,7 +364,13 @@ repair_delayed_set_stat (char const *dir,
|
||||
if (st.st_dev == dir_stat_info->st_dev
|
||||
&& st.st_ino == dir_stat_info->st_ino)
|
||||
{
|
||||
data->stat_info = current_stat_info.stat;
|
||||
data->dev = current_stat_info.stat.st_dev;
|
||||
data->ino = current_stat_info.stat.st_ino;
|
||||
data->mode = current_stat_info.stat.st_mode;
|
||||
data->uid = current_stat_info.stat.st_uid;
|
||||
data->gid = current_stat_info.stat.st_gid;
|
||||
data->atime = current_stat_info.atime;
|
||||
data->mtime = current_stat_info.mtime;
|
||||
data->invert_permissions =
|
||||
(MODE_RWX & (current_stat_info.stat.st_mode ^ st.st_mode));
|
||||
data->permstatus = ARCHIVED_PERMSTATUS;
|
||||
@@ -408,7 +426,7 @@ make_directories (char *file_name)
|
||||
invert_permissions is zero, because
|
||||
repair_delayed_set_stat may need to update the struct. */
|
||||
delay_set_stat (file_name,
|
||||
¤t_stat_info.stat /* ignored */,
|
||||
¤t_stat_info /* ignored */,
|
||||
invert_permissions, INTERDIR_PERMSTATUS);
|
||||
|
||||
print_for_mkdir (file_name, cursor - file_name, mode);
|
||||
@@ -448,7 +466,7 @@ file_newer_p (const char *file_name, struct tar_stat_info *tar_stat)
|
||||
return errno != ENOENT;
|
||||
}
|
||||
if (!S_ISDIR (st.st_mode)
|
||||
&& st.st_mtime >= tar_stat->stat.st_mtime)
|
||||
&& timespec_cmp (tar_stat->mtime, get_stat_mtime (&st)) <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -551,8 +569,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
|
||||
stat_error (data->file_name);
|
||||
skip_this_one = 1;
|
||||
}
|
||||
else if (! (st.st_dev == data->stat_info.st_dev
|
||||
&& (st.st_ino == data->stat_info.st_ino)))
|
||||
else if (! (st.st_dev == data->dev && st.st_ino == data->ino))
|
||||
{
|
||||
ERROR ((0, 0,
|
||||
_("%s: Directory renamed before its status could be extracted"),
|
||||
@@ -562,8 +579,16 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
|
||||
}
|
||||
|
||||
if (! skip_this_one)
|
||||
set_stat (data->file_name, &data->stat_info, cur_info,
|
||||
data->invert_permissions, data->permstatus, DIRTYPE);
|
||||
{
|
||||
struct tar_stat_info st;
|
||||
st.stat.st_mode = data->mode;
|
||||
st.stat.st_uid = data->uid;
|
||||
st.stat.st_gid = data->gid;
|
||||
st.atime = data->atime;
|
||||
st.mtime = data->mtime;
|
||||
set_stat (data->file_name, &st, cur_info,
|
||||
data->invert_permissions, data->permstatus, DIRTYPE);
|
||||
}
|
||||
|
||||
delayed_set_stat_head = data->next;
|
||||
free (data);
|
||||
@@ -627,7 +652,7 @@ extract_dir (char *file_name, int typeflag)
|
||||
if (status == 0
|
||||
|| old_files_option == DEFAULT_OLD_FILES
|
||||
|| old_files_option == OVERWRITE_OLD_FILES)
|
||||
delay_set_stat (file_name, ¤t_stat_info.stat,
|
||||
delay_set_stat (file_name, ¤t_stat_info,
|
||||
MODE_RWX & (mode ^ current_stat_info.stat.st_mode),
|
||||
(status == 0
|
||||
? ARCHIVED_PERMSTATUS
|
||||
@@ -771,7 +796,7 @@ extract_file (char *file_name, int typeflag)
|
||||
if (to_command_option)
|
||||
sys_wait_command ();
|
||||
else
|
||||
set_stat (file_name, ¤t_stat_info.stat, 0, 0,
|
||||
set_stat (file_name, ¤t_stat_info, NULL, 0,
|
||||
(old_files_option == OVERWRITE_OLD_FILES ?
|
||||
UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS),
|
||||
typeflag);
|
||||
@@ -815,7 +840,7 @@ create_placeholder_file (char *file_name, bool is_symlink, int *interdir_made)
|
||||
delayed_link_head = p;
|
||||
p->dev = st.st_dev;
|
||||
p->ino = st.st_ino;
|
||||
p->mtime = st.st_mtime;
|
||||
p->mtime = get_stat_mtime (&st);
|
||||
p->is_symlink = is_symlink;
|
||||
if (is_symlink)
|
||||
{
|
||||
@@ -842,8 +867,8 @@ create_placeholder_file (char *file_name, bool is_symlink, int *interdir_made)
|
||||
stat_error (h->file_name);
|
||||
else
|
||||
{
|
||||
h->stat_info.st_dev = st.st_dev;
|
||||
h->stat_info.st_ino = st.st_ino;
|
||||
h->dev = st.st_dev;
|
||||
h->ino = st.st_ino;
|
||||
}
|
||||
}
|
||||
while ((h = h->next) && ! h->after_links);
|
||||
@@ -879,7 +904,7 @@ extract_link (char *file_name, int typeflag)
|
||||
for (; ds; ds = ds->next)
|
||||
if (ds->dev == st1.st_dev
|
||||
&& ds->ino == st1.st_ino
|
||||
&& ds->mtime == st1.st_mtime)
|
||||
&& timespec_cmp (ds->mtime, get_stat_mtime (&st1)) == 0)
|
||||
{
|
||||
struct string_list *p = xmalloc (offsetof (struct string_list, string)
|
||||
+ strlen (file_name) + 1);
|
||||
@@ -926,7 +951,7 @@ extract_symlink (char *file_name, int typeflag)
|
||||
break;
|
||||
|
||||
if (status == 0)
|
||||
set_stat (file_name, ¤t_stat_info.stat, 0, 0, 0, SYMTYPE);
|
||||
set_stat (file_name, ¤t_stat_info, NULL, 0, 0, SYMTYPE);
|
||||
else
|
||||
symlink_error (current_stat_info.link_name, file_name);
|
||||
return status;
|
||||
@@ -958,7 +983,8 @@ extract_node (char *file_name, int typeflag)
|
||||
if (status != 0)
|
||||
mknod_error (file_name);
|
||||
else
|
||||
set_stat (file_name, ¤t_stat_info.stat, 0, 0, ARCHIVED_PERMSTATUS, typeflag);
|
||||
set_stat (file_name, ¤t_stat_info, NULL, 0,
|
||||
ARCHIVED_PERMSTATUS, typeflag);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
@@ -975,7 +1001,7 @@ extract_fifo (char *file_name, int typeflag)
|
||||
break;
|
||||
|
||||
if (status == 0)
|
||||
set_stat (file_name, ¤t_stat_info.stat, NULL, 0,
|
||||
set_stat (file_name, ¤t_stat_info, NULL, 0,
|
||||
ARCHIVED_PERMSTATUS, typeflag);
|
||||
else
|
||||
mkfifo_error (file_name);
|
||||
@@ -1217,7 +1243,7 @@ apply_delayed_links (void)
|
||||
if (lstat (source, &st) == 0
|
||||
&& st.st_dev == ds->dev
|
||||
&& st.st_ino == ds->ino
|
||||
&& st.st_mtime == ds->mtime)
|
||||
&& timespec_cmp (get_stat_mtime (&st), ds->mtime) == 0)
|
||||
{
|
||||
/* Unlink the placeholder, then create a hard link if possible,
|
||||
a symbolic link otherwise. */
|
||||
@@ -1234,10 +1260,11 @@ apply_delayed_links (void)
|
||||
symlink_error (ds->target, source);
|
||||
else
|
||||
{
|
||||
struct tar_stat_info st1;
|
||||
st1.stat.st_uid = ds->uid;
|
||||
st1.stat.st_gid = ds->gid;
|
||||
set_stat (source, &st1, NULL, 0, 0, SYMTYPE);
|
||||
valid_source = source;
|
||||
st.st_uid = ds->uid;
|
||||
st.st_gid = ds->gid;
|
||||
set_stat (source, &st, 0, 0, 0, SYMTYPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
src/list.c
33
src/list.c
@@ -99,8 +99,8 @@ read_and (void (*do_something) (void))
|
||||
/* FIXME: Grab fractional time stamps from
|
||||
extended header. */
|
||||
mtime.tv_nsec = 0,
|
||||
set_stat_mtime (¤t_stat_info.stat, mtime),
|
||||
OLDER_STAT_TIME (current_stat_info.stat, m)))
|
||||
current_stat_info.mtime = mtime,
|
||||
OLDER_TAR_STAT_TIME (current_stat_info, m)))
|
||||
|| excluded_name (current_stat_info.file_name))
|
||||
{
|
||||
switch (current_header->header.typeflag)
|
||||
@@ -243,7 +243,7 @@ list_archive (void)
|
||||
}
|
||||
if (multi_volume_option)
|
||||
assign_string (&save_name, 0);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -512,9 +512,6 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
enum archive_format *format_pointer, int do_user_group)
|
||||
{
|
||||
enum archive_format format;
|
||||
struct timespec atime;
|
||||
struct timespec ctime;
|
||||
struct timespec mtime;
|
||||
|
||||
if (strcmp (header->header.magic, TMAGIC) == 0)
|
||||
{
|
||||
@@ -536,9 +533,8 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
*format_pointer = format;
|
||||
|
||||
stat_info->stat.st_mode = MODE_FROM_HEADER (header->header.mode);
|
||||
mtime.tv_sec = TIME_FROM_HEADER (header->header.mtime);
|
||||
mtime.tv_nsec = 0;
|
||||
set_stat_mtime (&stat_info->stat, mtime);
|
||||
stat_info->mtime.tv_sec = TIME_FROM_HEADER (header->header.mtime);
|
||||
stat_info->mtime.tv_nsec = 0;
|
||||
assign_string (&stat_info->uname,
|
||||
header->header.uname[0] ? header->header.uname : NULL);
|
||||
assign_string (&stat_info->gname,
|
||||
@@ -546,21 +542,18 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
|
||||
|
||||
if (format == OLDGNU_FORMAT && incremental_option)
|
||||
{
|
||||
atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
|
||||
ctime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.ctime);
|
||||
atime.tv_nsec = ctime.tv_nsec = 0;
|
||||
stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
|
||||
stat_info->ctime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.ctime);
|
||||
stat_info->atime.tv_nsec = stat_info->ctime.tv_nsec = 0;
|
||||
}
|
||||
else if (format == STAR_FORMAT)
|
||||
{
|
||||
atime.tv_sec = TIME_FROM_HEADER (header->star_header.atime);
|
||||
ctime.tv_sec = TIME_FROM_HEADER (header->star_header.ctime);
|
||||
atime.tv_nsec = ctime.tv_nsec = 0;
|
||||
stat_info->atime.tv_sec = TIME_FROM_HEADER (header->star_header.atime);
|
||||
stat_info->ctime.tv_sec = TIME_FROM_HEADER (header->star_header.ctime);
|
||||
stat_info->atime.tv_nsec = stat_info->ctime.tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
atime = ctime = start_time;
|
||||
|
||||
set_stat_atime (&stat_info->stat, atime);
|
||||
set_stat_ctime (&stat_info->stat, ctime);
|
||||
stat_info->atime = stat_info->ctime = start_time;
|
||||
|
||||
if (format == V7_FORMAT)
|
||||
{
|
||||
@@ -1094,7 +1087,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
|
||||
|
||||
/* Time stamp. */
|
||||
|
||||
time_stamp = tartime (get_stat_mtime (&st->stat), false);
|
||||
time_stamp = tartime (st->mtime, false);
|
||||
time_stamp_len = strlen (time_stamp);
|
||||
if (datewidth < time_stamp_len)
|
||||
datewidth = time_stamp_len;
|
||||
|
||||
21
src/misc.c
21
src/misc.c
@@ -239,6 +239,27 @@ code_ns_fraction (int ns, char *p)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char const *
|
||||
code_timespec (struct timespec t, char sbuf[TIMESPEC_STRSIZE_BOUND])
|
||||
{
|
||||
time_t s = t.tv_sec;
|
||||
int ns = t.tv_nsec;
|
||||
char *np;
|
||||
bool negative = s < 0;
|
||||
|
||||
if (negative && ns != 0)
|
||||
{
|
||||
s++;
|
||||
ns = BILLION - ns;
|
||||
}
|
||||
|
||||
np = umaxtostr (negative ? - (uintmax_t) s : (uintmax_t) s, sbuf + 1);
|
||||
if (negative)
|
||||
*--np = '-';
|
||||
code_ns_fraction (ns, sbuf + UINTMAX_STRSIZE_BOUND);
|
||||
return np;
|
||||
}
|
||||
|
||||
/* File handling. */
|
||||
|
||||
|
||||
28
src/system.c
28
src/system.c
@@ -611,7 +611,16 @@ dec_to_env (char *envar, uintmax_t num)
|
||||
char *numstr;
|
||||
|
||||
numstr = STRINGIFY_BIGINT (num, buf);
|
||||
setenv (envar, numstr, 1);
|
||||
if (setenv (envar, numstr, 1) != 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
static void
|
||||
time_to_env (char *envar, struct timespec t)
|
||||
{
|
||||
char buf[TIMESPEC_STRSIZE_BOUND];
|
||||
if (setenv (envar, code_timespec (t, buf), 1) != 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -620,14 +629,18 @@ oct_to_env (char *envar, unsigned long num)
|
||||
char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
|
||||
|
||||
snprintf (buf, sizeof buf, "0%lo", num);
|
||||
setenv (envar, buf, 1);
|
||||
if (setenv (envar, buf, 1) != 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
static void
|
||||
str_to_env (char *envar, char const *str)
|
||||
{
|
||||
if (str)
|
||||
setenv (envar, str, 1);
|
||||
{
|
||||
if (setenv (envar, str, 1) != 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
else
|
||||
unsetenv (envar);
|
||||
}
|
||||
@@ -638,7 +651,8 @@ chr_to_env (char *envar, char c)
|
||||
char buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
setenv (envar, buf, 1);
|
||||
if (setenv (envar, buf, 1) != 0)
|
||||
xalloc_die ();
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -650,9 +664,9 @@ stat_to_env (char *name, char type, struct tar_stat_info *st)
|
||||
str_to_env ("TAR_REALNAME", st->file_name);
|
||||
str_to_env ("TAR_UNAME", st->uname);
|
||||
str_to_env ("TAR_GNAME", st->gname);
|
||||
dec_to_env ("TAR_MTIME", st->stat.st_mtime);
|
||||
dec_to_env ("TAR_ATIME", st->stat.st_atime);
|
||||
dec_to_env ("TAR_CTIME", st->stat.st_ctime);
|
||||
time_to_env ("TAR_ATIME", st->atime);
|
||||
time_to_env ("TAR_MTIME", st->mtime);
|
||||
time_to_env ("TAR_CTIME", st->ctime);
|
||||
dec_to_env ("TAR_SIZE", st->stat.st_size);
|
||||
dec_to_env ("TAR_UID", st->stat.st_uid);
|
||||
dec_to_env ("TAR_GID", st->stat.st_gid);
|
||||
|
||||
@@ -281,6 +281,12 @@ struct tar_stat_info
|
||||
char *gname; /* group name of owner */
|
||||
struct stat stat; /* regular filesystem stat */
|
||||
|
||||
/* STAT doesn't always have access, data modification, and status
|
||||
change times in a convenient form, so store them separately. */
|
||||
struct timespec atime;
|
||||
struct timespec mtime;
|
||||
struct timespec ctime;
|
||||
|
||||
off_t archive_file_size; /* Size of file as stored in the archive.
|
||||
Equals stat.st_size for non-sparse files */
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ update_archive (void)
|
||||
decode_header (current_header, ¤t_stat_info,
|
||||
¤t_format, 0);
|
||||
archive_format = current_format;
|
||||
|
||||
|
||||
if (subcommand_option == UPDATE_SUBCOMMAND
|
||||
&& (name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
@@ -138,7 +138,9 @@ update_archive (void)
|
||||
chdir_do (name->change_dir);
|
||||
if (deref_stat (dereference_option,
|
||||
current_stat_info.file_name, &s) == 0
|
||||
&& s.st_mtime <= current_stat_info.stat.st_mtime)
|
||||
&& (timespec_cmp (get_stat_mtime (&s),
|
||||
current_stat_info.mtime)
|
||||
<= 0))
|
||||
add_avoided_name (current_stat_info.file_name);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,8 +57,6 @@ static size_t global_header_count;
|
||||
|
||||
However it should wait until buffer.c is finally rewritten */
|
||||
|
||||
enum { BILLION = 1000000000, LOG10_BILLION = 9 };
|
||||
|
||||
|
||||
/* Keyword options */
|
||||
|
||||
@@ -747,23 +745,8 @@ decode_string (char **string, char const *arg)
|
||||
static void
|
||||
code_time (struct timespec t, char const *keyword, struct xheader *xhdr)
|
||||
{
|
||||
time_t s = t.tv_sec;
|
||||
int ns = t.tv_nsec;
|
||||
char sbuf[1/*"-"*/ + UINTMAX_STRSIZE_BOUND + 1/*"."*/ + LOG10_BILLION];
|
||||
char *np;
|
||||
bool negative = s < 0;
|
||||
|
||||
if (negative && ns != 0)
|
||||
{
|
||||
s++;
|
||||
ns = BILLION - ns;
|
||||
}
|
||||
|
||||
np = umaxtostr (negative ? - (uintmax_t) s : (uintmax_t) s, sbuf + 1);
|
||||
if (negative)
|
||||
*--np = '-';
|
||||
code_ns_fraction (ns, sbuf + UINTMAX_STRSIZE_BOUND);
|
||||
xheader_print (xhdr, keyword, np);
|
||||
char buf[TIMESPEC_STRSIZE_BOUND];
|
||||
xheader_print (xhdr, keyword, code_timespec (t, buf));
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -900,7 +883,7 @@ static void
|
||||
atime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_time (get_stat_atime (&st->stat), keyword, xhdr);
|
||||
code_time (st->atime, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -908,7 +891,7 @@ atime_decoder (struct tar_stat_info *st, char const *arg)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, "atime"))
|
||||
set_stat_atime (&st->stat, ts);
|
||||
st->atime = ts;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -956,7 +939,7 @@ static void
|
||||
ctime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_time (get_stat_ctime (&st->stat), keyword, xhdr);
|
||||
code_time (st->ctime, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -964,14 +947,14 @@ ctime_decoder (struct tar_stat_info *st, char const *arg)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, "ctime"))
|
||||
set_stat_ctime (&st->stat, ts);
|
||||
st->ctime = ts;
|
||||
}
|
||||
|
||||
static void
|
||||
mtime_coder (struct tar_stat_info const *st, char const *keyword,
|
||||
struct xheader *xhdr, void *data __attribute__ ((unused)))
|
||||
{
|
||||
code_time (get_stat_mtime (&st->stat), keyword, xhdr);
|
||||
code_time (st->mtime, keyword, xhdr);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -979,7 +962,7 @@ mtime_decoder (struct tar_stat_info *st, char const *arg)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (decode_time (&ts, arg, "mtime"))
|
||||
set_stat_mtime (&st->stat, ts);
|
||||
st->mtime = ts;
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
Reference in New Issue
Block a user