More portability improvements, thanks to Juergen Lock.
High-resolution mtime/ctime/atime is not POSIX-standard, so hide set/get of high-resolution time fields behind easily-mutable macros. That makes it easier to change how those fields are accessed.
This commit is contained in:
parent
1edf76f18b
commit
82ac6716b7
@ -369,11 +369,10 @@ archive_entry_mtime(struct archive_entry *entry)
|
||||
return (entry->ae_stat.st_mtime);
|
||||
}
|
||||
|
||||
|
||||
long
|
||||
archive_entry_mtime_nsec(struct archive_entry *entry)
|
||||
{
|
||||
return (entry->ae_stat.st_mtimespec.tv_nsec);
|
||||
return (ARCHIVE_STAT_MTIME_NANOS(&entry->ae_stat));
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -29,7 +29,9 @@
|
||||
/*
|
||||
* This header is the first thing included in any of the libarchive
|
||||
* source files. As far as possible, platform-specific issues should
|
||||
* be dealt with here and not within individual source files.
|
||||
* be dealt with here and not within individual source files. I'm
|
||||
* actively trying to minimize #if blocks within the main source,
|
||||
* since they obfuscate the code.
|
||||
*/
|
||||
|
||||
#ifndef ARCHIVE_PLATFORM_H_INCLUDED
|
||||
@ -57,10 +59,19 @@
|
||||
#define ARCHIVE_ERRNO_PROGRAMMER EINVAL
|
||||
#define ARCHIVE_ERRNO_MISC (-1)
|
||||
|
||||
/* Fetch/set high-resolution time data through a struct stat pointer. */
|
||||
#define ARCHIVE_STAT_ATIME_NANOS(st) (st)->st_atimespec.tv_nsec
|
||||
#define ARCHIVE_STAT_CTIME_NANOS(st) (st)->st_ctimespec.tv_nsec
|
||||
#define ARCHIVE_STAT_MTIME_NANOS(st) (st)->st_mtimespec.tv_nsec
|
||||
#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n) (st)->st_atimespec.tv_nsec = (n)
|
||||
#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n) (st)->st_ctimespec.tv_nsec = (n)
|
||||
#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n) (st)->st_mtimespec.tv_nsec = (n)
|
||||
|
||||
/*
|
||||
* Older versions of inttypes.h don't have INT64_MAX, etc. Since
|
||||
* SUSv3 requires them to be macros when they are defined, we can
|
||||
* easily test for and define them here if necessary.
|
||||
* easily test for and define them here if necessary. Someday, we
|
||||
* won't have to worry about non-C99-compliant systems.
|
||||
*/
|
||||
#ifndef INT64_MAX
|
||||
/* XXX Is this really necessary? XXX */
|
||||
@ -82,16 +93,32 @@
|
||||
|
||||
/* Linux */
|
||||
#ifdef LINUX
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#define _FILE_OFFSET_BITS 64 /* Needed for 64-bit file size handling. */
|
||||
#include <inttypes.h>
|
||||
#define ARCHIVE_ERRNO_FILE_FORMAT EILSEQ
|
||||
#define ARCHIVE_ERRNO_PROGRAMMER EINVAL
|
||||
#define ARCHIVE_ERRNO_MISC (-1)
|
||||
#define st_atimespec st_atim
|
||||
#define st_mtimespec st_mtim
|
||||
#define st_ctimespec st_ctim
|
||||
#define HAVE_STRERROR_R 1
|
||||
#define STRERROR_R_CHAR_P 1
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_TIMESPEC
|
||||
/* Fetch the nanosecond portion of the timestamp from a struct stat pointer. */
|
||||
#define ARCHIVE_STAT_ATIME_NANOS(pstat) (pstat)->st_atim.tv_nsec
|
||||
#define ARCHIVE_STAT_CTIME_NANOS(pstat) (pstat)->st_ctim.tv_nsec
|
||||
#define ARCHIVE_STAT_MTIME_NANOS(pstat) (pstat)->st_mtim.tv_nsec
|
||||
#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n) (st)->st_atim.tv_nsec = (n)
|
||||
#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n) (st)->st_ctim.tv_nsec = (n)
|
||||
#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n) (st)->st_mtim.tv_nsec = (n)
|
||||
#else
|
||||
/* High-res timestamps aren't available, so just use stubs here. */
|
||||
#define ARCHIVE_STAT_ATIME_NANOS(pstat) 0
|
||||
#define ARCHIVE_STAT_CTIME_NANOS(pstat) 0
|
||||
#define ARCHIVE_STAT_MTIME_NANOS(pstat) 0
|
||||
#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n)
|
||||
#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n)
|
||||
#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -116,37 +116,35 @@ archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
|
||||
{
|
||||
mode_t writable_mode;
|
||||
struct archive_extract_dir_entry *le;
|
||||
const struct stat *st;
|
||||
int ret;
|
||||
int restore_pwd;
|
||||
|
||||
restore_pwd = -1;
|
||||
if (S_ISDIR(archive_entry_stat(entry)->st_mode)) {
|
||||
st = archive_entry_stat(entry);
|
||||
if (S_ISDIR(st->st_mode)) {
|
||||
/*
|
||||
* TODO: Does this really work under all conditions?
|
||||
*
|
||||
* E.g., root restores a dir owned by someone else?
|
||||
*/
|
||||
writable_mode = archive_entry_stat(entry)->st_mode | 0700;
|
||||
writable_mode = st->st_mode | 0700;
|
||||
|
||||
/*
|
||||
* In order to correctly restore non-writable dirs or
|
||||
* dir timestamps, we need to maintain a fix-up list.
|
||||
*/
|
||||
if (archive_entry_stat(entry)->st_mode != writable_mode ||
|
||||
if (st->st_mode != writable_mode ||
|
||||
flags & ARCHIVE_EXTRACT_TIME) {
|
||||
le = malloc(sizeof(struct archive_extract_dir_entry));
|
||||
le->next = a->archive_extract_dir_list;
|
||||
a->archive_extract_dir_list = le;
|
||||
le->mode = archive_entry_stat(entry)->st_mode;
|
||||
le->mtime = archive_entry_stat(entry)->st_mtime;
|
||||
le->mtime_nanos =
|
||||
archive_entry_stat(entry)->st_mtimespec.tv_nsec;
|
||||
le->atime = archive_entry_stat(entry)->st_atime;
|
||||
le->atime_nanos =
|
||||
archive_entry_stat(entry)->st_atimespec.tv_nsec;
|
||||
le->name =
|
||||
malloc(strlen(archive_entry_pathname(entry)) + 1);
|
||||
strcpy(le->name, archive_entry_pathname(entry));
|
||||
le->mode = st->st_mode;
|
||||
le->mtime = st->st_mtime;
|
||||
le->mtime_nanos = ARCHIVE_STAT_MTIME_NANOS(st);
|
||||
le->atime = st->st_atime;
|
||||
le->atime_nanos = ARCHIVE_STAT_ATIME_NANOS(st);
|
||||
le->name = strdup(archive_entry_pathname(entry));
|
||||
a->cleanup_archive_extract = archive_extract_cleanup;
|
||||
/* Make sure I can write to this directory. */
|
||||
archive_entry_set_mode(entry, writable_mode);
|
||||
@ -167,7 +165,7 @@ archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
|
||||
/* XXX Update pathname in 'entry' XXX */
|
||||
}
|
||||
|
||||
switch (archive_entry_stat(entry)->st_mode & S_IFMT) {
|
||||
switch (st->st_mode & S_IFMT) {
|
||||
default:
|
||||
/* Fall through, as required by POSIX. */
|
||||
case S_IFREG:
|
||||
@ -720,10 +718,10 @@ set_time(struct archive *a, struct archive_entry *entry, int flags)
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
times[1].tv_sec = st->st_mtime;
|
||||
times[1].tv_usec = st->st_mtimespec.tv_nsec / 1000;
|
||||
times[1].tv_usec = ARCHIVE_STAT_MTIME_NANOS(st) / 1000;
|
||||
|
||||
times[0].tv_sec = st->st_atime;
|
||||
times[0].tv_usec = st->st_atimespec.tv_nsec / 1000;
|
||||
times[0].tv_usec = ARCHIVE_STAT_ATIME_NANOS(st) / 1000;
|
||||
|
||||
#ifdef HAVE_LUTIMES
|
||||
if (lutimes(archive_entry_pathname(entry), times) != 0) {
|
||||
|
@ -109,7 +109,7 @@ static int pax_attribute(struct archive_entry *, struct stat *,
|
||||
wchar_t *key, wchar_t *value);
|
||||
static int pax_header(struct archive *, struct tar *,
|
||||
struct archive_entry *, struct stat *, char *attr);
|
||||
static void pax_time(const wchar_t *, struct timespec *t);
|
||||
static void pax_time(const wchar_t *, int64_t *sec, long *nanos);
|
||||
static int read_body_to_string(struct archive *, struct archive_string *,
|
||||
const void *h);
|
||||
static int64_t tar_atol(const char *, unsigned);
|
||||
@ -884,6 +884,9 @@ static int
|
||||
pax_attribute(struct archive_entry *entry, struct stat *st,
|
||||
wchar_t *key, wchar_t *value)
|
||||
{
|
||||
int64_t s;
|
||||
long n;
|
||||
|
||||
switch (key[0]) {
|
||||
case 'L':
|
||||
/* Our extensions */
|
||||
@ -913,13 +916,18 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
|
||||
st->st_nlink = tar_atol10(value, wcslen(value));
|
||||
break;
|
||||
case 'a':
|
||||
if (wcscmp(key, L"atime")==0)
|
||||
pax_time(value, &(st->st_atimespec));
|
||||
if (wcscmp(key, L"atime")==0) {
|
||||
pax_time(value, &s, &n);
|
||||
st->st_atime = s;
|
||||
ARCHIVE_STAT_SET_ATIME_NANOS(st, n);
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (wcscmp(key, L"ctime")==0)
|
||||
pax_time(value, &(st->st_ctimespec));
|
||||
else if (wcscmp(key, L"charset")==0) {
|
||||
if (wcscmp(key, L"ctime")==0) {
|
||||
pax_time(value, &s, &n);
|
||||
st->st_ctime = s;
|
||||
ARCHIVE_STAT_SET_CTIME_NANOS(st, n);
|
||||
} else if (wcscmp(key, L"charset")==0) {
|
||||
/* TODO: Publish charset information in entry. */
|
||||
} else if (wcscmp(key, L"comment")==0) {
|
||||
/* TODO: Publish comment in entry. */
|
||||
@ -941,8 +949,11 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (wcscmp(key, L"mtime")==0)
|
||||
pax_time(value, &(st->st_mtimespec));
|
||||
if (wcscmp(key, L"mtime")==0) {
|
||||
pax_time(value, &s, &n);
|
||||
st->st_mtime = s;
|
||||
ARCHIVE_STAT_SET_MTIME_NANOS(st, n);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if (wcscmp(key, L"path")==0)
|
||||
@ -973,7 +984,7 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
|
||||
* parse a decimal time value, which may include a fractional portion
|
||||
*/
|
||||
static void
|
||||
pax_time(const wchar_t *p, struct timespec *t)
|
||||
pax_time(const wchar_t *p, int64_t *ps, long *pn)
|
||||
{
|
||||
char digit;
|
||||
int64_t s;
|
||||
@ -1000,10 +1011,10 @@ pax_time(const wchar_t *p, struct timespec *t)
|
||||
++p;
|
||||
}
|
||||
|
||||
t->tv_sec = s * sign;
|
||||
*ps = s * sign;
|
||||
|
||||
/* Calculate nanoseconds. */
|
||||
t->tv_nsec = 0;
|
||||
*pn = 0;
|
||||
|
||||
if (*p != '.')
|
||||
return;
|
||||
@ -1012,7 +1023,7 @@ pax_time(const wchar_t *p, struct timespec *t)
|
||||
do {
|
||||
++p;
|
||||
if (*p >= '0' && *p <= '9')
|
||||
t->tv_nsec += (*p - '0') * l;
|
||||
*pn += (*p - '0') * l;
|
||||
else
|
||||
break;
|
||||
} while (l /= 10);
|
||||
|
@ -515,19 +515,22 @@ archive_write_pax_header(struct archive *a,
|
||||
|
||||
if (st_main->st_mtime < 0 ||
|
||||
st_main->st_mtime >= 0x7fffffff ||
|
||||
st_main->st_mtimespec.tv_nsec != 0)
|
||||
ARCHIVE_STAT_MTIME_NANOS(st_main) != 0)
|
||||
add_pax_attr_time(&(pax->pax_header), "mtime",
|
||||
st_main->st_mtime, st_main->st_mtimespec.tv_nsec);
|
||||
st_main->st_mtime,
|
||||
ARCHIVE_STAT_MTIME_NANOS(st_main));
|
||||
|
||||
if (st_main->st_ctimespec.tv_nsec != 0 ||
|
||||
st_main->st_ctime != 0)
|
||||
if (st_main->st_ctime != 0 ||
|
||||
ARCHIVE_STAT_CTIME_NANOS(st_main) != 0)
|
||||
add_pax_attr_time(&(pax->pax_header), "ctime",
|
||||
st_main->st_ctime, st_main->st_ctimespec.tv_nsec);
|
||||
st_main->st_ctime,
|
||||
ARCHIVE_STAT_CTIME_NANOS(st_main));
|
||||
|
||||
if (st_main->st_atimespec.tv_nsec != 0 ||
|
||||
st_main->st_atime != 0)
|
||||
if (st_main->st_atime != 0 ||
|
||||
ARCHIVE_STAT_ATIME_NANOS(st_main) != 0)
|
||||
add_pax_attr_time(&(pax->pax_header), "atime",
|
||||
st_main->st_atime, st_main->st_atimespec.tv_nsec);
|
||||
st_main->st_atime,
|
||||
ARCHIVE_STAT_ATIME_NANOS(st_main));
|
||||
|
||||
/* I use a star-compatible file flag attribute. */
|
||||
p = archive_entry_fflags(entry_main);
|
||||
|
Loading…
Reference in New Issue
Block a user