summaryrefslogtreecommitdiffstats
path: root/contrib/libarchive/tar
diff options
context:
space:
mode:
authormm <mm@FreeBSD.org>2012-07-28 06:38:44 +0000
committermm <mm@FreeBSD.org>2012-07-28 06:38:44 +0000
commit11bb7fcf7b175da111e710d49b6e1c30153b625b (patch)
tree1ed0c7ff98605ecfbedcfa8d00cd1a29e2dfebe6 /contrib/libarchive/tar
parentf694295168072660e04cabb712367c5a73b59885 (diff)
parente7b24010c4d2190a1465594620e629e469c522f8 (diff)
downloadFreeBSD-src-11bb7fcf7b175da111e710d49b6e1c30153b625b.zip
FreeBSD-src-11bb7fcf7b175da111e710d49b6e1c30153b625b.tar.gz
Update libarchive to 3.0.4
Diffstat (limited to 'contrib/libarchive/tar')
-rw-r--r--contrib/libarchive/tar/bsdtar.12
-rw-r--r--contrib/libarchive/tar/bsdtar.c85
-rw-r--r--contrib/libarchive/tar/bsdtar.h15
-rw-r--r--contrib/libarchive/tar/getdate.c1037
-rw-r--r--contrib/libarchive/tar/read.c80
-rw-r--r--contrib/libarchive/tar/test/main.c321
-rw-r--r--contrib/libarchive/tar/test/test.h12
-rw-r--r--contrib/libarchive/tar/test/test_format_newc.c64
-rw-r--r--contrib/libarchive/tar/test/test_getdate.c80
-rw-r--r--contrib/libarchive/tar/test/test_option_nodump.c68
-rw-r--r--contrib/libarchive/tar/tree.c848
-rw-r--r--contrib/libarchive/tar/tree.h141
-rw-r--r--contrib/libarchive/tar/write.c650
13 files changed, 682 insertions, 2721 deletions
diff --git a/contrib/libarchive/tar/bsdtar.1 b/contrib/libarchive/tar/bsdtar.1
index 4dc7fe2..8298544 100644
--- a/contrib/libarchive/tar/bsdtar.1
+++ b/contrib/libarchive/tar/bsdtar.1
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd Oct 12, 2009
+.Dd December 24, 2011
.Dt TAR 1
.Os
.Sh NAME
diff --git a/contrib/libarchive/tar/bsdtar.c b/contrib/libarchive/tar/bsdtar.c
index fa99984..50f9c99 100644
--- a/contrib/libarchive/tar/bsdtar.c
+++ b/contrib/libarchive/tar/bsdtar.c
@@ -118,9 +118,6 @@ need_report(void)
}
#endif
-/* External function to parse a date/time string */
-time_t get_date(time_t, const char *);
-
static void long_help(void);
static void only_mode(struct bsdtar *, const char *opt,
const char *valid);
@@ -140,7 +137,6 @@ main(int argc, char **argv)
char option_o;
char possible_help_request;
char buff[16];
- time_t now;
/*
* Use a pointer for consistency, but stack-allocated storage
@@ -192,8 +188,6 @@ main(int argc, char **argv)
lafe_progname = *argv;
}
- time(&now);
-
#if HAVE_SETLOCALE
if (setlocale(LC_ALL, "") == NULL)
lafe_warnc(0, "Failed to set default locale");
@@ -241,11 +235,14 @@ main(int argc, char **argv)
* Enable Mac OS "copyfile()" extension by default.
* This has no effect on other platforms.
*/
- bsdtar->enable_copyfile = 1;
+ bsdtar->readdisk_flags |= ARCHIVE_READDISK_MAC_COPYFILE;
#ifdef COPYFILE_DISABLE_VAR
if (getenv(COPYFILE_DISABLE_VAR))
- bsdtar->enable_copyfile = 0;
+ bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE;
#endif
+ bsdtar->matching = archive_match_new();
+ if (bsdtar->matching == NULL)
+ lafe_errc(1, errno, "Out of memory");
bsdtar->argv = argv;
bsdtar->argc = argc;
@@ -287,10 +284,11 @@ main(int argc, char **argv)
bsdtar->option_chroot = 1;
break;
case OPTION_DISABLE_COPYFILE: /* Mac OS X */
- bsdtar->enable_copyfile = 0;
+ bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE;
break;
case OPTION_EXCLUDE: /* GNU tar */
- if (lafe_exclude(&bsdtar->matching, bsdtar->argument))
+ if (archive_match_exclude_pattern(
+ bsdtar->matching, bsdtar->argument) != ARCHIVE_OK)
lafe_errc(1, 0,
"Couldn't exclude %s\n", bsdtar->argument);
break;
@@ -341,7 +339,8 @@ main(int argc, char **argv)
* no one else needs this to filter entries
* when transforming archives.
*/
- if (lafe_include(&bsdtar->matching, bsdtar->argument))
+ if (archive_match_include_pattern(bsdtar->matching,
+ bsdtar->argument) != ARCHIVE_OK)
lafe_errc(1, 0,
"Failed to add %s to inclusion list",
bsdtar->argument);
@@ -395,39 +394,35 @@ main(int argc, char **argv)
* TODO: Add corresponding "older" options to reverse these.
*/
case OPTION_NEWER_CTIME: /* GNU tar */
- bsdtar->newer_ctime_filter = 1;
- bsdtar->newer_ctime_sec = get_date(now, bsdtar->argument);
+ if (archive_match_include_date(bsdtar->matching,
+ ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER,
+ bsdtar->argument) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(bsdtar->matching));
break;
case OPTION_NEWER_CTIME_THAN:
- {
- struct stat st;
- if (stat(bsdtar->argument, &st) != 0)
- lafe_errc(1, 0,
- "Can't open file %s", bsdtar->argument);
- bsdtar->newer_ctime_filter = 1;
- bsdtar->newer_ctime_sec = st.st_ctime;
- bsdtar->newer_ctime_nsec =
- ARCHIVE_STAT_CTIME_NANOS(&st);
- }
+ if (archive_match_include_file_time(bsdtar->matching,
+ ARCHIVE_MATCH_CTIME | ARCHIVE_MATCH_NEWER,
+ bsdtar->argument) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(bsdtar->matching));
break;
case OPTION_NEWER_MTIME: /* GNU tar */
- bsdtar->newer_mtime_filter = 1;
- bsdtar->newer_mtime_sec = get_date(now, bsdtar->argument);
+ if (archive_match_include_date(bsdtar->matching,
+ ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER,
+ bsdtar->argument) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(bsdtar->matching));
break;
case OPTION_NEWER_MTIME_THAN:
- {
- struct stat st;
- if (stat(bsdtar->argument, &st) != 0)
- lafe_errc(1, 0,
- "Can't open file %s", bsdtar->argument);
- bsdtar->newer_mtime_filter = 1;
- bsdtar->newer_mtime_sec = st.st_mtime;
- bsdtar->newer_mtime_nsec =
- ARCHIVE_STAT_MTIME_NANOS(&st);
- }
+ if (archive_match_include_file_time(bsdtar->matching,
+ ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_NEWER,
+ bsdtar->argument) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(bsdtar->matching));
break;
case OPTION_NODUMP: /* star */
- bsdtar->option_honor_nodump = 1;
+ bsdtar->readdisk_flags |= ARCHIVE_READDISK_HONOR_NODUMP;
break;
case OPTION_NO_SAME_OWNER: /* GNU tar */
bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
@@ -454,7 +449,8 @@ main(int argc, char **argv)
option_o = 1; /* Record it and resolve it later. */
break;
case OPTION_ONE_FILE_SYSTEM: /* GNU tar */
- bsdtar->option_dont_traverse_mounts = 1;
+ bsdtar->readdisk_flags |=
+ ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS;
break;
case OPTION_OPTIONS:
bsdtar->option_options = bsdtar->argument;
@@ -559,10 +555,11 @@ main(int argc, char **argv)
bsdtar->option_interactive = 1;
break;
case 'X': /* GNU tar */
- if (lafe_exclude_from_file(&bsdtar->matching, bsdtar->argument))
- lafe_errc(1, 0,
- "failed to process exclusions from file %s",
- bsdtar->argument);
+ if (archive_match_exclude_pattern_from_file(
+ bsdtar->matching, bsdtar->argument, 0)
+ != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(bsdtar->matching));
break;
case 'x': /* SUSv2 */
set_mode(bsdtar, opt);
@@ -612,11 +609,11 @@ main(int argc, char **argv)
"Must specify one of -c, -r, -t, -u, -x");
/* Check boolean options only permitted in certain modes. */
- if (bsdtar->option_dont_traverse_mounts)
+ if (bsdtar->readdisk_flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
only_mode(bsdtar, "--one-file-system", "cru");
if (bsdtar->option_fast_read)
only_mode(bsdtar, "--fast-read", "xt");
- if (bsdtar->option_honor_nodump)
+ if (bsdtar->readdisk_flags & ARCHIVE_READDISK_HONOR_NODUMP)
only_mode(bsdtar, "--nodump", "cru");
if (option_o > 0) {
switch (bsdtar->mode) {
@@ -684,7 +681,7 @@ main(int argc, char **argv)
break;
}
- lafe_cleanup_exclusions(&bsdtar->matching);
+ archive_match_free(bsdtar->matching);
#if HAVE_REGEX_H
cleanup_substitution(bsdtar);
#endif
diff --git a/contrib/libarchive/tar/bsdtar.h b/contrib/libarchive/tar/bsdtar.h
index e561a62..1528c48 100644
--- a/contrib/libarchive/tar/bsdtar.h
+++ b/contrib/libarchive/tar/bsdtar.h
@@ -28,8 +28,6 @@
#include "bsdtar_platform.h"
#include <stdio.h>
-#include "matching.h"
-
#define DEFAULT_BYTES_PER_BLOCK (20*512)
/*
@@ -46,16 +44,11 @@ struct bsdtar {
const char *create_format; /* -F format */
char *pending_chdir; /* -C dir */
const char *names_from_file; /* -T file */
- int newer_ctime_filter; /* --newer/--newer-than */
- time_t newer_ctime_sec; /* --newer/--newer-than */
- long newer_ctime_nsec; /* --newer/--newer-than */
- int newer_mtime_filter; /* --newer-mtime/--newer-mtime-than */
- time_t newer_mtime_sec; /* --newer-mtime */
- long newer_mtime_nsec; /* --newer-mtime-than */
int bytes_per_block; /* -b block_size */
int bytes_in_last_block; /* See -b handling. */
int verbose; /* -v */
int extract_flags; /* Flags for extract operation */
+ int readdisk_flags; /* Flags for read disk operation */
int strip_components; /* Remove this many leading dirs */
int gid; /* --gid */
const char *gname; /* --gname */
@@ -67,10 +60,8 @@ struct bsdtar {
const char *compress_program;
char option_absolute_paths; /* -P */
char option_chroot; /* --chroot */
- char option_dont_traverse_mounts; /* --one-file-system */
char option_fast_read; /* --fast-read */
const char *option_options; /* --options */
- char option_honor_nodump; /* --nodump */
char option_interactive; /* -w */
char option_no_owner; /* -o */
char option_no_subdirs; /* -n */
@@ -81,7 +72,6 @@ struct bsdtar {
char option_unlink_first; /* -U */
char option_warn_links; /* --check-links */
char day_first; /* show day before month in -tv output */
- char enable_copyfile; /* For Mac OS */
/* Option parser state */
int getopt_state;
@@ -111,7 +101,8 @@ struct bsdtar {
struct name_cache *gname_cache; /* for write.c */
char *buff; /* for write.c */
size_t buff_size; /* for write.c */
- struct lafe_matching *matching; /* for matching.c */
+ int first_fs; /* for write.c */
+ struct archive *matching; /* for matching.c */
struct security *security; /* for read.c */
struct name_cache *uname_cache; /* for write.c */
struct siginfo_data *siginfo; /* for siginfo.c */
diff --git a/contrib/libarchive/tar/getdate.c b/contrib/libarchive/tar/getdate.c
deleted file mode 100644
index 0e15d9c..0000000
--- a/contrib/libarchive/tar/getdate.c
+++ /dev/null
@@ -1,1037 +0,0 @@
-/*
- * This code is in the public domain and has no copyright.
- *
- * This is a plain C recursive-descent translation of an old
- * public-domain YACC grammar that has been used for parsing dates in
- * very many open-source projects.
- *
- * Since the original authors were generous enough to donate their
- * work to the public domain, I feel compelled to match their
- * generosity.
- *
- * Tim Kientzle, February 2009.
- */
-
-/*
- * Header comment from original getdate.y:
- */
-
-/*
-** Originally written by Steven M. Bellovin <smb@research.att.com> while
-** at the University of North Carolina at Chapel Hill. Later tweaked by
-** a couple of people on Usenet. Completely overhauled by Rich $alz
-** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
-**
-** This grammar has 10 shift/reduce conflicts.
-**
-** This code is in the public domain and has no copyright.
-*/
-
-#ifdef __FreeBSD__
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-#endif
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-/* This file defines a single public function. */
-time_t get_date(time_t now, char *);
-
-/* Basic time units. */
-#define EPOCH 1970
-#define MINUTE (60L)
-#define HOUR (60L * MINUTE)
-#define DAY (24L * HOUR)
-
-/* Daylight-savings mode: on, off, or not yet known. */
-enum DSTMODE { DSTon, DSToff, DSTmaybe };
-/* Meridian: am or pm. */
-enum { tAM, tPM };
-/* Token types returned by nexttoken() */
-enum { tAGO = 260, tDAY, tDAYZONE, tAMPM, tMONTH, tMONTH_UNIT, tSEC_UNIT,
- tUNUMBER, tZONE, tDST };
-struct token { int token; time_t value; };
-
-/*
- * Parser state.
- */
-struct gdstate {
- struct token *tokenp; /* Pointer to next token. */
- /* HaveXxxx counts how many of this kind of phrase we've seen;
- * it's a fatal error to have more than one time, zone, day,
- * or date phrase. */
- int HaveYear;
- int HaveMonth;
- int HaveDay;
- int HaveWeekDay; /* Day of week */
- int HaveTime; /* Hour/minute/second */
- int HaveZone; /* timezone and/or DST info */
- int HaveRel; /* time offset; we can have more than one */
- /* Absolute time values. */
- time_t Timezone; /* Seconds offset from GMT */
- time_t Day;
- time_t Hour;
- time_t Minutes;
- time_t Month;
- time_t Seconds;
- time_t Year;
- /* DST selection */
- enum DSTMODE DSTmode;
- /* Day of week accounting, e.g., "3rd Tuesday" */
- time_t DayOrdinal; /* "3" in "3rd Tuesday" */
- time_t DayNumber; /* "Tuesday" in "3rd Tuesday" */
- /* Relative time values: hour/day/week offsets are measured in
- * seconds, month/year are counted in months. */
- time_t RelMonth;
- time_t RelSeconds;
-};
-
-/*
- * A series of functions that recognize certain common time phrases.
- * Each function returns 1 if it managed to make sense of some of the
- * tokens, zero otherwise.
- */
-
-/*
- * hour:minute or hour:minute:second with optional AM, PM, or numeric
- * timezone offset
- */
-static int
-timephrase(struct gdstate *gds)
-{
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == ':'
- && gds->tokenp[2].token == tUNUMBER
- && gds->tokenp[3].token == ':'
- && gds->tokenp[4].token == tUNUMBER) {
- /* "12:14:18" or "22:08:07" */
- ++gds->HaveTime;
- gds->Hour = gds->tokenp[0].value;
- gds->Minutes = gds->tokenp[2].value;
- gds->Seconds = gds->tokenp[4].value;
- gds->tokenp += 5;
- }
- else if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == ':'
- && gds->tokenp[2].token == tUNUMBER) {
- /* "12:14" or "22:08" */
- ++gds->HaveTime;
- gds->Hour = gds->tokenp[0].value;
- gds->Minutes = gds->tokenp[2].value;
- gds->Seconds = 0;
- gds->tokenp += 3;
- }
- else if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == tAMPM) {
- /* "7" is a time if it's followed by "am" or "pm" */
- ++gds->HaveTime;
- gds->Hour = gds->tokenp[0].value;
- gds->Minutes = gds->Seconds = 0;
- /* We'll handle the AM/PM below. */
- gds->tokenp += 1;
- } else {
- /* We can't handle this. */
- return 0;
- }
-
- if (gds->tokenp[0].token == tAMPM) {
- /* "7:12pm", "12:20:13am" */
- if (gds->Hour == 12)
- gds->Hour = 0;
- if (gds->tokenp[0].value == tPM)
- gds->Hour += 12;
- gds->tokenp += 1;
- }
- if (gds->tokenp[0].token == '+'
- && gds->tokenp[1].token == tUNUMBER) {
- /* "7:14+0700" */
- gds->HaveZone++;
- gds->DSTmode = DSToff;
- gds->Timezone = - ((gds->tokenp[1].value / 100) * HOUR
- + (gds->tokenp[1].value % 100) * MINUTE);
- gds->tokenp += 2;
- }
- if (gds->tokenp[0].token == '-'
- && gds->tokenp[1].token == tUNUMBER) {
- /* "19:14:12-0530" */
- gds->HaveZone++;
- gds->DSTmode = DSToff;
- gds->Timezone = + ((gds->tokenp[1].value / 100) * HOUR
- + (gds->tokenp[1].value % 100) * MINUTE);
- gds->tokenp += 2;
- }
- return 1;
-}
-
-/*
- * Timezone name, possibly including DST.
- */
-static int
-zonephrase(struct gdstate *gds)
-{
- if (gds->tokenp[0].token == tZONE
- && gds->tokenp[1].token == tDST) {
- gds->HaveZone++;
- gds->Timezone = gds->tokenp[0].value;
- gds->DSTmode = DSTon;
- gds->tokenp += 1;
- return 1;
- }
-
- if (gds->tokenp[0].token == tZONE) {
- gds->HaveZone++;
- gds->Timezone = gds->tokenp[0].value;
- gds->DSTmode = DSToff;
- gds->tokenp += 1;
- return 1;
- }
-
- if (gds->tokenp[0].token == tDAYZONE) {
- gds->HaveZone++;
- gds->Timezone = gds->tokenp[0].value;
- gds->DSTmode = DSTon;
- gds->tokenp += 1;
- return 1;
- }
- return 0;
-}
-
-/*
- * Year/month/day in various combinations.
- */
-static int
-datephrase(struct gdstate *gds)
-{
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == '/'
- && gds->tokenp[2].token == tUNUMBER
- && gds->tokenp[3].token == '/'
- && gds->tokenp[4].token == tUNUMBER) {
- gds->HaveYear++;
- gds->HaveMonth++;
- gds->HaveDay++;
- if (gds->tokenp[0].value >= 13) {
- /* First number is big: 2004/01/29, 99/02/17 */
- gds->Year = gds->tokenp[0].value;
- gds->Month = gds->tokenp[2].value;
- gds->Day = gds->tokenp[4].value;
- } else if ((gds->tokenp[4].value >= 13)
- || (gds->tokenp[2].value >= 13)) {
- /* Last number is big: 01/07/98 */
- /* Middle number is big: 01/29/04 */
- gds->Month = gds->tokenp[0].value;
- gds->Day = gds->tokenp[2].value;
- gds->Year = gds->tokenp[4].value;
- } else {
- /* No significant clues: 02/03/04 */
- gds->Month = gds->tokenp[0].value;
- gds->Day = gds->tokenp[2].value;
- gds->Year = gds->tokenp[4].value;
- }
- gds->tokenp += 5;
- return 1;
- }
-
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == '/'
- && gds->tokenp[2].token == tUNUMBER) {
- /* "1/15" */
- gds->HaveMonth++;
- gds->HaveDay++;
- gds->Month = gds->tokenp[0].value;
- gds->Day = gds->tokenp[2].value;
- gds->tokenp += 3;
- return 1;
- }
-
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == '-'
- && gds->tokenp[2].token == tUNUMBER
- && gds->tokenp[3].token == '-'
- && gds->tokenp[4].token == tUNUMBER) {
- /* ISO 8601 format. yyyy-mm-dd. */
- gds->HaveYear++;
- gds->HaveMonth++;
- gds->HaveDay++;
- gds->Year = gds->tokenp[0].value;
- gds->Month = gds->tokenp[2].value;
- gds->Day = gds->tokenp[4].value;
- gds->tokenp += 5;
- return 1;
- }
-
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == '-'
- && gds->tokenp[2].token == tMONTH
- && gds->tokenp[3].token == '-'
- && gds->tokenp[4].token == tUNUMBER) {
- gds->HaveYear++;
- gds->HaveMonth++;
- gds->HaveDay++;
- if (gds->tokenp[0].value > 31) {
- /* e.g. 1992-Jun-17 */
- gds->Year = gds->tokenp[0].value;
- gds->Month = gds->tokenp[2].value;
- gds->Day = gds->tokenp[4].value;
- } else {
- /* e.g. 17-JUN-1992. */
- gds->Day = gds->tokenp[0].value;
- gds->Month = gds->tokenp[2].value;
- gds->Year = gds->tokenp[4].value;
- }
- gds->tokenp += 5;
- return 1;
- }
-
- if (gds->tokenp[0].token == tMONTH
- && gds->tokenp[1].token == tUNUMBER
- && gds->tokenp[2].token == ','
- && gds->tokenp[3].token == tUNUMBER) {
- /* "June 17, 2001" */
- gds->HaveYear++;
- gds->HaveMonth++;
- gds->HaveDay++;
- gds->Month = gds->tokenp[0].value;
- gds->Day = gds->tokenp[1].value;
- gds->Year = gds->tokenp[3].value;
- gds->tokenp += 4;
- return 1;
- }
-
- if (gds->tokenp[0].token == tMONTH
- && gds->tokenp[1].token == tUNUMBER) {
- /* "May 3" */
- gds->HaveMonth++;
- gds->HaveDay++;
- gds->Month = gds->tokenp[0].value;
- gds->Day = gds->tokenp[1].value;
- gds->tokenp += 2;
- return 1;
- }
-
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == tMONTH
- && gds->tokenp[2].token == tUNUMBER) {
- /* "12 Sept 1997" */
- gds->HaveYear++;
- gds->HaveMonth++;
- gds->HaveDay++;
- gds->Day = gds->tokenp[0].value;
- gds->Month = gds->tokenp[1].value;
- gds->Year = gds->tokenp[2].value;
- gds->tokenp += 3;
- return 1;
- }
-
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == tMONTH) {
- /* "12 Sept" */
- gds->HaveMonth++;
- gds->HaveDay++;
- gds->Day = gds->tokenp[0].value;
- gds->Month = gds->tokenp[1].value;
- gds->tokenp += 2;
- return 1;
- }
-
- return 0;
-}
-
-/*
- * Relative time phrase: "tomorrow", "yesterday", "+1 hour", etc.
- */
-static int
-relunitphrase(struct gdstate *gds)
-{
- if (gds->tokenp[0].token == '-'
- && gds->tokenp[1].token == tUNUMBER
- && gds->tokenp[2].token == tSEC_UNIT) {
- /* "-3 hours" */
- gds->HaveRel++;
- gds->RelSeconds -= gds->tokenp[1].value * gds->tokenp[2].value;
- gds->tokenp += 3;
- return 1;
- }
- if (gds->tokenp[0].token == '+'
- && gds->tokenp[1].token == tUNUMBER
- && gds->tokenp[2].token == tSEC_UNIT) {
- /* "+1 minute" */
- gds->HaveRel++;
- gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value;
- gds->tokenp += 3;
- return 1;
- }
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == tSEC_UNIT) {
- /* "1 day" */
- gds->HaveRel++;
- gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value;
- gds->tokenp += 3;
- return 1;
- }
- if (gds->tokenp[0].token == '-'
- && gds->tokenp[1].token == tUNUMBER
- && gds->tokenp[2].token == tMONTH_UNIT) {
- /* "-3 months" */
- gds->HaveRel++;
- gds->RelMonth -= gds->tokenp[1].value * gds->tokenp[2].value;
- gds->tokenp += 3;
- return 1;
- }
- if (gds->tokenp[0].token == '+'
- && gds->tokenp[1].token == tUNUMBER
- && gds->tokenp[2].token == tMONTH_UNIT) {
- /* "+5 years" */
- gds->HaveRel++;
- gds->RelMonth += gds->tokenp[1].value * gds->tokenp[2].value;
- gds->tokenp += 3;
- return 1;
- }
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == tMONTH_UNIT) {
- /* "2 years" */
- gds->HaveRel++;
- gds->RelMonth += gds->tokenp[0].value * gds->tokenp[1].value;
- gds->tokenp += 2;
- return 1;
- }
- if (gds->tokenp[0].token == tSEC_UNIT) {
- /* "now", "tomorrow" */
- gds->HaveRel++;
- gds->RelSeconds += gds->tokenp[0].value;
- ++gds->tokenp;
- return 1;
- }
- if (gds->tokenp[0].token == tMONTH_UNIT) {
- /* "month" */
- gds->HaveRel++;
- gds->RelMonth += gds->tokenp[0].value;
- gds->tokenp += 1;
- return 1;
- }
- return 0;
-}
-
-/*
- * Day of the week specification.
- */
-static int
-dayphrase(struct gdstate *gds)
-{
- if (gds->tokenp[0].token == tDAY) {
- /* "tues", "wednesday," */
- gds->HaveWeekDay++;
- gds->DayOrdinal = 1;
- gds->DayNumber = gds->tokenp[0].value;
- gds->tokenp += 1;
- if (gds->tokenp[0].token == ',')
- gds->tokenp += 1;
- return 1;
- }
- if (gds->tokenp[0].token == tUNUMBER
- && gds->tokenp[1].token == tDAY) {
- /* "second tues" "3 wed" */
- gds->HaveWeekDay++;
- gds->DayOrdinal = gds->tokenp[0].value;
- gds->DayNumber = gds->tokenp[1].value;
- gds->tokenp += 2;
- return 1;
- }
- return 0;
-}
-
-/*
- * Try to match a phrase using one of the above functions.
- * This layer also deals with a couple of generic issues.
- */
-static int
-phrase(struct gdstate *gds)
-{
- if (timephrase(gds))
- return 1;
- if (zonephrase(gds))
- return 1;
- if (datephrase(gds))
- return 1;
- if (dayphrase(gds))
- return 1;
- if (relunitphrase(gds)) {
- if (gds->tokenp[0].token == tAGO) {
- gds->RelSeconds = -gds->RelSeconds;
- gds->RelMonth = -gds->RelMonth;
- gds->tokenp += 1;
- }
- return 1;
- }
-
- /* Bare numbers sometimes have meaning. */
- if (gds->tokenp[0].token == tUNUMBER) {
- if (gds->HaveTime && !gds->HaveYear && !gds->HaveRel) {
- gds->HaveYear++;
- gds->Year = gds->tokenp[0].value;
- gds->tokenp += 1;
- return 1;
- }
-
- if(gds->tokenp[0].value > 10000) {
- /* "20040301" */
- gds->HaveYear++;
- gds->HaveMonth++;
- gds->HaveDay++;
- gds->Day= (gds->tokenp[0].value)%100;
- gds->Month= (gds->tokenp[0].value/100)%100;
- gds->Year = gds->tokenp[0].value/10000;
- gds->tokenp += 1;
- return 1;
- }
-
- if (gds->tokenp[0].value < 24) {
- gds->HaveTime++;
- gds->Hour = gds->tokenp[0].value;
- gds->Minutes = 0;
- gds->Seconds = 0;
- gds->tokenp += 1;
- return 1;
- }
-
- if ((gds->tokenp[0].value / 100 < 24)
- && (gds->tokenp[0].value % 100 < 60)) {
- /* "513" is same as "5:13" */
- gds->Hour = gds->tokenp[0].value / 100;
- gds->Minutes = gds->tokenp[0].value % 100;
- gds->Seconds = 0;
- gds->tokenp += 1;
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
- * A dictionary of time words.
- */
-static struct LEXICON {
- size_t abbrev;
- const char *name;
- int type;
- time_t value;
-} const TimeWords[] = {
- /* am/pm */
- { 0, "am", tAMPM, tAM },
- { 0, "pm", tAMPM, tPM },
-
- /* Month names. */
- { 3, "january", tMONTH, 1 },
- { 3, "february", tMONTH, 2 },
- { 3, "march", tMONTH, 3 },
- { 3, "april", tMONTH, 4 },
- { 3, "may", tMONTH, 5 },
- { 3, "june", tMONTH, 6 },
- { 3, "july", tMONTH, 7 },
- { 3, "august", tMONTH, 8 },
- { 3, "september", tMONTH, 9 },
- { 3, "october", tMONTH, 10 },
- { 3, "november", tMONTH, 11 },
- { 3, "december", tMONTH, 12 },
-
- /* Days of the week. */
- { 2, "sunday", tDAY, 0 },
- { 3, "monday", tDAY, 1 },
- { 2, "tuesday", tDAY, 2 },
- { 3, "wednesday", tDAY, 3 },
- { 2, "thursday", tDAY, 4 },
- { 2, "friday", tDAY, 5 },
- { 2, "saturday", tDAY, 6 },
-
- /* Timezones: Offsets are in seconds. */
- { 0, "gmt", tZONE, 0*HOUR }, /* Greenwich Mean */
- { 0, "ut", tZONE, 0*HOUR }, /* Universal (Coordinated) */
- { 0, "utc", tZONE, 0*HOUR },
- { 0, "wet", tZONE, 0*HOUR }, /* Western European */
- { 0, "bst", tDAYZONE, 0*HOUR }, /* British Summer */
- { 0, "wat", tZONE, 1*HOUR }, /* West Africa */
- { 0, "at", tZONE, 2*HOUR }, /* Azores */
- /* { 0, "bst", tZONE, 3*HOUR }, */ /* Brazil Standard: Conflict */
- /* { 0, "gst", tZONE, 3*HOUR }, */ /* Greenland Standard: Conflict*/
- { 0, "nft", tZONE, 3*HOUR+30*MINUTE }, /* Newfoundland */
- { 0, "nst", tZONE, 3*HOUR+30*MINUTE }, /* Newfoundland Standard */
- { 0, "ndt", tDAYZONE, 3*HOUR+30*MINUTE }, /* Newfoundland Daylight */
- { 0, "ast", tZONE, 4*HOUR }, /* Atlantic Standard */
- { 0, "adt", tDAYZONE, 4*HOUR }, /* Atlantic Daylight */
- { 0, "est", tZONE, 5*HOUR }, /* Eastern Standard */
- { 0, "edt", tDAYZONE, 5*HOUR }, /* Eastern Daylight */
- { 0, "cst", tZONE, 6*HOUR }, /* Central Standard */
- { 0, "cdt", tDAYZONE, 6*HOUR }, /* Central Daylight */
- { 0, "mst", tZONE, 7*HOUR }, /* Mountain Standard */
- { 0, "mdt", tDAYZONE, 7*HOUR }, /* Mountain Daylight */
- { 0, "pst", tZONE, 8*HOUR }, /* Pacific Standard */
- { 0, "pdt", tDAYZONE, 8*HOUR }, /* Pacific Daylight */
- { 0, "yst", tZONE, 9*HOUR }, /* Yukon Standard */
- { 0, "ydt", tDAYZONE, 9*HOUR }, /* Yukon Daylight */
- { 0, "hst", tZONE, 10*HOUR }, /* Hawaii Standard */
- { 0, "hdt", tDAYZONE, 10*HOUR }, /* Hawaii Daylight */
- { 0, "cat", tZONE, 10*HOUR }, /* Central Alaska */
- { 0, "ahst", tZONE, 10*HOUR }, /* Alaska-Hawaii Standard */
- { 0, "nt", tZONE, 11*HOUR }, /* Nome */
- { 0, "idlw", tZONE, 12*HOUR }, /* Intl Date Line West */
- { 0, "cet", tZONE, -1*HOUR }, /* Central European */
- { 0, "met", tZONE, -1*HOUR }, /* Middle European */
- { 0, "mewt", tZONE, -1*HOUR }, /* Middle European Winter */
- { 0, "mest", tDAYZONE, -1*HOUR }, /* Middle European Summer */
- { 0, "swt", tZONE, -1*HOUR }, /* Swedish Winter */
- { 0, "sst", tDAYZONE, -1*HOUR }, /* Swedish Summer */
- { 0, "fwt", tZONE, -1*HOUR }, /* French Winter */
- { 0, "fst", tDAYZONE, -1*HOUR }, /* French Summer */
- { 0, "eet", tZONE, -2*HOUR }, /* Eastern Eur, USSR Zone 1 */
- { 0, "bt", tZONE, -3*HOUR }, /* Baghdad, USSR Zone 2 */
- { 0, "it", tZONE, -3*HOUR-30*MINUTE },/* Iran */
- { 0, "zp4", tZONE, -4*HOUR }, /* USSR Zone 3 */
- { 0, "zp5", tZONE, -5*HOUR }, /* USSR Zone 4 */
- { 0, "ist", tZONE, -5*HOUR-30*MINUTE },/* Indian Standard */
- { 0, "zp6", tZONE, -6*HOUR }, /* USSR Zone 5 */
- /* { 0, "nst", tZONE, -6.5*HOUR }, */ /* North Sumatra: Conflict */
- /* { 0, "sst", tZONE, -7*HOUR }, */ /* So Sumatra, USSR 6: Conflict */
- { 0, "wast", tZONE, -7*HOUR }, /* West Australian Standard */
- { 0, "wadt", tDAYZONE, -7*HOUR }, /* West Australian Daylight */
- { 0, "jt", tZONE, -7*HOUR-30*MINUTE },/* Java (3pm in Cronusland!)*/
- { 0, "cct", tZONE, -8*HOUR }, /* China Coast, USSR Zone 7 */
- { 0, "jst", tZONE, -9*HOUR }, /* Japan Std, USSR Zone 8 */
- { 0, "cast", tZONE, -9*HOUR-30*MINUTE },/* Ctrl Australian Std */
- { 0, "cadt", tDAYZONE, -9*HOUR-30*MINUTE },/* Ctrl Australian Daylt */
- { 0, "east", tZONE, -10*HOUR }, /* Eastern Australian Std */
- { 0, "eadt", tDAYZONE, -10*HOUR }, /* Eastern Australian Daylt */
- { 0, "gst", tZONE, -10*HOUR }, /* Guam Std, USSR Zone 9 */
- { 0, "nzt", tZONE, -12*HOUR }, /* New Zealand */
- { 0, "nzst", tZONE, -12*HOUR }, /* New Zealand Standard */
- { 0, "nzdt", tDAYZONE, -12*HOUR }, /* New Zealand Daylight */
- { 0, "idle", tZONE, -12*HOUR }, /* Intl Date Line East */
-
- { 0, "dst", tDST, 0 },
-
- /* Time units. */
- { 4, "years", tMONTH_UNIT, 12 },
- { 5, "months", tMONTH_UNIT, 1 },
- { 9, "fortnights", tSEC_UNIT, 14 * DAY },
- { 4, "weeks", tSEC_UNIT, 7 * DAY },
- { 3, "days", tSEC_UNIT, DAY },
- { 4, "hours", tSEC_UNIT, HOUR },
- { 3, "minutes", tSEC_UNIT, MINUTE },
- { 3, "seconds", tSEC_UNIT, 1 },
-
- /* Relative-time words. */
- { 0, "tomorrow", tSEC_UNIT, DAY },
- { 0, "yesterday", tSEC_UNIT, -DAY },
- { 0, "today", tSEC_UNIT, 0 },
- { 0, "now", tSEC_UNIT, 0 },
- { 0, "last", tUNUMBER, -1 },
- { 0, "this", tSEC_UNIT, 0 },
- { 0, "next", tUNUMBER, 2 },
- { 0, "first", tUNUMBER, 1 },
- { 0, "1st", tUNUMBER, 1 },
-/* { 0, "second", tUNUMBER, 2 }, */
- { 0, "2nd", tUNUMBER, 2 },
- { 0, "third", tUNUMBER, 3 },
- { 0, "3rd", tUNUMBER, 3 },
- { 0, "fourth", tUNUMBER, 4 },
- { 0, "4th", tUNUMBER, 4 },
- { 0, "fifth", tUNUMBER, 5 },
- { 0, "5th", tUNUMBER, 5 },
- { 0, "sixth", tUNUMBER, 6 },
- { 0, "seventh", tUNUMBER, 7 },
- { 0, "eighth", tUNUMBER, 8 },
- { 0, "ninth", tUNUMBER, 9 },
- { 0, "tenth", tUNUMBER, 10 },
- { 0, "eleventh", tUNUMBER, 11 },
- { 0, "twelfth", tUNUMBER, 12 },
- { 0, "ago", tAGO, 1 },
-
- /* Military timezones. */
- { 0, "a", tZONE, 1*HOUR },
- { 0, "b", tZONE, 2*HOUR },
- { 0, "c", tZONE, 3*HOUR },
- { 0, "d", tZONE, 4*HOUR },
- { 0, "e", tZONE, 5*HOUR },
- { 0, "f", tZONE, 6*HOUR },
- { 0, "g", tZONE, 7*HOUR },
- { 0, "h", tZONE, 8*HOUR },
- { 0, "i", tZONE, 9*HOUR },
- { 0, "k", tZONE, 10*HOUR },
- { 0, "l", tZONE, 11*HOUR },
- { 0, "m", tZONE, 12*HOUR },
- { 0, "n", tZONE, -1*HOUR },
- { 0, "o", tZONE, -2*HOUR },
- { 0, "p", tZONE, -3*HOUR },
- { 0, "q", tZONE, -4*HOUR },
- { 0, "r", tZONE, -5*HOUR },
- { 0, "s", tZONE, -6*HOUR },
- { 0, "t", tZONE, -7*HOUR },
- { 0, "u", tZONE, -8*HOUR },
- { 0, "v", tZONE, -9*HOUR },
- { 0, "w", tZONE, -10*HOUR },
- { 0, "x", tZONE, -11*HOUR },
- { 0, "y", tZONE, -12*HOUR },
- { 0, "z", tZONE, 0*HOUR },
-
- /* End of table. */
- { 0, NULL, 0, 0 }
-};
-
-/*
- * Year is either:
- * = A number from 0 to 99, which means a year from 1970 to 2069, or
- * = The actual year (>=100).
- */
-static time_t
-Convert(time_t Month, time_t Day, time_t Year,
- time_t Hours, time_t Minutes, time_t Seconds,
- time_t Timezone, enum DSTMODE DSTmode)
-{
- static int DaysInMonth[12] = {
- 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- time_t Julian;
- int i;
-
- if (Year < 69)
- Year += 2000;
- else if (Year < 100)
- Year += 1900;
- DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
- ? 29 : 28;
- /* Checking for 2038 bogusly assumes that time_t is 32 bits. But
- I'm too lazy to try to check for time_t overflow in another way. */
- if (Year < EPOCH || Year > 2038
- || Month < 1 || Month > 12
- /* Lint fluff: "conversion from long may lose accuracy" */
- || Day < 1 || Day > DaysInMonth[(int)--Month]
- || Hours < 0 || Hours > 23
- || Minutes < 0 || Minutes > 59
- || Seconds < 0 || Seconds > 59)
- return -1;
-
- Julian = Day - 1;
- for (i = 0; i < Month; i++)
- Julian += DaysInMonth[i];
- for (i = EPOCH; i < Year; i++)
- Julian += 365 + (i % 4 == 0);
- Julian *= DAY;
- Julian += Timezone;
- Julian += Hours * HOUR + Minutes * MINUTE + Seconds;
- if (DSTmode == DSTon
- || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
- Julian -= HOUR;
- return Julian;
-}
-
-
-static time_t
-DSTcorrect(time_t Start, time_t Future)
-{
- time_t StartDay;
- time_t FutureDay;
-
- StartDay = (localtime(&Start)->tm_hour + 1) % 24;
- FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
- return (Future - Start) + (StartDay - FutureDay) * HOUR;
-}
-
-
-static time_t
-RelativeDate(time_t Start, time_t zone, int dstmode,
- time_t DayOrdinal, time_t DayNumber)
-{
- struct tm *tm;
- time_t t, now;
-
- t = Start - zone;
- tm = gmtime(&t);
- now = Start;
- now += DAY * ((DayNumber - tm->tm_wday + 7) % 7);
- now += 7 * DAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
- if (dstmode == DSTmaybe)
- return DSTcorrect(Start, now);
- return now - Start;
-}
-
-
-static time_t
-RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
-{
- struct tm *tm;
- time_t Month;
- time_t Year;
-
- if (RelMonth == 0)
- return 0;
- tm = localtime(&Start);
- Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
- Year = Month / 12;
- Month = Month % 12 + 1;
- return DSTcorrect(Start,
- Convert(Month, (time_t)tm->tm_mday, Year,
- (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
- Timezone, DSTmaybe));
-}
-
-/*
- * Tokenizer.
- */
-static int
-nexttoken(char **in, time_t *value)
-{
- char c;
- char buff[64];
-
- for ( ; ; ) {
- while (isspace((unsigned char)**in))
- ++*in;
-
- /* Skip parenthesized comments. */
- if (**in == '(') {
- int Count = 0;
- do {
- c = *(*in)++;
- if (c == '\0')
- return c;
- if (c == '(')
- Count++;
- else if (c == ')')
- Count--;
- } while (Count > 0);
- continue;
- }
-
- /* Try the next token in the word table first. */
- /* This allows us to match "2nd", for example. */
- {
- char *src = *in;
- const struct LEXICON *tp;
- unsigned i = 0;
-
- /* Force to lowercase and strip '.' characters. */
- while (*src != '\0'
- && (isalnum((unsigned char)*src) || *src == '.')
- && i < sizeof(buff)-1) {
- if (*src != '.') {
- if (isupper((unsigned char)*src))
- buff[i++] = tolower((unsigned char)*src);
- else
- buff[i++] = *src;
- }
- src++;
- }
- buff[i] = '\0';
-
- /*
- * Find the first match. If the word can be
- * abbreviated, make sure we match at least
- * the minimum abbreviation.
- */
- for (tp = TimeWords; tp->name; tp++) {
- size_t abbrev = tp->abbrev;
- if (abbrev == 0)
- abbrev = strlen(tp->name);
- if (strlen(buff) >= abbrev
- && strncmp(tp->name, buff, strlen(buff))
- == 0) {
- /* Skip over token. */
- *in = src;
- /* Return the match. */
- *value = tp->value;
- return tp->type;
- }
- }
- }
-
- /*
- * Not in the word table, maybe it's a number. Note:
- * Because '-' and '+' have other special meanings, I
- * don't deal with signed numbers here.
- */
- if (isdigit((unsigned char)(c = **in))) {
- for (*value = 0; isdigit((unsigned char)(c = *(*in)++)); )
- *value = 10 * *value + c - '0';
- (*in)--;
- return (tUNUMBER);
- }
-
- return *(*in)++;
- }
-}
-
-#define TM_YEAR_ORIGIN 1900
-
-/* Yield A - B, measured in seconds. */
-static long
-difftm (struct tm *a, struct tm *b)
-{
- int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
- int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
- int days = (
- /* difference in day of year */
- a->tm_yday - b->tm_yday
- /* + intervening leap days */
- + ((ay >> 2) - (by >> 2))
- - (ay/100 - by/100)
- + ((ay/100 >> 2) - (by/100 >> 2))
- /* + difference in years * 365 */
- + (long)(ay-by) * 365
- );
- return (days * DAY + (a->tm_hour - b->tm_hour) * HOUR
- + (a->tm_min - b->tm_min) * MINUTE
- + (a->tm_sec - b->tm_sec));
-}
-
-/*
- *
- * The public function.
- *
- * TODO: tokens[] array should be dynamically sized.
- */
-time_t
-get_date(time_t now, char *p)
-{
- struct token tokens[256];
- struct gdstate _gds;
- struct token *lasttoken;
- struct gdstate *gds;
- struct tm local, *tm;
- struct tm gmt, *gmt_ptr;
- time_t Start;
- time_t tod;
- long tzone;
-
- /* Clear out the parsed token array. */
- memset(tokens, 0, sizeof(tokens));
- /* Initialize the parser state. */
- memset(&_gds, 0, sizeof(_gds));
- gds = &_gds;
-
- /* Look up the current time. */
- memset(&local, 0, sizeof(local));
- tm = localtime (&now);
- if (tm == NULL)
- return -1;
- local = *tm;
-
- /* Look up UTC if we can and use that to determine the current
- * timezone offset. */
- memset(&gmt, 0, sizeof(gmt));
- gmt_ptr = gmtime (&now);
- if (gmt_ptr != NULL) {
- /* Copy, in case localtime and gmtime use the same buffer. */
- gmt = *gmt_ptr;
- }
- if (gmt_ptr != NULL)
- tzone = difftm (&gmt, &local);
- else
- /* This system doesn't understand timezones; fake it. */
- tzone = 0;
- if(local.tm_isdst)
- tzone += HOUR;
-
- /* Tokenize the input string. */
- lasttoken = tokens;
- while ((lasttoken->token = nexttoken(&p, &lasttoken->value)) != 0) {
- ++lasttoken;
- if (lasttoken > tokens + 255)
- return -1;
- }
- gds->tokenp = tokens;
-
- /* Match phrases until we run out of input tokens. */
- while (gds->tokenp < lasttoken) {
- if (!phrase(gds))
- return -1;
- }
-
- /* Use current local timezone if none was specified. */
- if (!gds->HaveZone) {
- gds->Timezone = tzone;
- gds->DSTmode = DSTmaybe;
- }
-
- /* If a timezone was specified, use that for generating the default
- * time components instead of the local timezone. */
- if (gds->HaveZone && gmt_ptr != NULL) {
- now -= gds->Timezone;
- gmt_ptr = gmtime (&now);
- if (gmt_ptr != NULL)
- local = *gmt_ptr;
- now += gds->Timezone;
- }
-
- if (!gds->HaveYear)
- gds->Year = local.tm_year + 1900;
- if (!gds->HaveMonth)
- gds->Month = local.tm_mon + 1;
- if (!gds->HaveDay)
- gds->Day = local.tm_mday;
- /* Note: No default for hour/min/sec; a specifier that just
- * gives date always refers to 00:00 on that date. */
-
- /* If we saw more than one time, timezone, weekday, year, month,
- * or day, then give up. */
- if (gds->HaveTime > 1 || gds->HaveZone > 1 || gds->HaveWeekDay > 1
- || gds->HaveYear > 1 || gds->HaveMonth > 1 || gds->HaveDay > 1)
- return -1;
-
- /* Compute an absolute time based on whatever absolute information
- * we collected. */
- if (gds->HaveYear || gds->HaveMonth || gds->HaveDay
- || gds->HaveTime || gds->HaveWeekDay) {
- Start = Convert(gds->Month, gds->Day, gds->Year,
- gds->Hour, gds->Minutes, gds->Seconds,
- gds->Timezone, gds->DSTmode);
- if (Start < 0)
- return -1;
- } else {
- Start = now;
- if (!gds->HaveRel)
- Start -= local.tm_hour * HOUR + local.tm_min * MINUTE
- + local.tm_sec;
- }
-
- /* Add the relative offset. */
- Start += gds->RelSeconds;
- Start += RelativeMonth(Start, gds->Timezone, gds->RelMonth);
-
- /* Adjust for day-of-week offsets. */
- if (gds->HaveWeekDay
- && !(gds->HaveYear || gds->HaveMonth || gds->HaveDay)) {
- tod = RelativeDate(Start, gds->Timezone,
- gds->DSTmode, gds->DayOrdinal, gds->DayNumber);
- Start += tod;
- }
-
- /* -1 is an error indicator, so return 0 instead of -1 if
- * that's the actual time. */
- return Start == -1 ? 0 : Start;
-}
-
-
-#if defined(TEST)
-
-/* ARGSUSED */
-int
-main(int argc, char **argv)
-{
- time_t d;
-
- while (*++argv != NULL) {
- (void)printf("Input: %s\n", *argv);
- d = get_date(*argv);
- if (d == -1)
- (void)printf("Bad format - couldn't convert.\n");
- else
- (void)printf("Output: %s\n", ctime(&d));
- }
- exit(0);
- /* NOTREACHED */
-}
-#endif /* defined(TEST) */
diff --git a/contrib/libarchive/tar/read.c b/contrib/libarchive/tar/read.c
index 12d4b6a..87ee735 100644
--- a/contrib/libarchive/tar/read.c
+++ b/contrib/libarchive/tar/read.c
@@ -77,12 +77,15 @@ struct progress_data {
static void list_item_verbose(struct bsdtar *, FILE *,
struct archive_entry *);
static void read_archive(struct bsdtar *bsdtar, char mode, struct archive *);
+static int unmatched_inclusions_warn(struct archive *matching, const char *);
+
void
tar_mode_t(struct bsdtar *bsdtar)
{
read_archive(bsdtar, 't', NULL);
- if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0)
+ if (unmatched_inclusions_warn(bsdtar->matching,
+ "Not found in archive") != 0)
bsdtar->return_value = 1;
}
@@ -100,7 +103,8 @@ tar_mode_x(struct bsdtar *bsdtar)
read_archive(bsdtar, 'x', writer);
- if (lafe_unmatched_inclusions_warn(bsdtar->matching, "Not found in archive") != 0)
+ if (unmatched_inclusions_warn(bsdtar->matching,
+ "Not found in archive") != 0)
bsdtar->return_value = 1;
archive_write_free(writer);
}
@@ -152,17 +156,21 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer)
struct archive *a;
struct archive_entry *entry;
int r;
- time_t sec;
- long nsec;
while (*bsdtar->argv) {
- lafe_include(&bsdtar->matching, *bsdtar->argv);
+ if (archive_match_include_pattern(bsdtar->matching,
+ *bsdtar->argv) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error inclusion pattern: %s",
+ archive_error_string(bsdtar->matching));
bsdtar->argv++;
}
if (bsdtar->names_from_file != NULL)
- lafe_include_from_file(&bsdtar->matching,
- bsdtar->names_from_file, bsdtar->option_null);
+ if (archive_match_include_pattern_from_file(
+ bsdtar->matching, bsdtar->names_from_file,
+ bsdtar->option_null) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error inclusion pattern: %s",
+ archive_error_string(bsdtar->matching));
a = archive_read_new();
if (bsdtar->compress_program != NULL)
@@ -199,7 +207,7 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer)
for (;;) {
/* Support --fast-read option */
if (bsdtar->option_fast_read &&
- lafe_unmatched_inclusions(bsdtar->matching) == 0)
+ archive_match_path_unmatched_inclusions(bsdtar->matching) == 0)
break;
r = archive_read_next_header(a, &entry);
@@ -232,42 +240,6 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer)
archive_entry_set_gname(entry, bsdtar->gname);
/*
- * Exclude entries that are too old.
- */
- if (bsdtar->newer_ctime_filter) {
- /* Use ctime if format provides, else mtime. */
- if (archive_entry_ctime_is_set(entry)) {
- sec = archive_entry_ctime(entry);
- nsec = archive_entry_ctime_nsec(entry);
- } else if (archive_entry_mtime_is_set(entry)) {
- sec = archive_entry_mtime(entry);
- nsec = archive_entry_mtime_nsec(entry);
- } else {
- sec = 0;
- nsec = 0;
- }
- if (sec < bsdtar->newer_ctime_sec)
- continue; /* Too old, skip it. */
- if (sec == bsdtar->newer_ctime_sec
- && nsec <= bsdtar->newer_ctime_nsec)
- continue; /* Too old, skip it. */
- }
- if (bsdtar->newer_mtime_filter) {
- if (archive_entry_mtime_is_set(entry)) {
- sec = archive_entry_mtime(entry);
- nsec = archive_entry_mtime_nsec(entry);
- } else {
- sec = 0;
- nsec = 0;
- }
- if (sec < bsdtar->newer_mtime_sec)
- continue; /* Too old, skip it. */
- if (sec == bsdtar->newer_mtime_sec
- && nsec <= bsdtar->newer_mtime_nsec)
- continue; /* Too old, skip it. */
- }
-
- /*
* Note that pattern exclusions are checked before
* pathname rewrites are handled. This gives more
* control over exclusions, since rewrites always lose
@@ -276,7 +248,7 @@ read_archive(struct bsdtar *bsdtar, char mode, struct archive *writer)
* rewrite, there would be no way to exclude foo1/bar
* while allowing foo2/bar.)
*/
- if (lafe_excluded(bsdtar->matching, archive_entry_pathname(entry)))
+ if (archive_match_excluded(bsdtar->matching, entry))
continue; /* Excluded by a pattern test. */
if (mode == 't') {
@@ -471,3 +443,21 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
else if (archive_entry_symlink(entry)) /* Symbolic link */
safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
}
+
+static int
+unmatched_inclusions_warn(struct archive *matching, const char *msg)
+{
+ const char *p;
+ int r;
+
+ if (matching == NULL)
+ return (0);
+
+ while ((r = archive_match_path_unmatched_inclusions_next(
+ matching, &p)) == ARCHIVE_OK)
+ lafe_warnc(0, "%s: %s", p, msg);
+ if (r == ARCHIVE_FATAL)
+ lafe_errc(1, errno, "Out of memory");
+
+ return (archive_match_path_unmatched_inclusions(matching));
+}
diff --git a/contrib/libarchive/tar/test/main.c b/contrib/libarchive/tar/test/main.c
index 798b4e0..0d617e3 100644
--- a/contrib/libarchive/tar/test/main.c
+++ b/contrib/libarchive/tar/test/main.c
@@ -24,6 +24,9 @@
*/
#include "test.h"
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
@@ -31,6 +34,16 @@
#ifdef HAVE_ICONV_H
#include <iconv.h>
#endif
+/*
+ * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
+ * As the include guards don't agree, the order of include is important.
+ */
+#ifdef HAVE_LINUX_EXT2_FS_H
+#include <linux/ext2_fs.h> /* for Linux file flags */
+#endif
+#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
+#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */
+#endif
#include <limits.h>
#include <locale.h>
#ifdef HAVE_SIGNAL_H
@@ -116,7 +129,14 @@ __FBSDID("$FreeBSD$");
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
-void *GetFunctionKernel32(const char *name)
+static void *GetFunctionKernel32(const char *);
+static int my_CreateSymbolicLinkA(const char *, const char *, int);
+static int my_CreateHardLinkA(const char *, const char *);
+static int my_GetFileInformationByName(const char *,
+ BY_HANDLE_FILE_INFORMATION *);
+
+static void *
+GetFunctionKernel32(const char *name)
{
static HINSTANCE lib;
static int set;
@@ -155,7 +175,7 @@ my_CreateHardLinkA(const char *linkname, const char *target)
return f == NULL ? 0 : (*f)(linkname, target, NULL);
}
-int
+static int
my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
{
HANDLE h;
@@ -1507,7 +1527,7 @@ assertion_make_dir(const char *file, int line, const char *dirname, int mode)
/* Create a file with the specified contents and report any failures. */
int
assertion_make_file(const char *file, int line,
- const char *path, int mode, const char *contents)
+ const char *path, int mode, int csize, const void *contents)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
/* TODO: Rework this to set file mode as well. */
@@ -1521,8 +1541,13 @@ assertion_make_file(const char *file, int line,
return (0);
}
if (contents != NULL) {
- if (strlen(contents)
- != fwrite(contents, 1, strlen(contents), f)) {
+ size_t wsize;
+
+ if (csize < 0)
+ wsize = strlen(contents);
+ else
+ wsize = (size_t)csize;
+ if (wsize != fwrite(contents, 1, wsize, f)) {
fclose(f);
failure_start(file, line,
"Could not write file %s", path);
@@ -1542,10 +1567,16 @@ assertion_make_file(const char *file, int line,
return (0);
}
if (contents != NULL) {
- if ((ssize_t)strlen(contents)
- != write(fd, contents, strlen(contents))) {
+ ssize_t wsize;
+
+ if (csize < 0)
+ wsize = (ssize_t)strlen(contents);
+ else
+ wsize = (ssize_t)csize;
+ if (wsize != write(fd, contents, wsize)) {
close(fd);
- failure_start(file, line, "Could not write to %s", path);
+ failure_start(file, line,
+ "Could not write to %s", path);
failure_finish(NULL);
return (0);
}
@@ -1716,6 +1747,52 @@ assertion_utimes(const char *file, int line,
#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
}
+/* Set nodump, report failures. */
+int
+assertion_nodump(const char *file, int line, const char *pathname)
+{
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
+ int r;
+
+ assertion_count(file, line);
+ r = chflags(pathname, UF_NODUMP);
+ if (r < 0) {
+ failure_start(file, line, "Can't set nodump %s\n", pathname);
+ failure_finish(NULL);
+ return (0);
+ }
+#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
+ && defined(EXT2_NODUMP_FL)
+ int fd, r, flags;
+
+ assertion_count(file, line);
+ fd = open(pathname, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ failure_start(file, line, "Can't open %s\n", pathname);
+ failure_finish(NULL);
+ return (0);
+ }
+ r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
+ if (r < 0) {
+ failure_start(file, line, "Can't get flags %s\n", pathname);
+ failure_finish(NULL);
+ return (0);
+ }
+ flags |= EXT2_NODUMP_FL;
+ r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
+ if (r < 0) {
+ failure_start(file, line, "Can't set nodump %s\n", pathname);
+ failure_finish(NULL);
+ return (0);
+ }
+ close(fd);
+#else
+ (void)pathname; /* UNUSED */
+ assertion_count(file, line);
+#endif
+ return (1);
+}
+
/*
*
* UTILITIES for use by tests.
@@ -1744,7 +1821,7 @@ canSymlink(void)
return (value);
++tested;
- assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, "a");
+ assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a");
/* Note: Cygwin has its own symlink() emulation that does not
* use the Win32 CreateSymbolicLink() function. */
#if defined(_WIN32) && !defined(__CYGWIN__)
@@ -1794,6 +1871,70 @@ canGunzip(void)
}
/*
+ * Can this filesystem handle nodump flags.
+ */
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
+
+int
+canNodump(void)
+{
+ const char *path = "cannodumptest";
+ struct stat sb;
+
+ assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
+ if (chflags(path, UF_NODUMP) < 0)
+ return (0);
+ if (stat(path, &sb) < 0)
+ return (0);
+ if (sb.st_flags & UF_NODUMP)
+ return (1);
+ return (0);
+}
+
+#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
+ && defined(EXT2_NODUMP_FL)
+
+int
+canNodump(void)
+{
+ const char *path = "cannodumptest";
+ int fd, r, flags;
+
+ assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
+ fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ return (0);
+ r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
+ if (r < 0)
+ return (0);
+ flags |= EXT2_NODUMP_FL;
+ r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
+ if (r < 0)
+ return (0);
+ close(fd);
+ fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (fd < 0)
+ return (0);
+ r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
+ if (r < 0)
+ return (0);
+ close(fd);
+ if (flags & EXT2_NODUMP_FL)
+ return (1);
+ return (0);
+}
+
+#else
+
+int
+canNodump()
+{
+ return (0);
+}
+
+#endif
+
+/*
* Sleep as needed; useful for verifying disk timestamp changes by
* ensuring that the wall-clock time has actually changed before we
* go back to re-read something from disk.
@@ -2236,17 +2377,77 @@ success:
return strdup(buff);
}
+static int
+get_test_set(int *test_set, int limit, const char *test)
+{
+ int start, end;
+ int idx = 0;
+
+ if (test == NULL) {
+ /* Default: Run all tests. */
+ for (;idx < limit; idx++)
+ test_set[idx] = idx;
+ return (limit);
+ }
+ if (*test >= '0' && *test <= '9') {
+ const char *vp = test;
+ start = 0;
+ while (*vp >= '0' && *vp <= '9') {
+ start *= 10;
+ start += *vp - '0';
+ ++vp;
+ }
+ if (*vp == '\0') {
+ end = start;
+ } else if (*vp == '-') {
+ ++vp;
+ if (*vp == '\0') {
+ end = limit - 1;
+ } else {
+ end = 0;
+ while (*vp >= '0' && *vp <= '9') {
+ end *= 10;
+ end += *vp - '0';
+ ++vp;
+ }
+ }
+ } else
+ return (-1);
+ if (start < 0 || end >= limit || start > end)
+ return (-1);
+ while (start <= end)
+ test_set[idx++] = start++;
+ } else {
+ size_t len = strlen(test);
+ for (start = 0; start < limit; ++start) {
+ const char *name = tests[start].name;
+ const char *p;
+
+ while ((p = strchr(name, test[0])) != NULL) {
+ if (strncmp(p, test, len) == 0) {
+ test_set[idx++] = start;
+ break;
+ } else
+ name = p + 1;
+ }
+
+ }
+ }
+ return ((idx == 0)?-1:idx);
+}
+
int
main(int argc, char **argv)
{
static const int limit = sizeof(tests) / sizeof(tests[0]);
- int i = 0, j = 0, start, end, tests_run = 0, tests_failed = 0, option;
+ int test_set[sizeof(tests) / sizeof(tests[0])];
+ int i = 0, j = 0, tests_run = 0, tests_failed = 0, option;
time_t now;
char *refdir_alloc = NULL;
const char *progname;
char **saved_argv;
const char *tmp, *option_arg, *p;
- char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL;
+ char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL;
char tmpdir_timestamp[256];
(void)argc; /* UNUSED */
@@ -2332,6 +2533,19 @@ main(int argc, char **argv)
if (getenv(ENVBASE "_DEBUG") != NULL)
dump_on_failure = 1;
+ /* Allow -v to be controlled through the environment. */
+ if (getenv("_VERBOSITY_LEVEL") != NULL)
+ {
+ vlevel = getenv("_VERBOSITY_LEVEL");
+ verbosity = atoi(vlevel);
+ if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL)
+ {
+ /* Unsupported verbosity levels are silently ignored */
+ vlevel = NULL;
+ verbosity = VERBOSITY_PASSFAIL;
+ }
+ }
+
/* Get the directory holding test files from environment. */
refdir = getenv(ENVBASE "_TEST_FILES");
@@ -2379,7 +2593,8 @@ main(int argc, char **argv)
#endif
break;
case 'q':
- verbosity--;
+ if (!vlevel)
+ verbosity--;
break;
case 'r':
refdir = option_arg;
@@ -2388,7 +2603,8 @@ main(int argc, char **argv)
until_failure++;
break;
case 'v':
- verbosity++;
+ if (!vlevel)
+ verbosity++;
break;
default:
fprintf(stderr, "Unrecognized option '%c'\n",
@@ -2501,78 +2717,27 @@ main(int argc, char **argv)
saved_argv = argv;
do {
argv = saved_argv;
- if (*argv == NULL) {
- /* Default: Run all tests. */
- for (i = 0; i < limit; i++) {
+ do {
+ int test_num;
+
+ test_num = get_test_set(test_set, limit, *argv);
+ if (test_num < 0) {
+ printf("*** INVALID Test %s\n", *argv);
+ free(refdir_alloc);
+ usage(progname);
+ return (1);
+ }
+ for (i = 0; i < test_num; i++) {
tests_run++;
- if (test_run(i, tmpdir)) {
+ if (test_run(test_set[i], tmpdir)) {
tests_failed++;
if (until_failure)
goto finish;
}
}
- } else {
- while (*(argv) != NULL) {
- if (**argv >= '0' && **argv <= '9') {
- char *vp = *argv;
- start = 0;
- while (*vp >= '0' && *vp <= '9') {
- start *= 10;
- start += *vp - '0';
- ++vp;
- }
- if (*vp == '\0') {
- end = start;
- } else if (*vp == '-') {
- ++vp;
- if (*vp == '\0') {
- end = limit - 1;
- } else {
- end = 0;
- while (*vp >= '0' && *vp <= '9') {
- end *= 10;
- end += *vp - '0';
- ++vp;
- }
- }
- } else {
- printf("*** INVALID Test %s\n", *argv);
- free(refdir_alloc);
- usage(progname);
- return (1);
- }
- if (start < 0 || end >= limit || start > end) {
- printf("*** INVALID Test %s\n", *argv);
- free(refdir_alloc);
- usage(progname);
- return (1);
- }
- } else {
- for (start = 0; start < limit; ++start) {
- if (strcmp(*argv, tests[start].name) == 0)
- break;
- }
- end = start;
- if (start >= limit) {
- printf("*** INVALID Test ``%s''\n",
- *argv);
- free(refdir_alloc);
- usage(progname);
- /* usage() never returns */
- }
- }
- while (start <= end) {
- tests_run++;
- if (test_run(start, tmpdir)) {
- tests_failed++;
- if (until_failure)
- goto finish;
- }
- ++start;
- }
+ if (*argv != NULL)
argv++;
- }
- }
+ } while (*argv != NULL);
} while (until_failure);
finish:
diff --git a/contrib/libarchive/tar/test/test.h b/contrib/libarchive/tar/test/test.h
index 43462cc..4c6e9cb 100644
--- a/contrib/libarchive/tar/test/test.h
+++ b/contrib/libarchive/tar/test/test.h
@@ -196,11 +196,15 @@
#define assertMakeDir(dirname, mode) \
assertion_make_dir(__FILE__, __LINE__, dirname, mode)
#define assertMakeFile(path, mode, contents) \
- assertion_make_file(__FILE__, __LINE__, path, mode, contents)
+ assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents)
+#define assertMakeBinFile(path, mode, csize, contents) \
+ assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents)
#define assertMakeHardlink(newfile, oldfile) \
assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile)
#define assertMakeSymlink(newfile, linkto) \
assertion_make_symlink(__FILE__, __LINE__, newfile, linkto)
+#define assertNodump(path) \
+ assertion_nodump(__FILE__, __LINE__, path)
#define assertUmask(mask) \
assertion_umask(__FILE__, __LINE__, mask)
#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \
@@ -243,9 +247,10 @@ int assertion_is_not_hardlink(const char *, int, const char *, const char *);
int assertion_is_reg(const char *, int, const char *, int);
int assertion_is_symlink(const char *, int, const char *, const char *);
int assertion_make_dir(const char *, int, const char *, int);
-int assertion_make_file(const char *, int, const char *, int, const char *);
+int assertion_make_file(const char *, int, const char *, int, int, const void *);
int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
int assertion_make_symlink(const char *, int, const char *newpath, const char *);
+int assertion_nodump(const char *, int, const char *);
int assertion_non_empty_file(const char *, int, const char *);
int assertion_text_file_contents(const char *, int, const char *buff, const char *f);
int assertion_umask(const char *, int, int);
@@ -269,6 +274,9 @@ int canGzip(void);
/* Return true if this platform can run the "gunzip" program. */
int canGunzip(void);
+/* Return true if this filesystem can handle nodump flags. */
+int canNodump(void);
+
/* Return true if the file has large i-node number(>0xffffffff). */
int is_LargeInode(const char *);
diff --git a/contrib/libarchive/tar/test/test_format_newc.c b/contrib/libarchive/tar/test/test_format_newc.c
new file mode 100644
index 0000000..808fa4b
--- /dev/null
+++ b/contrib/libarchive/tar/test/test_format_newc.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+DEFINE_TEST(test_format_newc)
+{
+
+ assertMakeFile("file1", 0644, "file1");
+ assertMakeFile("file2", 0644, "file2");
+ assertMakeHardlink("file3", "file1");
+
+ /* Test 1: Create an archive file with a newc format. */
+ assertEqualInt(0,
+ systemf("%s -cf test1.cpio --format newc file1 file2 file3",
+ testprog));
+ assertMakeDir("test1", 0755);
+ assertChdir("test1");
+ assertEqualInt(0,
+ systemf("%s -xf ../test1.cpio >test.out 2>test.err", testprog));
+ assertFileContents("file1", 5, "file1");
+ assertFileContents("file2", 5, "file2");
+ assertFileContents("file1", 5, "file3");
+ assertEmptyFile("test.out");
+ assertEmptyFile("test.err");
+ assertChdir("..");
+
+ /* Test 2: Exclude one of hardlinked files. */
+ assertEqualInt(0,
+ systemf("%s -cf test2.cpio --format newc file1 file2",
+ testprog));
+ assertMakeDir("test2", 0755);
+ assertChdir("test2");
+ assertEqualInt(0,
+ systemf("%s -xf ../test2.cpio >test.out 2>test.err", testprog));
+ assertFileContents("file1", 5, "file1");
+ assertFileContents("file2", 5, "file2");
+ assertFileNotExists("file3");
+ assertEmptyFile("test.out");
+ assertEmptyFile("test.err");
+ assertChdir("..");
+}
diff --git a/contrib/libarchive/tar/test/test_getdate.c b/contrib/libarchive/tar/test/test_getdate.c
deleted file mode 100644
index cd6d55a..0000000
--- a/contrib/libarchive/tar/test/test_getdate.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "test.h"
-__FBSDID("$FreeBSD$");
-
-#include <time.h>
-
-/*
- * Verify that the getdate() function works.
- */
-
-time_t get_date(time_t, const char *);
-
-DEFINE_TEST(test_getdate)
-{
- time_t now = time(NULL);
-
- assertEqualInt(get_date(now, "Jan 1, 1970 UTC"), 0);
- assertEqualInt(get_date(now, "7:12:18-0530 4 May 1983"), 420900138);
- assertEqualInt(get_date(now, "2004/01/29 513 mest"), 1075345980);
- assertEqualInt(get_date(now, "99/02/17 7pm utc"), 919278000);
- assertEqualInt(get_date(now, "02/17/99 7:11am est"), 919253460);
- /* It's important that we handle ctime() format. */
- assertEqualInt(get_date(now, "Sun Feb 22 17:38:26 PST 2009"),
- 1235353106);
- /* Basic relative offsets. */
- /* If we use the actual current time as the reference, then
- * these tests break around DST changes, so it's actually
- * important to use a specific reference time here. */
- assertEqualInt(get_date(0, "tomorrow"), 24 * 60 * 60);
- assertEqualInt(get_date(0, "yesterday"), - 24 * 60 * 60);
- assertEqualInt(get_date(0, "now + 1 hour"), 60 * 60);
- assertEqualInt(get_date(0, "now + 1 hour + 1 minute"), 60 * 60 + 60);
- /* Repeat the above for a different start time. */
- now = 1231113600; /* Jan 5, 2009 00:00 UTC */
- assertEqualInt(get_date(0, "Jan 5, 2009 00:00 UTC"), now);
- assertEqualInt(get_date(now, "tomorrow"), now + 24 * 60 * 60);
- assertEqualInt(get_date(now, "yesterday"), now - 24 * 60 * 60);
- assertEqualInt(get_date(now, "now + 1 hour"), now + 60 * 60);
- assertEqualInt(get_date(now, "now + 1 hour + 1 minute"),
- now + 60 * 60 + 60);
- assertEqualInt(get_date(now, "tomorrow 5:16am UTC"),
- now + 24 * 60 * 60 + 5 * 60 * 60 + 16 * 60);
- assertEqualInt(get_date(now, "UTC 5:16am tomorrow"),
- now + 24 * 60 * 60 + 5 * 60 * 60 + 16 * 60);
-
- /* Jan 5, 2009 was a Monday. */
- assertEqualInt(get_date(now, "monday UTC"), now);
- assertEqualInt(get_date(now, "sunday UTC"), now + 6 * 24 * 60 * 60);
- assertEqualInt(get_date(now, "tuesday UTC"), now + 24 * 60 * 60);
- /* "next tuesday" is one week after "tuesday" */
- assertEqualInt(get_date(now, "UTC next tuesday"),
- now + 8 * 24 * 60 * 60);
- /* "last tuesday" is one week before "tuesday" */
- assertEqualInt(get_date(now, "last tuesday UTC"),
- now - 6 * 24 * 60 * 60);
- /* TODO: Lots more tests here. */
-}
diff --git a/contrib/libarchive/tar/test/test_option_nodump.c b/contrib/libarchive/tar/test/test_option_nodump.c
new file mode 100644
index 0000000..768f64a
--- /dev/null
+++ b/contrib/libarchive/tar/test/test_option_nodump.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+DEFINE_TEST(test_option_nodump)
+{
+
+ if (!canNodump()) {
+ skipping("Can't test nodump on this filesystem");
+ return;
+ }
+
+ assertMakeFile("file1", 0644, "file1");
+ assertMakeFile("file2", 0644, "file2");
+ assertMakeFile("file3", 0644, "file3");
+ assertNodump("file2");
+
+ /* Test 1: Without --nodump */
+ assertEqualInt(0, systemf("%s -cf test1.tar file1 file2 file3",
+ testprog));
+ assertMakeDir("test1", 0755);
+ assertChdir("test1");
+ assertEqualInt(0,
+ systemf("%s -xf ../test1.tar >test.out 2>test.err", testprog));
+ assertFileContents("file1", 5, "file1");
+ assertFileContents("file2", 5, "file2");
+ assertFileContents("file3", 5, "file3");
+ assertEmptyFile("test.out");
+ assertEmptyFile("test.err");
+ assertChdir("..");
+
+ /* Test 2: With --nodump */
+ assertEqualInt(0, systemf("%s -cf test2.tar --nodump file1 file2 file3",
+ testprog));
+ assertMakeDir("test2", 0755);
+ assertChdir("test2");
+ assertEqualInt(0,
+ systemf("%s -xf ../test2.tar >test.out 2>test.err", testprog));
+ assertFileContents("file1", 5, "file1");
+ assertFileNotExists("file2");
+ assertFileContents("file3", 5, "file3");
+ assertEmptyFile("test.out");
+ assertEmptyFile("test.err");
+ assertChdir("..");
+}
diff --git a/contrib/libarchive/tar/tree.c b/contrib/libarchive/tar/tree.c
deleted file mode 100644
index a5bcdf4..0000000
--- a/contrib/libarchive/tar/tree.c
+++ /dev/null
@@ -1,848 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*-
- * This is a new directory-walking system that addresses a number
- * of problems I've had with fts(3). In particular, it has no
- * pathname-length limits (other than the size of 'int'), handles
- * deep logical traversals, uses considerably less memory, and has
- * an opaque interface (easier to modify in the future).
- *
- * Internally, it keeps a single list of "tree_entry" items that
- * represent filesystem objects that require further attention.
- * Non-directories are not kept in memory: they are pulled from
- * readdir(), returned to the client, then freed as soon as possible.
- * Any directory entry to be traversed gets pushed onto the stack.
- *
- * There is surprisingly little information that needs to be kept for
- * each item on the stack. Just the name, depth (represented here as the
- * string length of the parent directory's pathname), and some markers
- * indicating how to get back to the parent (via chdir("..") for a
- * regular dir or via fchdir(2) for a symlink).
- */
-#include "bsdtar_platform.h"
-__FBSDID("$FreeBSD$");
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef HAVE_DIRECT_H
-#include <direct.h>
-#endif
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if defined(HAVE_WINDOWS_H) && !defined(__CYGWIN__)
-#include <windows.h>
-#endif
-
-#include "tree.h"
-
-/*
- * TODO:
- * 1) Loop checking.
- * 3) Arbitrary logical traversals by closing/reopening intermediate fds.
- */
-
-struct tree_entry {
- int depth;
- struct tree_entry *next;
- struct tree_entry *parent;
- char *name;
- size_t dirname_length;
- dev_t dev;
- ino_t ino;
- int flags;
- /* How to return back to the parent of a symlink. */
-#ifdef HAVE_FCHDIR
- int symlink_parent_fd;
-#elif defined(_WIN32) && !defined(__CYGWIN__)
- char *symlink_parent_path;
-#else
-#error fchdir function required.
-#endif
-};
-
-/* Definitions for tree_entry.flags bitmap. */
-#define isDir 1 /* This entry is a regular directory. */
-#define isDirLink 2 /* This entry is a symbolic link to a directory. */
-#define needsFirstVisit 4 /* This is an initial entry. */
-#define needsDescent 8 /* This entry needs to be previsited. */
-#define needsOpen 16 /* This is a directory that needs to be opened. */
-#define needsAscent 32 /* This entry needs to be postvisited. */
-
-/*
- * On Windows, "first visit" is handled as a pattern to be handed to
- * _findfirst(). This is consistent with Windows conventions that
- * file patterns are handled within the application. On Posix,
- * "first visit" is just returned to the client.
- */
-
-/*
- * Local data for this package.
- */
-struct tree {
- struct tree_entry *stack;
- struct tree_entry *current;
-#if defined(_WIN32) && !defined(__CYGWIN__)
- HANDLE d;
- BY_HANDLE_FILE_INFORMATION fileInfo;
-#define INVALID_DIR_HANDLE INVALID_HANDLE_VALUE
- WIN32_FIND_DATA _findData;
- WIN32_FIND_DATA *findData;
-#else
- DIR *d;
-#define INVALID_DIR_HANDLE NULL
- struct dirent *de;
-#endif
- int flags;
- int visit_type;
- int tree_errno; /* Error code from last failed operation. */
-
- /* Dynamically-sized buffer for holding path */
- char *buff;
- size_t buff_length;
-
- const char *basename; /* Last path element */
- size_t dirname_length; /* Leading dir length */
- size_t path_length; /* Total path length */
-
- int depth;
- int openCount;
- int maxOpenCount;
-
- struct stat lst;
- struct stat st;
-};
-
-/* Definitions for tree.flags bitmap. */
-#define hasStat 16 /* The st entry is valid. */
-#define hasLstat 32 /* The lst entry is valid. */
-#define hasFileInfo 64 /* The Windows fileInfo entry is valid. */
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-static int
-tree_dir_next_windows(struct tree *t, const char *pattern);
-#else
-static int
-tree_dir_next_posix(struct tree *t);
-#endif
-
-#ifdef HAVE_DIRENT_D_NAMLEN
-/* BSD extension; avoids need for a strlen() call. */
-#define D_NAMELEN(dp) (dp)->d_namlen
-#else
-#define D_NAMELEN(dp) (strlen((dp)->d_name))
-#endif
-
-#include <stdio.h>
-void
-tree_dump(struct tree *t, FILE *out)
-{
- char buff[300];
- struct tree_entry *te;
-
- fprintf(out, "\tdepth: %d\n", t->depth);
- fprintf(out, "\tbuff: %s\n", t->buff);
- fprintf(out, "\tpwd: %s\n", getcwd(buff, sizeof(buff)));
- fprintf(out, "\tbasename: %s\n", t->basename);
- fprintf(out, "\tstack:\n");
- for (te = t->stack; te != NULL; te = te->next) {
- fprintf(out, "\t\t%s%d:\"%s\" %s%s%s%s%s%s\n",
- t->current == te ? "*" : " ",
- te->depth,
- te->name,
- te->flags & needsFirstVisit ? "V" : "",
- te->flags & needsDescent ? "D" : "",
- te->flags & needsOpen ? "O" : "",
- te->flags & needsAscent ? "A" : "",
- te->flags & isDirLink ? "L" : "",
- (t->current == te && t->d) ? "+" : ""
- );
- }
-}
-
-/*
- * Add a directory path to the current stack.
- */
-static void
-tree_push(struct tree *t, const char *path)
-{
- struct tree_entry *te;
-
- te = malloc(sizeof(*te));
- memset(te, 0, sizeof(*te));
- te->next = t->stack;
- te->parent = t->current;
- if (te->parent)
- te->depth = te->parent->depth + 1;
- t->stack = te;
-#ifdef HAVE_FCHDIR
- te->symlink_parent_fd = -1;
- te->name = strdup(path);
-#elif defined(_WIN32) && !defined(__CYGWIN__)
- te->symlink_parent_path = NULL;
- te->name = strdup(path);
-#endif
- te->flags = needsDescent | needsOpen | needsAscent;
- te->dirname_length = t->dirname_length;
-}
-
-/*
- * Append a name to the current dir path.
- */
-static void
-tree_append(struct tree *t, const char *name, size_t name_length)
-{
- char *p;
- size_t size_needed;
-
- if (t->buff != NULL)
- t->buff[t->dirname_length] = '\0';
- /* Strip trailing '/' from name, unless entire name is "/". */
- while (name_length > 1 && name[name_length - 1] == '/')
- name_length--;
-
- /* Resize pathname buffer as needed. */
- size_needed = name_length + 1 + t->dirname_length;
- if (t->buff_length < size_needed) {
- if (t->buff_length < 1024)
- t->buff_length = 1024;
- while (t->buff_length < size_needed)
- t->buff_length *= 2;
- t->buff = realloc(t->buff, t->buff_length);
- }
- if (t->buff == NULL)
- abort();
- p = t->buff + t->dirname_length;
- t->path_length = t->dirname_length + name_length;
- /* Add a separating '/' if it's needed. */
- if (t->dirname_length > 0 && p[-1] != '/') {
- *p++ = '/';
- t->path_length ++;
- }
-#if HAVE_STRNCPY_S
- strncpy_s(p, t->buff_length - (p - t->buff), name, name_length);
-#else
- strncpy(p, name, name_length);
-#endif
- p[name_length] = '\0';
- t->basename = p;
-}
-
-/*
- * Open a directory tree for traversal.
- */
-struct tree *
-tree_open(const char *path)
-{
-#ifdef HAVE_FCHDIR
- struct tree *t;
-
- t = malloc(sizeof(*t));
- memset(t, 0, sizeof(*t));
- /* First item is set up a lot like a symlink traversal. */
- tree_push(t, path);
- t->stack->flags = needsFirstVisit | isDirLink | needsAscent;
- t->stack->symlink_parent_fd = open(".", O_RDONLY);
- t->openCount++;
- t->d = INVALID_DIR_HANDLE;
- return (t);
-#elif defined(_WIN32) && !defined(__CYGWIN__)
- struct tree *t;
- char *cwd = _getcwd(NULL, 0);
- char *pathname, *p, *base;
- wchar_t *wcs, *wp;
- size_t l, wlen;
-
- /* Take care of '\' character in multi-byte character-set.
- * Some multi-byte character-set have been using '\' character
- * for a part of its character code. */
- l = MultiByteToWideChar(CP_OEMCP, 0, path, strlen(path), NULL, 0);
- if (l == 0)
- abort();
- wcs = malloc(sizeof(*wcs) * (l+1));
- if (wcs == NULL)
- abort();
- l = MultiByteToWideChar(CP_OEMCP, 0, path, strlen(path), wcs, l);
- wcs[l] = L'\0';
- wlen = l;
- for (wp = wcs; *wp != L'\0'; ++wp) {
- if (*wp == L'\\')
- *wp = L'/';
- }
- l = WideCharToMultiByte(CP_OEMCP, 0, wcs, wlen, NULL, 0, NULL, NULL);
- if (l == 0)
- abort();
- pathname = malloc(l+1);
- if (pathname == NULL)
- abort();
- l = WideCharToMultiByte(CP_OEMCP, 0, wcs, wlen, pathname, l, NULL, NULL);
- pathname[l] = '\0';
- free(wcs);
- base = pathname;
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* ASCII version APIs do not accept the path which begin with
- * "//?/" prefix. */
- if (strncmp(base, "//?/", 4) == 0)
- base += 4;
-#endif
-
- t = malloc(sizeof(*t));
- memset(t, 0, sizeof(*t));
- /* First item is set up a lot like a symlink traversal. */
- /* printf("Looking for wildcard in %s\n", path); */
- /* TODO: wildcard detection here screws up on \\?\c:\ UNC names */
- if (strchr(base, '*') || strchr(base, '?')) {
- /* It has a wildcard in it... */
- /* Separate the last element. */
- p = strrchr(base, '/');
- if (p != NULL) {
- *p = '\0';
- chdir(base);
- tree_append(t, base, p - base);
- t->dirname_length = t->path_length;
- base = p + 1;
- }
- }
- tree_push(t, base);
- free(pathname);
- t->stack->flags = needsFirstVisit | isDirLink | needsAscent;
- t->stack->symlink_parent_path = cwd;
- t->d = INVALID_DIR_HANDLE;
- return (t);
-#endif
-}
-
-/*
- * We've finished a directory; ascend back to the parent.
- */
-static int
-tree_ascend(struct tree *t)
-{
- struct tree_entry *te;
- int r = 0;
-
- te = t->stack;
- t->depth--;
- if (te->flags & isDirLink) {
-#ifdef HAVE_FCHDIR
- if (fchdir(te->symlink_parent_fd) != 0) {
- t->tree_errno = errno;
- r = TREE_ERROR_FATAL;
- }
- close(te->symlink_parent_fd);
-#elif defined(_WIN32) && !defined(__CYGWIN__)
- if (SetCurrentDirectory(te->symlink_parent_path) == 0) {
- t->tree_errno = errno;
- r = TREE_ERROR_FATAL;
- }
- free(te->symlink_parent_path);
- te->symlink_parent_path = NULL;
-#endif
- t->openCount--;
- } else {
-#if defined(_WIN32) && !defined(__CYGWIN__)
- if (SetCurrentDirectory("..") == 0) {
-#else
- if (chdir("..") != 0) {
-#endif
- t->tree_errno = errno;
- r = TREE_ERROR_FATAL;
- }
- }
- return (r);
-}
-
-/*
- * Pop the working stack.
- */
-static void
-tree_pop(struct tree *t)
-{
- struct tree_entry *te;
-
- if (t->buff)
- t->buff[t->dirname_length] = '\0';
- if (t->stack == t->current && t->current != NULL)
- t->current = t->current->parent;
- te = t->stack;
- t->stack = te->next;
- t->dirname_length = te->dirname_length;
- if (t->buff) {
- t->basename = t->buff + t->dirname_length;
- while (t->basename[0] == '/')
- t->basename++;
- }
- free(te->name);
- free(te);
-}
-
-/*
- * Get the next item in the tree traversal.
- */
-int
-tree_next(struct tree *t)
-{
- int r;
-
- /* If we're called again after a fatal error, that's an API
- * violation. Just crash now. */
- if (t->visit_type == TREE_ERROR_FATAL) {
- fprintf(stderr, "Unable to continue traversing"
- " directory hierarchy after a fatal error.");
- abort();
- }
-
- while (t->stack != NULL) {
- /* If there's an open dir, get the next entry from there. */
- if (t->d != INVALID_DIR_HANDLE) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
- r = tree_dir_next_windows(t, NULL);
-#else
- r = tree_dir_next_posix(t);
-#endif
- if (r == 0)
- continue;
- return (r);
- }
-
- if (t->stack->flags & needsFirstVisit) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
- char *d = t->stack->name;
- t->stack->flags &= ~needsFirstVisit;
- if (strchr(d, '*') || strchr(d, '?')) {
- r = tree_dir_next_windows(t, d);
- if (r == 0)
- continue;
- return (r);
- }
- /* Not a pattern, handle it as-is... */
-#endif
- /* Top stack item needs a regular visit. */
- t->current = t->stack;
- tree_append(t, t->stack->name, strlen(t->stack->name));
- /* t->dirname_length = t->path_length; */
- /* tree_pop(t); */
- t->stack->flags &= ~needsFirstVisit;
- return (t->visit_type = TREE_REGULAR);
- } else if (t->stack->flags & needsDescent) {
- /* Top stack item is dir to descend into. */
- t->current = t->stack;
- tree_append(t, t->stack->name, strlen(t->stack->name));
- t->stack->flags &= ~needsDescent;
- /* If it is a link, set up fd for the ascent. */
- if (t->stack->flags & isDirLink) {
-#ifdef HAVE_FCHDIR
- t->stack->symlink_parent_fd = open(".", O_RDONLY);
- t->openCount++;
- if (t->openCount > t->maxOpenCount)
- t->maxOpenCount = t->openCount;
-#elif defined(_WIN32) && !defined(__CYGWIN__)
- t->stack->symlink_parent_path = _getcwd(NULL, 0);
-#endif
- }
- t->dirname_length = t->path_length;
-#if defined(_WIN32) && !defined(__CYGWIN__)
- if (t->path_length == 259 || !SetCurrentDirectory(t->stack->name) != 0)
-#else
- if (chdir(t->stack->name) != 0)
-#endif
- {
- /* chdir() failed; return error */
- tree_pop(t);
- t->tree_errno = errno;
- return (t->visit_type = TREE_ERROR_DIR);
- }
- t->depth++;
- return (t->visit_type = TREE_POSTDESCENT);
- } else if (t->stack->flags & needsOpen) {
- t->stack->flags &= ~needsOpen;
-#if defined(_WIN32) && !defined(__CYGWIN__)
- r = tree_dir_next_windows(t, "*");
-#else
- r = tree_dir_next_posix(t);
-#endif
- if (r == 0)
- continue;
- return (r);
- } else if (t->stack->flags & needsAscent) {
- /* Top stack item is dir and we're done with it. */
- r = tree_ascend(t);
- tree_pop(t);
- t->visit_type = r != 0 ? r : TREE_POSTASCENT;
- return (t->visit_type);
- } else {
- /* Top item on stack is dead. */
- tree_pop(t);
- t->flags &= ~hasLstat;
- t->flags &= ~hasStat;
- }
- }
- return (t->visit_type = 0);
-}
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-static int
-tree_dir_next_windows(struct tree *t, const char *pattern)
-{
- const char *name;
- size_t namelen;
- int r;
-
- for (;;) {
- if (pattern != NULL) {
- t->d = FindFirstFile(pattern, &t->_findData);
- if (t->d == INVALID_DIR_HANDLE) {
- r = tree_ascend(t); /* Undo "chdir" */
- tree_pop(t);
- t->tree_errno = errno;
- t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
- return (t->visit_type);
- }
- t->findData = &t->_findData;
- pattern = NULL;
- } else if (!FindNextFile(t->d, &t->_findData)) {
- FindClose(t->d);
- t->d = INVALID_DIR_HANDLE;
- t->findData = NULL;
- return (0);
- }
- name = t->findData->cFileName;
- namelen = strlen(name);
- t->flags &= ~hasLstat;
- t->flags &= ~hasStat;
- if (name[0] == '.' && name[1] == '\0')
- continue;
- if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
- continue;
- tree_append(t, name, namelen);
- return (t->visit_type = TREE_REGULAR);
- }
-}
-#else
-static int
-tree_dir_next_posix(struct tree *t)
-{
- int r;
- const char *name;
- size_t namelen;
-
- if (t->d == NULL) {
- if ((t->d = opendir(".")) == NULL) {
- r = tree_ascend(t); /* Undo "chdir" */
- tree_pop(t);
- t->tree_errno = errno;
- t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
- return (t->visit_type);
- }
- }
- for (;;) {
- t->de = readdir(t->d);
- if (t->de == NULL) {
- closedir(t->d);
- t->d = INVALID_DIR_HANDLE;
- return (0);
- }
- name = t->de->d_name;
- namelen = D_NAMELEN(t->de);
- t->flags &= ~hasLstat;
- t->flags &= ~hasStat;
- if (name[0] == '.' && name[1] == '\0')
- continue;
- if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
- continue;
- tree_append(t, name, namelen);
- return (t->visit_type = TREE_REGULAR);
- }
-}
-#endif
-
-/*
- * Return error code.
- */
-int
-tree_errno(struct tree *t)
-{
- return (t->tree_errno);
-}
-
-/*
- * Called by the client to mark the directory just returned from
- * tree_next() as needing to be visited.
- */
-void
-tree_descend(struct tree *t)
-{
- if (t->visit_type != TREE_REGULAR)
- return;
-
- if (tree_current_is_physical_dir(t)) {
- tree_push(t, t->basename);
- t->stack->flags |= isDir;
- } else if (tree_current_is_dir(t)) {
- tree_push(t, t->basename);
- t->stack->flags |= isDirLink;
- }
-}
-
-/*
- * Get the stat() data for the entry just returned from tree_next().
- */
-const struct stat *
-tree_current_stat(struct tree *t)
-{
- if (!(t->flags & hasStat)) {
- if (stat(tree_current_access_path(t), &t->st) != 0)
- return NULL;
- t->flags |= hasStat;
- }
- return (&t->st);
-}
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-const BY_HANDLE_FILE_INFORMATION *
-tree_current_file_information(struct tree *t)
-{
- if (!(t->flags & hasFileInfo)) {
- HANDLE h = CreateFile(tree_current_access_path(t),
- 0, 0, NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
- if (h == INVALID_HANDLE_VALUE)
- return NULL;
- if (!GetFileInformationByHandle(h, &t->fileInfo)) {
- CloseHandle(h);
- return NULL;
- }
- CloseHandle(h);
- t->flags |= hasFileInfo;
- }
- return (&t->fileInfo);
-}
-#endif
-/*
- * Get the lstat() data for the entry just returned from tree_next().
- */
-const struct stat *
-tree_current_lstat(struct tree *t)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- return (tree_current_stat(t));
-#else
- if (!(t->flags & hasLstat)) {
- if (lstat(tree_current_access_path(t), &t->lst) != 0)
- return NULL;
- t->flags |= hasLstat;
- }
- return (&t->lst);
-#endif
-}
-
-/*
- * Test whether current entry is a dir or link to a dir.
- */
-int
-tree_current_is_dir(struct tree *t)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- if (t->findData)
- return (t->findData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
- if (tree_current_file_information(t))
- return (t->fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
- return (0);
-#else
- const struct stat *st;
- /*
- * If we already have lstat() info, then try some
- * cheap tests to determine if this is a dir.
- */
- if (t->flags & hasLstat) {
- /* If lstat() says it's a dir, it must be a dir. */
- if (S_ISDIR(tree_current_lstat(t)->st_mode))
- return 1;
- /* Not a dir; might be a link to a dir. */
- /* If it's not a link, then it's not a link to a dir. */
- if (!S_ISLNK(tree_current_lstat(t)->st_mode))
- return 0;
- /*
- * It's a link, but we don't know what it's a link to,
- * so we'll have to use stat().
- */
- }
-
- st = tree_current_stat(t);
- /* If we can't stat it, it's not a dir. */
- if (st == NULL)
- return 0;
- /* Use the definitive test. Hopefully this is cached. */
- return (S_ISDIR(st->st_mode));
-#endif
-}
-
-/*
- * Test whether current entry is a physical directory. Usually, we
- * already have at least one of stat() or lstat() in memory, so we
- * use tricks to try to avoid an extra trip to the disk.
- */
-int
-tree_current_is_physical_dir(struct tree *t)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
- if (tree_current_is_physical_link(t))
- return (0);
- return (tree_current_is_dir(t));
-#else
- const struct stat *st;
-
- /*
- * If stat() says it isn't a dir, then it's not a dir.
- * If stat() data is cached, this check is free, so do it first.
- */
- if ((t->flags & hasStat)
- && (!S_ISDIR(tree_current_stat(t)->st_mode)))
- return 0;
-
- /*
- * Either stat() said it was a dir (in which case, we have
- * to determine whether it's really a link to a dir) or
- * stat() info wasn't available. So we use lstat(), which
- * hopefully is already cached.
- */
-
- st = tree_current_lstat(t);
- /* If we can't stat it, it's not a dir. */
- if (st == NULL)
- return 0;
- /* Use the definitive test. Hopefully this is cached. */
- return (S_ISDIR(st->st_mode));
-#endif
-}
-
-/*
- * Test whether current entry is a symbolic link.
- */
-int
-tree_current_is_physical_link(struct tree *t)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#ifndef IO_REPARSE_TAG_SYMLINK
-/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */
-#define IO_REPARSE_TAG_SYMLINK 0xA000000CL
-#endif
- if (t->findData)
- return ((t->findData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
- && (t->findData->dwReserved0 == IO_REPARSE_TAG_SYMLINK));
- return (0);
-#else
- const struct stat *st = tree_current_lstat(t);
- if (st == NULL)
- return 0;
- return (S_ISLNK(st->st_mode));
-#endif
-}
-
-/*
- * Return the access path for the entry just returned from tree_next().
- */
-const char *
-tree_current_access_path(struct tree *t)
-{
- return (t->basename);
-}
-
-/*
- * Return the full path for the entry just returned from tree_next().
- */
-const char *
-tree_current_path(struct tree *t)
-{
- return (t->buff);
-}
-
-/*
- * Return the length of the path for the entry just returned from tree_next().
- */
-size_t
-tree_current_pathlen(struct tree *t)
-{
- return (t->path_length);
-}
-
-/*
- * Return the nesting depth of the entry just returned from tree_next().
- */
-int
-tree_current_depth(struct tree *t)
-{
- return (t->depth);
-}
-
-/*
- * Terminate the traversal and release any resources.
- */
-void
-tree_close(struct tree *t)
-{
- /* Release anything remaining in the stack. */
- while (t->stack != NULL)
- tree_pop(t);
- free(t->buff);
- /* TODO: Ensure that premature close() resets cwd */
-#if 0
-#ifdef HAVE_FCHDIR
- if (t->initialDirFd >= 0) {
- int s = fchdir(t->initialDirFd);
- (void)s; /* UNUSED */
- close(t->initialDirFd);
- t->initialDirFd = -1;
- }
-#elif defined(_WIN32) && !defined(__CYGWIN__)
- if (t->initialDir != NULL) {
- SetCurrentDir(t->initialDir);
- free(t->initialDir);
- t->initialDir = NULL;
- }
-#endif
-#endif
- free(t);
-}
diff --git a/contrib/libarchive/tar/tree.h b/contrib/libarchive/tar/tree.h
deleted file mode 100644
index 3ae74fd..0000000
--- a/contrib/libarchive/tar/tree.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-/*-
- * A set of routines for traversing directory trees.
- * Similar in concept to the fts library, but with a few
- * important differences:
- * * Uses less memory. In particular, fts stores an entire directory
- * in memory at a time. This package only keeps enough subdirectory
- * information in memory to track the traversal. Information
- * about non-directories is discarded as soon as possible.
- * * Supports very deep logical traversals. The fts package
- * uses "non-chdir" approach for logical traversals. This
- * package does use a chdir approach for logical traversals
- * and can therefore handle pathnames much longer than PATH_MAX.
- * * Supports deep physical traversals "out of the box."
- * Due to the memory optimizations above, there's no need to
- * limit dir names to 32k.
- */
-
-#include <sys/stat.h>
-#include <stdio.h>
-
-struct tree;
-
-/* Initiate/terminate a tree traversal. */
-struct tree *tree_open(const char * /* pathname */);
-void tree_close(struct tree *);
-
-/*
- * tree_next() returns Zero if there is no next entry, non-zero if
- * there is. Note that directories are visited three times.
- * Directories are always visited first as part of enumerating their
- * parent; that is a "regular" visit. If tree_descend() is invoked at
- * that time, the directory is added to a work list and will
- * subsequently be visited two more times: once just after descending
- * into the directory ("postdescent") and again just after ascending
- * back to the parent ("postascent").
- *
- * TREE_ERROR_DIR is returned if the descent failed (because the
- * directory couldn't be opened, for instance). This is returned
- * instead of TREE_POSTDESCENT/TREE_POSTASCENT. TREE_ERROR_DIR is not a
- * fatal error, but it does imply that the relevant subtree won't be
- * visited. TREE_ERROR_FATAL is returned for an error that left the
- * traversal completely hosed. Right now, this is only returned for
- * chdir() failures during ascent.
- */
-#define TREE_REGULAR 1
-#define TREE_POSTDESCENT 2
-#define TREE_POSTASCENT 3
-#define TREE_ERROR_DIR -1
-#define TREE_ERROR_FATAL -2
-
-int tree_next(struct tree *);
-
-/* Errno value associated with the last traversal error. */
-int tree_errno(struct tree *);
-
-/*
- * Request that current entry be visited. If you invoke it on every
- * directory, you'll get a physical traversal. This is ignored if the
- * current entry isn't a directory or a link to a directory. So, if
- * you invoke this on every returned path, you'll get a full logical
- * traversal.
- */
-void tree_descend(struct tree *);
-
-/*
- * Return information about the current entry.
- */
-
-/* Current depth in the traversal. */
-int tree_current_depth(struct tree *);
-
-/*
- * The current full pathname, length of the full pathname, and a name
- * that can be used to access the file. Because tree does use chdir
- * extensively, the access path is almost never the same as the full
- * current path.
- *
- * TODO: Flesh out this interface to provide other information. In
- * particular, Windows can provide file size, mode, and some permission
- * information without invoking stat() at all.
- *
- * TODO: On platforms that support it, use openat()-style operations
- * to eliminate the chdir() operations entirely while still supporting
- * arbitrarily deep traversals. This makes access_path troublesome to
- * support, of course, which means we'll need a rich enough interface
- * that clients can function without it. (In particular, we'll need
- * tree_current_open() that returns an open file descriptor.)
- *
- * TODO: Provide tree_current_archive_entry().
- */
-const char *tree_current_path(struct tree *);
-size_t tree_current_pathlen(struct tree *);
-const char *tree_current_access_path(struct tree *);
-
-/*
- * Request the lstat() or stat() data for the current path. Since the
- * tree package needs to do some of this anyway, and caches the
- * results, you should take advantage of it here if you need it rather
- * than make a redundant stat() or lstat() call of your own.
- */
-const struct stat *tree_current_stat(struct tree *);
-const struct stat *tree_current_lstat(struct tree *);
-
-/* The following functions use tricks to avoid a certain number of
- * stat()/lstat() calls. */
-/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */
-int tree_current_is_physical_dir(struct tree *);
-/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */
-int tree_current_is_physical_link(struct tree *);
-/* "is_dir" is equivalent to S_ISDIR(tree_current_stat()->st_mode) */
-int tree_current_is_dir(struct tree *);
-
-/* For testing/debugging: Dump the internal status to the given filehandle. */
-void tree_dump(struct tree *, FILE *);
diff --git a/contrib/libarchive/tar/write.c b/contrib/libarchive/tar/write.c
index 799d511..f8987c7 100644
--- a/contrib/libarchive/tar/write.c
+++ b/contrib/libarchive/tar/write.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,9 +30,6 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
@@ -56,20 +54,6 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
-#ifdef HAVE_LINUX_FS_H
-#include <linux/fs.h> /* for Linux file flags */
-#endif
-/*
- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
- * As the include guards don't agree, the order of include is important.
- */
-#ifdef HAVE_LINUX_EXT2_FS_H
-#include <linux/ext2_fs.h> /* for Linux file flags */
-#endif
-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
-/* This header exists but is broken on Cygwin. */
-#include <ext2fs/ext2_fs.h>
-#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
@@ -93,7 +77,6 @@ __FBSDID("$FreeBSD$");
#include "bsdtar.h"
#include "err.h"
#include "line_reader.h"
-#include "tree.h"
#ifndef O_BINARY
#define O_BINARY 0
@@ -110,28 +93,27 @@ struct archive_dir {
struct archive_dir_entry *head, *tail;
};
-static void add_dir_list(struct bsdtar *bsdtar, const char *path,
- time_t mtime_sec, int mtime_nsec);
static int append_archive(struct bsdtar *, struct archive *,
struct archive *ina);
static int append_archive_filename(struct bsdtar *,
struct archive *, const char *fname);
static void archive_names_from_file(struct bsdtar *bsdtar,
struct archive *a);
-static int copy_file_data(struct bsdtar *, struct archive *a,
- struct archive *ina, struct archive_entry *);
-static int new_enough(struct bsdtar *, const char *path,
- const struct stat *);
+static int copy_file_data_block(struct bsdtar *,
+ struct archive *a, struct archive *,
+ struct archive_entry *);
+static void excluded_callback(struct archive *, void *,
+ struct archive_entry *);
static void report_write(struct bsdtar *, struct archive *,
struct archive_entry *, int64_t progress);
static void test_for_append(struct bsdtar *);
+static int metadata_filter(struct archive *, void *,
+ struct archive_entry *);
static void write_archive(struct archive *, struct bsdtar *);
static void write_entry(struct bsdtar *, struct archive *,
struct archive_entry *);
static void write_file(struct bsdtar *, struct archive *,
struct archive_entry *);
-static int write_file_data(struct bsdtar *, struct archive *,
- struct archive_entry *, int fd, size_t align);
static void write_hierarchy(struct bsdtar *, struct archive *,
const char *);
@@ -360,9 +342,11 @@ tar_mode_u(struct bsdtar *bsdtar)
lafe_errc(1, 0,
"Cannot append to compressed archive.");
}
- add_dir_list(bsdtar, archive_entry_pathname(entry),
- archive_entry_mtime(entry),
- archive_entry_mtime_nsec(entry));
+ if (archive_match_exclude_entry(bsdtar->matching,
+ ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_OLDER |
+ ARCHIVE_MATCH_EQUAL, entry) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(bsdtar->matching));
/* Record the last format determination we see */
format = archive_format(a);
/* Keep going until we hit end-of-archive */
@@ -426,8 +410,30 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
lafe_errc(1, 0, "cannot create link resolver");
archive_entry_linkresolver_set_strategy(bsdtar->resolver,
archive_format(a));
+
+ /* Create a read_disk object. */
if ((bsdtar->diskreader = archive_read_disk_new()) == NULL)
lafe_errc(1, 0, "Cannot create read_disk object");
+ /* Tell the read_disk how handle symlink. */
+ switch (bsdtar->symlink_mode) {
+ case 'H':
+ archive_read_disk_set_symlink_hybrid(bsdtar->diskreader);
+ break;
+ case 'L':
+ archive_read_disk_set_symlink_logical(bsdtar->diskreader);
+ break;
+ default:
+ archive_read_disk_set_symlink_physical(bsdtar->diskreader);
+ break;
+ }
+ /* Register entry filters. */
+ archive_read_disk_set_matching(bsdtar->diskreader,
+ bsdtar->matching, excluded_callback, bsdtar);
+ archive_read_disk_set_metadata_filter_callback(
+ bsdtar->diskreader, metadata_filter, bsdtar);
+ /* Set the behavior of archive_read_disk. */
+ archive_read_disk_set_behavior(bsdtar->diskreader,
+ bsdtar->readdisk_flags);
archive_read_disk_set_standard_lookup(bsdtar->diskreader);
if (bsdtar->names_from_file != NULL)
@@ -467,11 +473,57 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
bsdtar->argv++;
}
+ archive_read_disk_set_matching(bsdtar->diskreader, NULL, NULL, NULL);
+ archive_read_disk_set_metadata_filter_callback(
+ bsdtar->diskreader, NULL, NULL);
entry = NULL;
archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry);
while (entry != NULL) {
+ int r;
+ struct archive_entry *entry2;
+ struct archive *disk = bsdtar->diskreader;
+
+ /*
+ * This tricky code here is to correctly read the cotents
+ * of the entry because the disk reader bsdtar->diskreader
+ * is pointing at does not have any information about the
+ * entry by this time and using archive_read_data_block()
+ * with the disk reader consequently must fail. And we
+ * have to re-open the entry to read the contents.
+ */
+ /* TODO: Work with -C option as well. */
+ r = archive_read_disk_open(disk,
+ archive_entry_sourcepath(entry));
+ if (r != ARCHIVE_OK) {
+ lafe_warnc(archive_errno(disk),
+ "%s", archive_error_string(disk));
+ bsdtar->return_value = 1;
+ archive_entry_free(entry);
+ continue;
+ }
+
+ /*
+ * Invoke archive_read_next_header2() to work
+ * archive_read_data_block(), which is called via write_file(),
+ * without failure.
+ */
+ entry2 = archive_entry_new();
+ r = archive_read_next_header2(disk, entry2);
+ archive_entry_free(entry2);
+ if (r != ARCHIVE_OK) {
+ lafe_warnc(archive_errno(disk),
+ "%s", archive_error_string(disk));
+ if (r == ARCHIVE_FATAL)
+ bsdtar->return_value = 1;
+ else
+ archive_read_close(disk);
+ archive_entry_free(entry);
+ continue;
+ }
+
write_file(bsdtar, a, entry);
archive_entry_free(entry);
+ archive_read_close(disk);
entry = NULL;
archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry);
}
@@ -584,10 +636,7 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
int e;
while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) {
- if (!new_enough(bsdtar, archive_entry_pathname(in_entry),
- archive_entry_stat(in_entry)))
- continue;
- if (lafe_excluded(bsdtar->matching, archive_entry_pathname(in_entry)))
+ if (archive_match_excluded(bsdtar->matching, in_entry))
continue;
if (bsdtar->option_interactive &&
!yes("copy '%s'", archive_entry_pathname(in_entry)))
@@ -613,7 +662,7 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
if (e >= ARCHIVE_WARN) {
if (archive_entry_size(in_entry) == 0)
archive_read_data_skip(ina);
- else if (copy_file_data(bsdtar, a, ina, in_entry))
+ else if (copy_file_data_block(bsdtar, a, ina, in_entry))
exit(1);
}
@@ -624,204 +673,168 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
return (e == ARCHIVE_EOF ? ARCHIVE_OK : e);
}
-/* Helper function to copy data between archives. */
+/* Helper function to copy file to archive. */
static int
-copy_file_data(struct bsdtar *bsdtar, struct archive *a,
- struct archive *ina, struct archive_entry *entry)
+copy_file_data_block(struct bsdtar *bsdtar, struct archive *a,
+ struct archive *in_a, struct archive_entry *entry)
{
- ssize_t bytes_read;
+ size_t bytes_read;
ssize_t bytes_written;
- int64_t progress = 0;
+ int64_t offset, progress = 0;
+ char *null_buff = NULL;
+ const void *buff;
+ int r;
- bytes_read = archive_read_data(ina, bsdtar->buff, bsdtar->buff_size);
- while (bytes_read > 0) {
+ while ((r = archive_read_data_block(in_a, &buff,
+ &bytes_read, &offset)) == ARCHIVE_OK) {
if (need_report())
report_write(bsdtar, a, entry, progress);
- bytes_written = archive_write_data(a, bsdtar->buff,
- bytes_read);
- if (bytes_written < bytes_read) {
+ if (offset > progress) {
+ int64_t sparse = offset - progress;
+ size_t ns;
+
+ if (null_buff == NULL) {
+ null_buff = bsdtar->buff;
+ memset(null_buff, 0, bsdtar->buff_size);
+ }
+
+ while (sparse > 0) {
+ if (sparse > (int64_t)bsdtar->buff_size)
+ ns = bsdtar->buff_size;
+ else
+ ns = (size_t)sparse;
+ bytes_written =
+ archive_write_data(a, null_buff, ns);
+ if (bytes_written < 0) {
+ /* Write failed; this is bad */
+ lafe_warnc(0, "%s",
+ archive_error_string(a));
+ return (-1);
+ }
+ if ((size_t)bytes_written < ns) {
+ /* Write was truncated; warn but
+ * continue. */
+ lafe_warnc(0,
+ "%s: Truncated write; file may "
+ "have grown while being archived.",
+ archive_entry_pathname(entry));
+ return (0);
+ }
+ progress += bytes_written;
+ sparse -= bytes_written;
+ }
+ }
+
+ bytes_written = archive_write_data(a, buff, bytes_read);
+ if (bytes_written < 0) {
+ /* Write failed; this is bad */
lafe_warnc(0, "%s", archive_error_string(a));
return (-1);
}
+ if ((size_t)bytes_written < bytes_read) {
+ /* Write was truncated; warn but continue. */
+ lafe_warnc(0,
+ "%s: Truncated write; file may have grown "
+ "while being archived.",
+ archive_entry_pathname(entry));
+ return (0);
+ }
progress += bytes_written;
- bytes_read = archive_read_data(ina, bsdtar->buff, bsdtar->buff_size);
}
-
+ if (r < ARCHIVE_WARN) {
+ lafe_warnc(archive_errno(a), "%s", archive_error_string(a));
+ return (-1);
+ }
return (0);
}
+static void
+excluded_callback(struct archive *a, void *_data, struct archive_entry *entry)
+{
+ struct bsdtar *bsdtar = (struct bsdtar *)_data;
+
+ if (bsdtar->option_no_subdirs)
+ return;
+ if (!archive_read_disk_can_descend(a))
+ return;
+ if (bsdtar->option_interactive &&
+ !yes("add '%s'", archive_entry_pathname(entry)))
+ return;
+ archive_read_disk_descend(a);
+}
+
+static int
+metadata_filter(struct archive *a, void *_data, struct archive_entry *entry)
+{
+ struct bsdtar *bsdtar = (struct bsdtar *)_data;
+
+ /* XXX TODO: check whether this filesystem is
+ * synthetic and/or local. Add a new
+ * --local-only option to skip non-local
+ * filesystems. Skip synthetic filesystems
+ * regardless.
+ *
+ * The results should be cached, since
+ * tree.c doesn't usually visit a directory
+ * and the directory contents together. A simple
+ * move-to-front list should perform quite well.
+ *
+ * Use archive_read_disk_current_filesystem_is_remote().
+ */
+
+ /*
+ * If the user vetoes this file/directory, skip it.
+ * We want this to be fairly late; if some other
+ * check would veto this file, we shouldn't bother
+ * the user with it.
+ */
+ if (bsdtar->option_interactive &&
+ !yes("add '%s'", archive_entry_pathname(entry)))
+ return (0);
+
+ /* Note: if user vetoes, we won't descend. */
+ if (!bsdtar->option_no_subdirs && archive_read_disk_can_descend(a))
+ archive_read_disk_descend(a);
+
+ return (1);
+}
+
/*
* Add the file or dir hierarchy named by 'path' to the archive
*/
static void
write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
{
+ struct archive *disk = bsdtar->diskreader;
struct archive_entry *entry = NULL, *spare_entry = NULL;
- struct tree *tree;
- char symlink_mode = bsdtar->symlink_mode;
- dev_t first_dev = 0;
- int dev_recorded = 0;
- int tree_ret;
-
- tree = tree_open(path);
+ int r;
- if (!tree) {
- lafe_warnc(errno, "%s: Cannot open", path);
+ r = archive_read_disk_open(disk, path);
+ if (r != ARCHIVE_OK) {
+ lafe_warnc(archive_errno(disk),
+ "%s", archive_error_string(disk));
bsdtar->return_value = 1;
return;
}
+ bsdtar->first_fs = -1;
- while ((tree_ret = tree_next(tree)) != 0) {
- int r;
- const char *name = tree_current_path(tree);
- const struct stat *st = NULL; /* info to use for this entry */
- const struct stat *lst = NULL; /* lstat() information */
- int descend;
-
- if (tree_ret == TREE_ERROR_FATAL)
- lafe_errc(1, tree_errno(tree),
- "%s: Unable to continue traversing directory tree",
- name);
- if (tree_ret == TREE_ERROR_DIR) {
- lafe_warnc(errno,
- "%s: Couldn't visit directory", name);
- bsdtar->return_value = 1;
- }
- if (tree_ret != TREE_REGULAR)
- continue;
-
- /*
- * If this file/dir is excluded by a filename
- * pattern, skip it.
- */
- if (lafe_excluded(bsdtar->matching, name))
- continue;
-
- /*
- * Get lstat() info from the tree library.
- */
- lst = tree_current_lstat(tree);
- if (lst == NULL) {
- /* Couldn't lstat(); must not exist. */
- lafe_warnc(errno, "%s: Cannot stat", name);
- /* Return error if files disappear during traverse. */
- bsdtar->return_value = 1;
- continue;
- }
-
- /*
- * Distinguish 'L'/'P'/'H' symlink following.
- */
- switch(symlink_mode) {
- case 'H':
- /* 'H': After the first item, rest like 'P'. */
- symlink_mode = 'P';
- /* 'H': First item (from command line) like 'L'. */
- /* FALLTHROUGH */
- case 'L':
- /* 'L': Do descend through a symlink to dir. */
- descend = tree_current_is_dir(tree);
- /* 'L': Follow symlinks to files. */
- archive_read_disk_set_symlink_logical(bsdtar->diskreader);
- /* 'L': Archive symlinks as targets, if we can. */
- st = tree_current_stat(tree);
- if (st != NULL)
- break;
- /* If stat fails, we have a broken symlink;
- * in that case, don't follow the link. */
- /* FALLTHROUGH */
- default:
- /* 'P': Don't descend through a symlink to dir. */
- descend = tree_current_is_physical_dir(tree);
- /* 'P': Don't follow symlinks to files. */
- archive_read_disk_set_symlink_physical(bsdtar->diskreader);
- /* 'P': Archive symlinks as symlinks. */
- st = lst;
+ for (;;) {
+ archive_entry_free(entry);
+ entry = archive_entry_new();
+ r = archive_read_next_header2(disk, entry);
+ if (r == ARCHIVE_EOF)
break;
- }
-
- if (bsdtar->option_no_subdirs)
- descend = 0;
-
- /*
- * Are we about to cross to a new filesystem?
- */
- if (!dev_recorded) {
- /* This is the initial file system. */
- first_dev = lst->st_dev;
- dev_recorded = 1;
- } else if (lst->st_dev == first_dev) {
- /* The starting file system is always acceptable. */
- } else if (descend == 0) {
- /* We're not descending, so no need to check. */
- } else if (bsdtar->option_dont_traverse_mounts) {
- descend = 0;
- } else {
- /* We're prepared to cross a mount point. */
-
- /* XXX TODO: check whether this filesystem is
- * synthetic and/or local. Add a new
- * --local-only option to skip non-local
- * filesystems. Skip synthetic filesystems
- * regardless.
- *
- * The results should be cached, since
- * tree.c doesn't usually visit a directory
- * and the directory contents together. A simple
- * move-to-front list should perform quite well.
- *
- * This is going to be heavily OS dependent:
- * FreeBSD's statfs() in conjunction with getvfsbyname()
- * provides all of this; NetBSD's statvfs() does
- * most of it; other systems will vary.
- */
- }
-
- /*
- * In -u mode, check that the file is newer than what's
- * already in the archive; in all modes, obey --newerXXX flags.
- */
- if (!new_enough(bsdtar, name, st)) {
- if (!descend)
- continue;
- if (bsdtar->option_interactive &&
- !yes("add '%s'", name))
+ else if (r != ARCHIVE_OK) {
+ lafe_warnc(archive_errno(disk),
+ "%s", archive_error_string(disk));
+ if (r == ARCHIVE_FATAL) {
+ bsdtar->return_value = 1;
+ return;
+ } else if (r < ARCHIVE_WARN)
continue;
- tree_descend(tree);
- continue;
}
- archive_entry_free(entry);
- entry = archive_entry_new();
-
- archive_entry_set_pathname(entry, name);
- archive_entry_copy_sourcepath(entry,
- tree_current_access_path(tree));
-
- /* Populate the archive_entry with metadata from the disk. */
- /* XXX TODO: Arrange to open a regular file before
- * calling this so we can pass in an fd and shorten
- * the race to query metadata. The linkify dance
- * makes this more complex than it might sound. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
- /* TODO: tree.c uses stat(), which is badly broken
- * on Windows. To fix this, we should
- * deprecate tree_current_stat() and provide a new
- * call tree_populate_entry(t, entry). This call
- * would use stat() internally on POSIX and
- * GetInfoByFileHandle() internally on Windows.
- * This would be another step towards a tree-walker
- * that can be integrated deep into libarchive.
- * For now, just set st to NULL on Windows;
- * archive_read_disk_entry_from_file() should
- * be smart enough to use platform-appropriate
- * ways to probe file information.
- */
- st = NULL;
-#endif
- r = archive_read_disk_entry_from_file(bsdtar->diskreader,
- entry, -1, st);
if (bsdtar->uid >= 0) {
archive_entry_set_uid(entry, bsdtar->uid);
if (!bsdtar->uname)
@@ -840,68 +853,6 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
archive_entry_set_uname(entry, bsdtar->uname);
if (bsdtar->gname)
archive_entry_set_gname(entry, bsdtar->gname);
- if (r != ARCHIVE_OK)
- lafe_warnc(archive_errno(bsdtar->diskreader),
- "%s", archive_error_string(bsdtar->diskreader));
- if (r < ARCHIVE_WARN)
- continue;
-
- /* XXX TODO: Just use flag data from entry; avoid the
- * duplicate check here. */
-
- /*
- * If this file/dir is flagged "nodump" and we're
- * honoring such flags, skip this file/dir.
- */
-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
- /* BSD systems store flags in struct stat */
- if (bsdtar->option_honor_nodump &&
- (lst->st_flags & UF_NODUMP))
- continue;
-#endif
-
-#if defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
- /* Linux uses ioctl to read flags. */
- if (bsdtar->option_honor_nodump) {
- int fd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY);
- if (fd >= 0) {
- unsigned long fflags;
- int r = ioctl(fd, EXT2_IOC_GETFLAGS, &fflags);
- close(fd);
- if (r >= 0 && (fflags & EXT2_NODUMP_FL))
- continue;
- }
- }
-#endif
-
-#ifdef __APPLE__
- if (bsdtar->enable_copyfile) {
- /* If we're using copyfile(), ignore "._XXX" files. */
- const char *bname = strrchr(name, '/');
- if (bname == NULL)
- bname = name;
- else
- ++bname;
- if (bname[0] == '.' && bname[1] == '_')
- continue;
- } else {
- /* If not, drop the copyfile() data. */
- archive_entry_copy_mac_metadata(entry, NULL, 0);
- }
-#endif
-
- /*
- * If the user vetoes this file/directory, skip it.
- * We want this to be fairly late; if some other
- * check would veto this file, we shouldn't bother
- * the user with it.
- */
- if (bsdtar->option_interactive &&
- !yes("add '%s'", name))
- continue;
-
- if (descend)
- tree_descend(tree);
/*
* Rewrite the pathname to be archived. If rewrite
@@ -933,7 +884,7 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path)
fprintf(stderr, "\n");
}
archive_entry_free(entry);
- tree_close(tree);
+ archive_read_close(disk);
}
/*
@@ -954,29 +905,7 @@ static void
write_entry(struct bsdtar *bsdtar, struct archive *a,
struct archive_entry *entry)
{
- int fd = -1;
int e;
- size_t align = 4096;
-
- if (archive_entry_size(entry) > 0) {
- const char *pathname = archive_entry_sourcepath(entry);
- /* TODO: Use O_DIRECT here and set 'align' to the
- * actual filesystem block size. As of July 2010, new
- * directory-traversal code is going in that will make
- * it much easier to track filesystem properties like
- * this during the traversal. */
- fd = open(pathname, O_RDONLY | O_BINARY);
- align = 4096;
- if (fd == -1) {
- bsdtar->return_value = 1;
- if (!bsdtar->verbose)
- lafe_warnc(errno,
- "%s: could not open file", pathname);
- else
- fprintf(stderr, ": %s", strerror(errno));
- return;
- }
- }
e = archive_write_header(a, entry);
if (e != ARCHIVE_OK) {
@@ -997,17 +926,10 @@ write_entry(struct bsdtar *bsdtar, struct archive *a,
* to inform us that the archive body won't get stored. In
* that case, just skip the write.
*/
- if (e >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0) {
- if (write_file_data(bsdtar, a, entry, fd, align))
+ if (e >= ARCHIVE_WARN && archive_entry_size(entry) > 0) {
+ if (copy_file_data_block(bsdtar, a, bsdtar->diskreader, entry))
exit(1);
}
-
- /*
- * If we opened a file, close it now even if there was an error
- * which made us decide not to write the archive body.
- */
- if (fd >= 0)
- close(fd);
}
static void
@@ -1038,144 +960,6 @@ report_write(struct bsdtar *bsdtar, struct archive *a,
tar_i64toa(archive_entry_size(entry)));
}
-
-/* Helper function to copy file to archive. */
-static int
-write_file_data(struct bsdtar *bsdtar, struct archive *a,
- struct archive_entry *entry, int fd, size_t align)
-{
- ssize_t bytes_read;
- ssize_t bytes_written;
- int64_t progress = 0;
- size_t buff_size;
- char *buff = bsdtar->buff;
-
- /* Round 'buff' up to the next multiple of 'align' and reduce
- * 'buff_size' accordingly. */
- buff = (char *)((((uintptr_t)buff + align - 1) / align) * align);
- buff_size = bsdtar->buff + bsdtar->buff_size - buff;
- buff_size = (buff_size / align) * align;
-
- bytes_read = read(fd, buff, buff_size);
- while (bytes_read > 0) {
- if (need_report())
- report_write(bsdtar, a, entry, progress);
-
- bytes_written = archive_write_data(a, buff, bytes_read);
- if (bytes_written < 0) {
- /* Write failed; this is bad */
- lafe_warnc(0, "%s", archive_error_string(a));
- return (-1);
- }
- if (bytes_written < bytes_read) {
- /* Write was truncated; warn but continue. */
- lafe_warnc(0,
- "%s: Truncated write; file may have grown while being archived.",
- archive_entry_pathname(entry));
- return (0);
- }
- progress += bytes_written;
- bytes_read = read(fd, buff, buff_size);
- }
- if (bytes_read < 0) {
- lafe_warnc(errno,
- "%s: Read error",
- archive_entry_pathname(entry));
- bsdtar->return_value = 1;
- }
- return 0;
-}
-
-/*
- * Test if the specified file is new enough to include in the archive.
- */
-static int
-new_enough(struct bsdtar *bsdtar, const char *path, const struct stat *st)
-{
- struct archive_dir_entry *p;
-
- /*
- * If this file/dir is excluded by a time comparison, skip it.
- */
- if (bsdtar->newer_ctime_filter) {
- if (st->st_ctime < bsdtar->newer_ctime_sec)
- return (0); /* Too old, skip it. */
- if (st->st_ctime == bsdtar->newer_ctime_sec
- && ARCHIVE_STAT_CTIME_NANOS(st)
- <= bsdtar->newer_ctime_nsec)
- return (0); /* Too old, skip it. */
- }
- if (bsdtar->newer_mtime_filter) {
- if (st->st_mtime < bsdtar->newer_mtime_sec)
- return (0); /* Too old, skip it. */
- if (st->st_mtime == bsdtar->newer_mtime_sec
- && ARCHIVE_STAT_MTIME_NANOS(st)
- <= bsdtar->newer_mtime_nsec)
- return (0); /* Too old, skip it. */
- }
-
- /*
- * In -u mode, we only write an entry if it's newer than
- * what was already in the archive.
- */
- if (bsdtar->archive_dir != NULL &&
- bsdtar->archive_dir->head != NULL) {
- for (p = bsdtar->archive_dir->head; p != NULL; p = p->next) {
- if (pathcmp(path, p->name)==0)
- return (p->mtime_sec < st->st_mtime ||
- (p->mtime_sec == st->st_mtime &&
- p->mtime_nsec
- < ARCHIVE_STAT_MTIME_NANOS(st)));
- }
- }
-
- /* If the file wasn't rejected, include it. */
- return (1);
-}
-
-/*
- * Add an entry to the dir list for 'u' mode.
- *
- * XXX TODO: Make this fast.
- */
-static void
-add_dir_list(struct bsdtar *bsdtar, const char *path,
- time_t mtime_sec, int mtime_nsec)
-{
- struct archive_dir_entry *p;
-
- /*
- * Search entire list to see if this file has appeared before.
- * If it has, override the timestamp data.
- */
- p = bsdtar->archive_dir->head;
- while (p != NULL) {
- if (strcmp(path, p->name)==0) {
- p->mtime_sec = mtime_sec;
- p->mtime_nsec = mtime_nsec;
- return;
- }
- p = p->next;
- }
-
- p = malloc(sizeof(*p));
- if (p == NULL)
- lafe_errc(1, ENOMEM, "Can't read archive directory");
-
- p->name = strdup(path);
- if (p->name == NULL)
- lafe_errc(1, ENOMEM, "Can't read archive directory");
- p->mtime_sec = mtime_sec;
- p->mtime_nsec = mtime_nsec;
- p->next = NULL;
- if (bsdtar->archive_dir->tail == NULL) {
- bsdtar->archive_dir->head = bsdtar->archive_dir->tail = p;
- } else {
- bsdtar->archive_dir->tail->next = p;
- bsdtar->archive_dir->tail = p;
- }
-}
-
static void
test_for_append(struct bsdtar *bsdtar)
{
OpenPOWER on IntegriCloud