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
f8f8803bd5
commit
0f7d2bd380
@ -369,11 +369,10 @@ archive_entry_mtime(struct archive_entry *entry)
|
|||||||
return (entry->ae_stat.st_mtime);
|
return (entry->ae_stat.st_mtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
long
|
long
|
||||||
archive_entry_mtime_nsec(struct archive_entry *entry)
|
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 *
|
const char *
|
||||||
|
@ -29,7 +29,9 @@
|
|||||||
/*
|
/*
|
||||||
* This header is the first thing included in any of the libarchive
|
* This header is the first thing included in any of the libarchive
|
||||||
* source files. As far as possible, platform-specific issues should
|
* 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
|
#ifndef ARCHIVE_PLATFORM_H_INCLUDED
|
||||||
@ -57,10 +59,19 @@
|
|||||||
#define ARCHIVE_ERRNO_PROGRAMMER EINVAL
|
#define ARCHIVE_ERRNO_PROGRAMMER EINVAL
|
||||||
#define ARCHIVE_ERRNO_MISC (-1)
|
#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
|
* Older versions of inttypes.h don't have INT64_MAX, etc. Since
|
||||||
* SUSv3 requires them to be macros when they are defined, we can
|
* 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
|
#ifndef INT64_MAX
|
||||||
/* XXX Is this really necessary? XXX */
|
/* XXX Is this really necessary? XXX */
|
||||||
@ -82,16 +93,32 @@
|
|||||||
|
|
||||||
/* Linux */
|
/* Linux */
|
||||||
#ifdef LINUX
|
#ifdef LINUX
|
||||||
#define _FILE_OFFSET_BITS 64
|
#define _FILE_OFFSET_BITS 64 /* Needed for 64-bit file size handling. */
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#define ARCHIVE_ERRNO_FILE_FORMAT EILSEQ
|
#define ARCHIVE_ERRNO_FILE_FORMAT EILSEQ
|
||||||
#define ARCHIVE_ERRNO_PROGRAMMER EINVAL
|
#define ARCHIVE_ERRNO_PROGRAMMER EINVAL
|
||||||
#define ARCHIVE_ERRNO_MISC (-1)
|
#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 HAVE_STRERROR_R 1
|
||||||
#define STRERROR_R_CHAR_P 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
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -116,37 +116,35 @@ archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
|
|||||||
{
|
{
|
||||||
mode_t writable_mode;
|
mode_t writable_mode;
|
||||||
struct archive_extract_dir_entry *le;
|
struct archive_extract_dir_entry *le;
|
||||||
|
const struct stat *st;
|
||||||
int ret;
|
int ret;
|
||||||
int restore_pwd;
|
int restore_pwd;
|
||||||
|
|
||||||
restore_pwd = -1;
|
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?
|
* TODO: Does this really work under all conditions?
|
||||||
*
|
*
|
||||||
* E.g., root restores a dir owned by someone else?
|
* 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
|
* In order to correctly restore non-writable dirs or
|
||||||
* dir timestamps, we need to maintain a fix-up list.
|
* 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) {
|
flags & ARCHIVE_EXTRACT_TIME) {
|
||||||
le = malloc(sizeof(struct archive_extract_dir_entry));
|
le = malloc(sizeof(struct archive_extract_dir_entry));
|
||||||
le->next = a->archive_extract_dir_list;
|
le->next = a->archive_extract_dir_list;
|
||||||
a->archive_extract_dir_list = le;
|
a->archive_extract_dir_list = le;
|
||||||
le->mode = archive_entry_stat(entry)->st_mode;
|
le->mode = st->st_mode;
|
||||||
le->mtime = archive_entry_stat(entry)->st_mtime;
|
le->mtime = st->st_mtime;
|
||||||
le->mtime_nanos =
|
le->mtime_nanos = ARCHIVE_STAT_MTIME_NANOS(st);
|
||||||
archive_entry_stat(entry)->st_mtimespec.tv_nsec;
|
le->atime = st->st_atime;
|
||||||
le->atime = archive_entry_stat(entry)->st_atime;
|
le->atime_nanos = ARCHIVE_STAT_ATIME_NANOS(st);
|
||||||
le->atime_nanos =
|
le->name = strdup(archive_entry_pathname(entry));
|
||||||
archive_entry_stat(entry)->st_atimespec.tv_nsec;
|
|
||||||
le->name =
|
|
||||||
malloc(strlen(archive_entry_pathname(entry)) + 1);
|
|
||||||
strcpy(le->name, archive_entry_pathname(entry));
|
|
||||||
a->cleanup_archive_extract = archive_extract_cleanup;
|
a->cleanup_archive_extract = archive_extract_cleanup;
|
||||||
/* Make sure I can write to this directory. */
|
/* Make sure I can write to this directory. */
|
||||||
archive_entry_set_mode(entry, writable_mode);
|
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 */
|
/* XXX Update pathname in 'entry' XXX */
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (archive_entry_stat(entry)->st_mode & S_IFMT) {
|
switch (st->st_mode & S_IFMT) {
|
||||||
default:
|
default:
|
||||||
/* Fall through, as required by POSIX. */
|
/* Fall through, as required by POSIX. */
|
||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
@ -720,10 +718,10 @@ set_time(struct archive *a, struct archive_entry *entry, int flags)
|
|||||||
return (ARCHIVE_OK);
|
return (ARCHIVE_OK);
|
||||||
|
|
||||||
times[1].tv_sec = st->st_mtime;
|
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_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
|
#ifdef HAVE_LUTIMES
|
||||||
if (lutimes(archive_entry_pathname(entry), times) != 0) {
|
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);
|
wchar_t *key, wchar_t *value);
|
||||||
static int pax_header(struct archive *, struct tar *,
|
static int pax_header(struct archive *, struct tar *,
|
||||||
struct archive_entry *, struct stat *, char *attr);
|
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 *,
|
static int read_body_to_string(struct archive *, struct archive_string *,
|
||||||
const void *h);
|
const void *h);
|
||||||
static int64_t tar_atol(const char *, unsigned);
|
static int64_t tar_atol(const char *, unsigned);
|
||||||
@ -884,6 +884,9 @@ static int
|
|||||||
pax_attribute(struct archive_entry *entry, struct stat *st,
|
pax_attribute(struct archive_entry *entry, struct stat *st,
|
||||||
wchar_t *key, wchar_t *value)
|
wchar_t *key, wchar_t *value)
|
||||||
{
|
{
|
||||||
|
int64_t s;
|
||||||
|
long n;
|
||||||
|
|
||||||
switch (key[0]) {
|
switch (key[0]) {
|
||||||
case 'L':
|
case 'L':
|
||||||
/* Our extensions */
|
/* Our extensions */
|
||||||
@ -913,13 +916,18 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
|
|||||||
st->st_nlink = tar_atol10(value, wcslen(value));
|
st->st_nlink = tar_atol10(value, wcslen(value));
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
if (wcscmp(key, L"atime")==0)
|
if (wcscmp(key, L"atime")==0) {
|
||||||
pax_time(value, &(st->st_atimespec));
|
pax_time(value, &s, &n);
|
||||||
|
st->st_atime = s;
|
||||||
|
ARCHIVE_STAT_SET_ATIME_NANOS(st, n);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
if (wcscmp(key, L"ctime")==0)
|
if (wcscmp(key, L"ctime")==0) {
|
||||||
pax_time(value, &(st->st_ctimespec));
|
pax_time(value, &s, &n);
|
||||||
else if (wcscmp(key, L"charset")==0) {
|
st->st_ctime = s;
|
||||||
|
ARCHIVE_STAT_SET_CTIME_NANOS(st, n);
|
||||||
|
} else if (wcscmp(key, L"charset")==0) {
|
||||||
/* TODO: Publish charset information in entry. */
|
/* TODO: Publish charset information in entry. */
|
||||||
} else if (wcscmp(key, L"comment")==0) {
|
} else if (wcscmp(key, L"comment")==0) {
|
||||||
/* TODO: Publish comment in entry. */
|
/* TODO: Publish comment in entry. */
|
||||||
@ -941,8 +949,11 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
if (wcscmp(key, L"mtime")==0)
|
if (wcscmp(key, L"mtime")==0) {
|
||||||
pax_time(value, &(st->st_mtimespec));
|
pax_time(value, &s, &n);
|
||||||
|
st->st_mtime = s;
|
||||||
|
ARCHIVE_STAT_SET_MTIME_NANOS(st, n);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
if (wcscmp(key, L"path")==0)
|
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
|
* parse a decimal time value, which may include a fractional portion
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
pax_time(const wchar_t *p, struct timespec *t)
|
pax_time(const wchar_t *p, int64_t *ps, long *pn)
|
||||||
{
|
{
|
||||||
char digit;
|
char digit;
|
||||||
int64_t s;
|
int64_t s;
|
||||||
@ -1000,10 +1011,10 @@ pax_time(const wchar_t *p, struct timespec *t)
|
|||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->tv_sec = s * sign;
|
*ps = s * sign;
|
||||||
|
|
||||||
/* Calculate nanoseconds. */
|
/* Calculate nanoseconds. */
|
||||||
t->tv_nsec = 0;
|
*pn = 0;
|
||||||
|
|
||||||
if (*p != '.')
|
if (*p != '.')
|
||||||
return;
|
return;
|
||||||
@ -1012,7 +1023,7 @@ pax_time(const wchar_t *p, struct timespec *t)
|
|||||||
do {
|
do {
|
||||||
++p;
|
++p;
|
||||||
if (*p >= '0' && *p <= '9')
|
if (*p >= '0' && *p <= '9')
|
||||||
t->tv_nsec += (*p - '0') * l;
|
*pn += (*p - '0') * l;
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
} while (l /= 10);
|
} while (l /= 10);
|
||||||
|
@ -515,19 +515,22 @@ archive_write_pax_header(struct archive *a,
|
|||||||
|
|
||||||
if (st_main->st_mtime < 0 ||
|
if (st_main->st_mtime < 0 ||
|
||||||
st_main->st_mtime >= 0x7fffffff ||
|
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",
|
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 ||
|
if (st_main->st_ctime != 0 ||
|
||||||
st_main->st_ctime != 0)
|
ARCHIVE_STAT_CTIME_NANOS(st_main) != 0)
|
||||||
add_pax_attr_time(&(pax->pax_header), "ctime",
|
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 ||
|
if (st_main->st_atime != 0 ||
|
||||||
st_main->st_atime != 0)
|
ARCHIVE_STAT_ATIME_NANOS(st_main) != 0)
|
||||||
add_pax_attr_time(&(pax->pax_header), "atime",
|
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. */
|
/* I use a star-compatible file flag attribute. */
|
||||||
p = archive_entry_fflags(entry_main);
|
p = archive_entry_fflags(entry_main);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user