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:
Tim Kientzle 2004-04-21 05:13:42 +00:00
parent f8f8803bd5
commit 0f7d2bd380
5 changed files with 82 additions and 44 deletions

View File

@ -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 *

View File

@ -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
/* /*

View File

@ -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) {

View File

@ -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);

View File

@ -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);