diff options
author | mm <mm@FreeBSD.org> | 2012-07-28 06:38:44 +0000 |
---|---|---|
committer | mm <mm@FreeBSD.org> | 2012-07-28 06:38:44 +0000 |
commit | 11bb7fcf7b175da111e710d49b6e1c30153b625b (patch) | |
tree | 1ed0c7ff98605ecfbedcfa8d00cd1a29e2dfebe6 /contrib/libarchive/tar | |
parent | f694295168072660e04cabb712367c5a73b59885 (diff) | |
parent | e7b24010c4d2190a1465594620e629e469c522f8 (diff) | |
download | FreeBSD-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.1 | 2 | ||||
-rw-r--r-- | contrib/libarchive/tar/bsdtar.c | 85 | ||||
-rw-r--r-- | contrib/libarchive/tar/bsdtar.h | 15 | ||||
-rw-r--r-- | contrib/libarchive/tar/getdate.c | 1037 | ||||
-rw-r--r-- | contrib/libarchive/tar/read.c | 80 | ||||
-rw-r--r-- | contrib/libarchive/tar/test/main.c | 321 | ||||
-rw-r--r-- | contrib/libarchive/tar/test/test.h | 12 | ||||
-rw-r--r-- | contrib/libarchive/tar/test/test_format_newc.c | 64 | ||||
-rw-r--r-- | contrib/libarchive/tar/test/test_getdate.c | 80 | ||||
-rw-r--r-- | contrib/libarchive/tar/test/test_option_nodump.c | 68 | ||||
-rw-r--r-- | contrib/libarchive/tar/tree.c | 848 | ||||
-rw-r--r-- | contrib/libarchive/tar/tree.h | 141 | ||||
-rw-r--r-- | contrib/libarchive/tar/write.c | 650 |
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) { |