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);
}
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 *

View File

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

View File

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

View File

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

View File

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