1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-17 15:27:36 +00:00

Update libarchive to 3.0.3

Some of new features:
  - New readers: RAR, LHA/LZH, CAB reader, 7-Zip
  - New writers: ISO9660, XAR
  - Improvements to many formats, especially including ISO9660 and Zip
  - Stackable write filters to write, e.g., tar.gz.uu in a single pass
  - Exploit seekable input; new "seekable" Zip reader can exploit the Zip
    Central Directory when it's available; the old "streamable" Zip reader
    is still fully supported for cases where seeking is not possible.

Full release notes available at:
	https://github.com/libarchive/libarchive/wiki/ReleaseNotes
This commit is contained in:
Martin Matuska 2012-02-25 10:58:02 +00:00
commit 6c95142e79
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=232153
470 changed files with 125683 additions and 13638 deletions

View File

@ -38,6 +38,24 @@
# xargs -n1 | sort | uniq -d; # xargs -n1 | sort | uniq -d;
# done # done
# 20120225: libarchive 3.0.3
OLD_FILES+=man/man3/archive_read_data_into_buffer.3.gz \
man/man3/archive_read_support_compression_all.3.gz \
man/man3/archive_read_support_compression_bzip2.3.gz \
man/man3/archive_read_support_compression_compress.3.gz \
man/man3/archive_read_support_compression_gzip.3.gz \
man/man3/archive_read_support_compression_lzma.3.gz \
man/man3/archive_read_support_compression_none.3.gz \
man/man3/archive_read_support_compression_program.3.gz \
man/man3/archive_read_support_compression_program_signature.3.gz \
man/man3/archive_read_support_compression_xz.3.gz \
man/man3/archive_write_set_callbacks.3.gz \
man/man3/archive_write_set_compression_bzip2.3.gz \
man/man3/archive_write_set_compression_compress.3.gz \
man/man3/archive_write_set_compression_gzip.3.gz \
man/man3/archive_write_set_compression_none.3.gz \
man/man3/archive_write_set_compression_program.3.gz
OLD_LIBS+=usr/lib/libarchive.so.5
# 20120113: removal of wtmpcvt(1) # 20120113: removal of wtmpcvt(1)
OLD_FILES+=usr/bin/wtmpcvt OLD_FILES+=usr/bin/wtmpcvt
OLD_FILES+=usr/share/man/man1/wtmpcvt.1.gz OLD_FILES+=usr/share/man/man1/wtmpcvt.1.gz

View File

@ -16,8 +16,8 @@ the actual statements in the files are controlling.
a 3-clause UC Regents copyright; please read the individual source a 3-clause UC Regents copyright; please read the individual source
files for details: files for details:
libarchive/archive_entry.c libarchive/archive_entry.c
libarchive/archive_read_support_compression_compress.c libarchive/archive_read_support_filter_compress.c
libarchive/archive_write_set_compression_compress.c libarchive/archive_write_set_filter_compress.c
libarchive/mtree.5 libarchive/mtree.5
tar/matching.c tar/matching.c

View File

@ -15,8 +15,10 @@ doc
examples examples
libarchive/CMakeLists.txt libarchive/CMakeLists.txt
libarchive/archive_entry_copy_bhfi.c libarchive/archive_entry_copy_bhfi.c
libarchive/archive_read_disk_windows.c
libarchive/archive_windows.c libarchive/archive_windows.c
libarchive/archive_windows.h libarchive/archive_windows.h
libarchive/archive_write_disk_windows.c
libarchive/config_freebsd.h libarchive/config_freebsd.h
libarchive/filter_fork_windows.c libarchive/filter_fork_windows.c
libarchive/mtree.5 libarchive/mtree.5

View File

@ -1,27 +1,80 @@
Feb 05, 2011: Fix issue 134: Improve handling of open failures Jan 10, 2012: Issue 223: Skip atime tests if atime not supported
Dec 06, 2010: Fix issue 119: Relax ISO verification Jan 09, 2012: Issue 222: Errors saving sparse files to pax archives
Dec 06, 2010: Fix issue 121: mtree parsing Jan 09, 2012: Issue 221: allow archive_*_free(NULL)
Dec 05, 2010: Fix extraction of GNU tar 'D' directory entries Dec 31, 2011: Issue 212: configure script on Solaris
Dec 05, 2010: Be less demanding in LZMA/XZ compression tests Dec 30, 2011: Issue 218: empty contents extracting Zip files with bsdcpio
Jun 30, 2010: libarchive 2.8.4 released Dec 30, 2011: Issue 217: fix compile warning
Jun 30, 2010: Improved reliability of hash function detection Dec 30, 2011: Issue 216: truncated filenames in listings
Jun 30, 2010: Fix issues on ancient FreeBSD, QNX, ancient NetBSD and Minix Dec 28, 2011: Issue 210: memory leak on Windows
Dec 28, 2011: Issue 206: fix hardlink tests on Windows 2000
Dec 27, 2011: Issue 208: Don't hang when using external compression
program on Windows
Mar 14, 2010: libarchive 2.8.3 released Dec 24, 2011: libarchive 3.0.2 released
Mar 14, 2010: Symlink dereference fix for Linux broke the build there; corrected. Dec 23, 2011: Various fixes merged from FreeBSD
Dec 23, 2011: Symlink support in Zip reader and writer
Dec 23, 2011: Robustness fixes to 7Zip reader
Mar 14, 2010: libarchive 2.8.2 released Nov 27, 2011: libarchive 3.0.1b released
Mar 12, 2010: Fix NULL deference for short self-extracting zip archives.
Nov 26, 2011: 7Zip reader
Nov 26, 2011: Small fixes to ISO and Zip to improve robustness with corrupted input
Nov 24, 2011: Improve streaming Zip reader's support for uncompressed entries
Nov 20, 2011: New seeking Zip reader supports SFX Zip archives
Nov 20, 2011: Build fixes on Windows
Nov 13, 2011: libarchive 3.0.0a released
Nov 06, 2011: Update shared-library version calculations for libarchive 3.x
Sep 04, 2011: Fix tar -s; follow GNU tar for controlling hardlink/symlink substitutions
Aug 18, 2011: Fix reading ISO images built by NetBSD's mkisofs
Aug 15, 2011: Old archive_read_support_compression_XXX functions are deprecated and
will disappear in libarchive 4.0.
Jun 26, 2011: RAR reader
Jun 16, 2011: Add tar:compat-2x option to emulate broken libarchive 2.x
handling of pax UTF-8 headers
Apr 25, 2011: Refactor read_open() into a collection of single-item setters;
support the old interfaces as wrappers
Apr 12, 2011: Split disk writer into separate POSIX and Windows implementations
Apr 10, 2011: Improvements to character translations on Windows.
Mar 30, 2011: More work to return errors instead of calling abort()
Mar 23, 2011: Add charset option to many writers to control MBCS filenames
Mar 17, 2011: Overhauled support for per-format extension options
Mar 17, 2011: Track character set used for mbcs strings, support
translating to/from user-specified locale
Mar 09, 2011: Recognize mtree files without requiring a signature
Mar 06, 2011: Use iconv to convert to/from Unicode instead of making bad
assumptions about the C90 character set translation functions
Feb 17, 2011: Fixes for AIX, TRU64, and other platforms
Dec 22, 2010: CAB reader
Dec 20, 2010: LHA/LZH reader
Jul 03, 2010: minitar example demonstrates archive_read_disk directory traversal
Jun 29, 2010: Many improvements to ISO reader compatibility
Jun 26, 2010: Use larger buffers when copy files into an archive
Jun 18, 2010: Reimplement Mac OS extensions in libarchive
Jun 09, 2010: archive_read_disk now supports traversals
May 28, 2010: XAR writer
May 16, 2010: Fix ^T handling; don't exit on interrupted reads and writes
May 09, 2010: Improved detection of platform-specific crypto support
May 04, 2010: lzip read and write filters
May 01, 2010: New options: tar --gid --gname --uid --uname
Apr 28, 2010: Use Red-black tree for ISO reader/writer to improve performance
Apr 17, 2010: Minimal writer for legacy GNU tar format
Mar 12, 2010: Don't dereference symlinks on Linux when reading ACLs. Mar 12, 2010: Don't dereference symlinks on Linux when reading ACLs.
Mar 07, 2010: Better detection of SHA2 support for old OpenSSL versions.
Mar 07, 2010: Fix parsing of input files for bsdtar -T.
Mar 07, 2010: Do not leak setup_xattr into the global namespace.
Mar 06, 2010: libarchive 2.8.1 released
Mar 06, 2010: Fix build when an older libarchive is already installed Mar 06, 2010: Fix build when an older libarchive is already installed
Mar 03, 2010: Use O_BINARY opening files in bsdtar Feb 28, 2010: Relax handling of state failures; misuse by clients now generally
Mar 02, 2010: Include missing archive_crc32.h results in a sticky ARCHIVE_FATAL rather than a visit to abort()
Mar 01, 2010: Correctly include iconv.h required by libxml2. Feb 25, 2010: ISO writer
Feb 21, 2010: Split many man pages into smaller chunks.
Feb 21, 2010: Performance: Cheat on block sizes when reading archives from disk.
Feb 21, 2010: Use int64_t instead of off_t, dev_t, ino_t, uid_t, and gid_t
Feb 20, 2010: Document new ACL functions.
Feb 19, 2010: Support multiple write filters
Feb 07, 2010: Remove some legacy libarchive 1.x APIs
Feb 04, 2010: Read afio headers
Feb 02, 2010: Archive sparse files compatibly with GNU tar
Feb 01, 2010: Integrate Apple extensions for Mac OS extended attributes into bsdtar
Jan 31, 2010: Support cpio -V
Feb 04, 2010: libarchive 2.8.0 released Feb 04, 2010: libarchive 2.8.0 released
Jan 17, 2010: Fix error handling for 'echo nonexistent | cpio -o' Jan 17, 2010: Fix error handling for 'echo nonexistent | cpio -o'

View File

@ -13,8 +13,6 @@ This distribution bundle includes the following components:
essentially the same functionality essentially the same functionality
* examples: Some small example programs that you may find useful. * examples: Some small example programs that you may find useful.
* examples/minitar: a compact sample demonstrating use of libarchive. * examples/minitar: a compact sample demonstrating use of libarchive.
I use this for testing link pollution; it should produce a very
small executable file on most systems.
* contrib: Various items sent to me by third parties; * contrib: Various items sent to me by third parties;
please contact the authors with any questions. please contact the authors with any questions.
@ -51,16 +49,11 @@ The manual pages above are provided in the 'doc' directory in
a number of different formats. a number of different formats.
You should also read the copious comments in "archive.h" and the You should also read the copious comments in "archive.h" and the
source code for the sample programs for more details. Please let me source code for the sample programs for more details. Please let us
know about any errors or omissions you find. know about any errors or omissions you find.
Currently, the library automatically detects and reads the following: Currently, the library automatically detects and reads the following fomats:
* gzip compression * GNU tar format (including GNU long filenames, long link names, and sparse files)
* bzip2 compression
* compress/LZW compression
* lzma and xz compression
* GNU tar format (including GNU long filenames, long link names, and
sparse files)
* Solaris 9 extended tar format (including ACLs) * Solaris 9 extended tar format (including ACLs)
* Old V7 tar archives * Old V7 tar archives
* POSIX ustar * POSIX ustar
@ -73,22 +66,40 @@ Currently, the library automatically detects and reads the following:
* ZIP archives (with uncompressed or "deflate" compressed entries) * ZIP archives (with uncompressed or "deflate" compressed entries)
* GNU and BSD 'ar' archives * GNU and BSD 'ar' archives
* 'mtree' format * 'mtree' format
* Microsoft CAB format
* LHA and LZH archives
* RAR archives
* XAR archives
The library can write: The library also detects and handles any of the following before evaluating the archive:
* uuencoded files
* files with RPM wrapper
* gzip compression * gzip compression
* bzip2 compression * bzip2 compression
* compress/LZW compression * compress/LZW compression
* lzma and xz compression * lzma, lzip, and xz compression
The library can create archives in any of the following formats:
* POSIX ustar * POSIX ustar
* POSIX pax interchange format * POSIX pax interchange format
* "restricted" pax format, which will create ustar archives except for * "restricted" pax format, which will create ustar archives except for
entries that require pax extensions (for long filenames, ACLs, etc). entries that require pax extensions (for long filenames, ACLs, etc).
* Old GNU tar format
* POSIX octet-oriented cpio * POSIX octet-oriented cpio
* SVR4 "newc" cpio * SVR4 "newc" cpio
* shar archives * shar archives
* ZIP archives (with uncompressed or "deflate" compressed entries) * ZIP archives (with uncompressed or "deflate" compressed entries)
* GNU and BSD 'ar' archives * GNU and BSD 'ar' archives
* 'mtree' format * 'mtree' format
* ISO9660 format
* XAR archives
When creating archives, the result can be filtered with any of the following:
* uuencode
* gzip compression
* bzip2 compression
* compress/LZW compression
* lzma, lzip, and xz compression
Notes about the library architecture: Notes about the library architecture:

View File

@ -24,8 +24,8 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd September 5, 2010 .Dd December 21, 2007
.Dt BSDCPIO 1 .Dt CPIO 1
.Os .Os
.Sh NAME .Sh NAME
.Nm cpio .Nm cpio
@ -59,7 +59,7 @@ is a mode indicator from the following list:
.Bl -tag -compact -width indent .Bl -tag -compact -width indent
.It Fl i .It Fl i
Input. Input.
Read an archive from standard input (unless overriden) and extract the Read an archive from standard input (unless overridden) and extract the
contents to disk or (if the contents to disk or (if the
.Fl t .Fl t
option is specified) option is specified)
@ -69,7 +69,7 @@ one of the patterns will be extracted.
.It Fl o .It Fl o
Output. Output.
Read a list of filenames from standard input and produce a new archive Read a list of filenames from standard input and produce a new archive
on standard output (unless overriden) containing the specified items. on standard output (unless overridden) containing the specified items.
.It Fl p .It Fl p
Pass-through. Pass-through.
Read a list of filenames from standard input and copy the files to the Read a list of filenames from standard input and copy the files to the
@ -80,7 +80,7 @@ specified directory.
Unless specifically stated otherwise, options are applicable in Unless specifically stated otherwise, options are applicable in
all operating modes. all operating modes.
.Bl -tag -width indent .Bl -tag -width indent
.It Fl 0 .It Fl 0 , Fl Fl null
Read filenames separated by NUL characters instead of newlines. Read filenames separated by NUL characters instead of newlines.
This is necessary if any of the filenames being read might contain newlines. This is necessary if any of the filenames being read might contain newlines.
.It Fl A .It Fl A
@ -102,8 +102,8 @@ bytes.
(o mode only) (o mode only)
Use the old POSIX portable character format. Use the old POSIX portable character format.
Equivalent to Equivalent to
.Fl -format Ar odc . .Fl Fl format Ar odc .
.It Fl d .It Fl d , Fl Fl make-directories
(i and p modes) (i and p modes)
Create directories as necessary. Create directories as necessary.
.It Fl E Ar file .It Fl E Ar file
@ -111,14 +111,14 @@ Create directories as necessary.
Read list of file name patterns from Read list of file name patterns from
.Ar file .Ar file
to list and extract. to list and extract.
.It Fl F Ar file .It Fl F Ar file , Fl Fl file Ar file
Read archive from or write archive to Read archive from or write archive to
.Ar file . .Ar file .
.It Fl f Ar pattern .It Fl f Ar pattern
(i mode only) (i mode only)
Ignore files that match Ignore files that match
.Ar pattern . .Ar pattern .
.It Fl -format Ar format .It Fl H Ar format , Fl Fl format Ar format
(o mode only) (o mode only)
Produce the output archive in the specified format. Produce the output archive in the specified format.
Supported formats include: Supported formats include:
@ -145,24 +145,21 @@ for more complete information about the
formats currently supported by the underlying formats currently supported by the underlying
.Xr libarchive 3 .Xr libarchive 3
library. library.
.It Fl H Ar format .It Fl h , Fl Fl help
Synonym for
.Fl -format .
.It Fl h , Fl -help
Print usage information. Print usage information.
.It Fl I Ar file .It Fl I Ar file
Read archive from Read archive from
.Ar file . .Ar file .
.It Fl i .It Fl i , Fl Fl extract
Input mode. Input mode.
See above for description. See above for description.
.It Fl -insecure .It Fl Fl insecure
(i and p mode only) (i and p mode only)
Disable security checks during extraction or copying. Disable security checks during extraction or copying.
This allows extraction via symbolic links and path names containing This allows extraction via symbolic links and path names containing
.Sq .. .Sq ..
in the name. in the name.
.It Fl J .It Fl J , Fl Fl xz
(o mode only) (o mode only)
Compress the file with xz-compatible compression before writing it. Compress the file with xz-compatible compression before writing it.
In input mode, this option is ignored; xz compression is recognized In input mode, this option is ignored; xz compression is recognized
@ -175,20 +172,20 @@ Synonym for
All symbolic links will be followed. All symbolic links will be followed.
Normally, symbolic links are archived and copied as symbolic links. Normally, symbolic links are archived and copied as symbolic links.
With this option, the target of the link will be archived or copied instead. With this option, the target of the link will be archived or copied instead.
.It Fl l .It Fl l , Fl Fl link
(p mode only) (p mode only)
Create links from the target directory to the original files, Create links from the target directory to the original files,
instead of copying. instead of copying.
.It Fl lzma .It Fl Fl lzma
(o mode only) (o mode only)
Compress the file with lzma-compatible compression before writing it. Compress the file with lzma-compatible compression before writing it.
In input mode, this option is ignored; lzma compression is recognized In input mode, this option is ignored; lzma compression is recognized
automatically on input. automatically on input.
.It Fl m .It Fl m , Fl Fl preserve-modification-time
(i and p modes) (i and p modes)
Set file modification time on created files to match Set file modification time on created files to match
those in the source. those in the source.
.It Fl n .It Fl n , Fl Fl numeric-uid-gid
(i mode, only with (i mode, only with
.Fl t ) .Fl t )
Display numeric uid and gid. Display numeric uid and gid.
@ -197,26 +194,26 @@ By default,
displays the user and group names when they are provided in the displays the user and group names when they are provided in the
archive, or looks up the user and group names in the system archive, or looks up the user and group names in the system
password database. password database.
.It Fl no-preserve-owner .It Fl Fl no-preserve-owner
(i mode only) (i mode only)
Do not attempt to restore file ownership. Do not attempt to restore file ownership.
This is the default when run by non-root users. This is the default when run by non-root users.
.It Fl O Ar file .It Fl O Ar file
Write archive to Write archive to
.Ar file . .Ar file .
.It Fl o .It Fl o , Fl Fl create
Output mode. Output mode.
See above for description. See above for description.
.It Fl p .It Fl p , Fl Fl pass-through
Pass-through mode. Pass-through mode.
See above for description. See above for description.
.It Fl preserve-owner .It Fl Fl preserve-owner
(i mode only) (i mode only)
Restore file ownership. Restore file ownership.
This is the default when run by the root user. This is the default when run by the root user.
.It Fl -quiet .It Fl Fl quiet
Suppress unnecessary messages. Suppress unnecessary messages.
.It Fl R Oo user Oc Ns Oo : Oc Ns Oo group Oc .It Fl R Oo user Oc Ns Oo : Oc Ns Oo group Oc , Fl Fl owner Oo user Oc Ns Oo : Oc Ns Oo group Oc
Set the owner and/or group on files in the output. Set the owner and/or group on files in the output.
If group is specified with no user If group is specified with no user
(for example, (for example,
@ -244,20 +241,24 @@ containing the name of the file and a line is read from
If the line read is blank, the file is skipped. If the line read is blank, the file is skipped.
If the line contains a single period, the file is processed normally. If the line contains a single period, the file is processed normally.
Otherwise, the line is taken to be the new name of the file. Otherwise, the line is taken to be the new name of the file.
.It Fl t .It Fl t , Fl Fl list
(i mode only) (i mode only)
List the contents of the archive to stdout; List the contents of the archive to stdout;
do not restore the contents to disk. do not restore the contents to disk.
.It Fl u .It Fl u , Fl Fl unconditional
(i and p modes) (i and p modes)
Unconditionally overwrite existing files. Unconditionally overwrite existing files.
Ordinarily, an older file will not overwrite a newer file on disk. Ordinarily, an older file will not overwrite a newer file on disk.
.It Fl v .It Fl V , Fl Fl dot
Print a dot to stderr for each file as it is processed.
Superseded by
.Fl v .
.It Fl v , Fl Fl verbose
Print the name of each file to stderr as it is processed. Print the name of each file to stderr as it is processed.
With With
.Fl t , .Fl t ,
provide a detailed listing of each file. provide a detailed listing of each file.
.It Fl -version .It Fl Fl version
Print the program version information and exit. Print the program version information and exit.
.It Fl y .It Fl y
(o mode only) (o mode only)
@ -275,6 +276,8 @@ Compress the archive with gzip-compatible compression before writing it.
In input mode, this option is ignored; In input mode, this option is ignored;
gzip compression is recognized automatically on input. gzip compression is recognized automatically on input.
.El .El
.Sh EXIT STATUS
.Ex -std
.Sh ENVIRONMENT .Sh ENVIRONMENT
The following environment variables affect the execution of The following environment variables affect the execution of
.Nm : .Nm :
@ -290,8 +293,6 @@ See
.Xr environ 7 .Xr environ 7
for more information. for more information.
.El .El
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES .Sh EXAMPLES
The The
.Nm .Nm

View File

@ -51,7 +51,7 @@ __FBSDID("$FreeBSD$");
/* /*
* Short options for cpio. Please keep this sorted. * Short options for cpio. Please keep this sorted.
*/ */
static const char *short_options = "0AaBC:cdE:F:f:H:hI:iJjLlmnO:opR:rtuvW:yZz"; static const char *short_options = "0AaBC:cdE:F:f:H:hI:iJjLlmnO:opR:rtuVvW:yZz";
/* /*
* Long options for cpio. Please keep this sorted. * Long options for cpio. Please keep this sorted.
@ -62,6 +62,7 @@ static const struct option {
int equivalent; /* Equivalent short option. */ int equivalent; /* Equivalent short option. */
} cpio_longopts[] = { } cpio_longopts[] = {
{ "create", 0, 'o' }, { "create", 0, 'o' },
{ "dot", 0, 'V' },
{ "extract", 0, 'i' }, { "extract", 0, 'i' },
{ "file", 1, 'F' }, { "file", 1, 'F' },
{ "format", 1, 'H' }, { "format", 1, 'H' },
@ -109,7 +110,7 @@ cpio_getopt(struct cpio *cpio)
int opt = '?'; int opt = '?';
int required = 0; int required = 0;
cpio->optarg = NULL; cpio->argument = NULL;
/* First time through, initialize everything. */ /* First time through, initialize everything. */
if (state == state_start) { if (state == state_start) {
@ -188,7 +189,7 @@ cpio_getopt(struct cpio *cpio)
long_prefix = "-W "; /* For clearer errors. */ long_prefix = "-W "; /* For clearer errors. */
} else { } else {
state = state_next_word; state = state_next_word;
cpio->optarg = opt_word; cpio->argument = opt_word;
} }
} }
} }
@ -202,7 +203,7 @@ cpio_getopt(struct cpio *cpio)
p = strchr(opt_word, '='); p = strchr(opt_word, '=');
if (p != NULL) { if (p != NULL) {
optlength = (size_t)(p - opt_word); optlength = (size_t)(p - opt_word);
cpio->optarg = (char *)(uintptr_t)(p + 1); cpio->argument = (char *)(uintptr_t)(p + 1);
} else { } else {
optlength = strlen(opt_word); optlength = strlen(opt_word);
} }
@ -241,9 +242,9 @@ cpio_getopt(struct cpio *cpio)
/* We've found a unique match; does it need an argument? */ /* We've found a unique match; does it need an argument? */
if (match->required) { if (match->required) {
/* Argument required: get next word if necessary. */ /* Argument required: get next word if necessary. */
if (cpio->optarg == NULL) { if (cpio->argument == NULL) {
cpio->optarg = *cpio->argv; cpio->argument = *cpio->argv;
if (cpio->optarg == NULL) { if (cpio->argument == NULL) {
lafe_warnc(0, lafe_warnc(0,
"Option %s%s requires an argument", "Option %s%s requires an argument",
long_prefix, match->name); long_prefix, match->name);
@ -254,7 +255,7 @@ cpio_getopt(struct cpio *cpio)
} }
} else { } else {
/* Argument forbidden: fail if there is one. */ /* Argument forbidden: fail if there is one. */
if (cpio->optarg != NULL) { if (cpio->argument != NULL) {
lafe_warnc(0, lafe_warnc(0,
"Option %s%s does not allow an argument", "Option %s%s does not allow an argument",
long_prefix, match->name); long_prefix, match->name);
@ -340,7 +341,7 @@ owner_parse(const char *spec, int *uid, int *gid)
} else { } else {
char *end; char *end;
errno = 0; errno = 0;
*uid = strtoul(user, &end, 10); *uid = (int)strtoul(user, &end, 10);
if (errno || *end != '\0') { if (errno || *end != '\0') {
snprintf(errbuff, sizeof(errbuff), snprintf(errbuff, sizeof(errbuff),
"Couldn't lookup user ``%s''", user); "Couldn't lookup user ``%s''", user);
@ -358,7 +359,7 @@ owner_parse(const char *spec, int *uid, int *gid)
} else { } else {
char *end; char *end;
errno = 0; errno = 0;
*gid = strtoul(g, &end, 10); *gid = (int)strtoul(g, &end, 10);
if (errno || *end != '\0') { if (errno || *end != '\0') {
snprintf(errbuff, sizeof(errbuff), snprintf(errbuff, sizeof(errbuff),
"Couldn't lookup group ``%s''", g); "Couldn't lookup group ``%s''", g);

View File

@ -50,9 +50,15 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_GRP_H #ifdef HAVE_GRP_H
#include <grp.h> #include <grp.h>
#endif #endif
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#ifdef HAVE_PWD_H #ifdef HAVE_PWD_H
#include <pwd.h> #include <pwd.h>
#endif #endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_STDARG_H #ifdef HAVE_STDARG_H
#include <stdarg.h> #include <stdarg.h>
#endif #endif
@ -69,9 +75,6 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_TIME_H #ifdef HAVE_TIME_H
#include <time.h> #include <time.h>
#endif #endif
@ -116,6 +119,7 @@ static void mode_in(struct cpio *);
static void mode_list(struct cpio *); static void mode_list(struct cpio *);
static void mode_out(struct cpio *); static void mode_out(struct cpio *);
static void mode_pass(struct cpio *, const char *); static void mode_pass(struct cpio *, const char *);
static const char *remove_leading_slash(const char *);
static int restore_time(struct cpio *, struct archive_entry *, static int restore_time(struct cpio *, struct archive_entry *,
const char *, int fd); const char *, int fd);
static void usage(void); static void usage(void);
@ -136,20 +140,34 @@ main(int argc, char *argv[])
cpio->buff = buff; cpio->buff = buff;
cpio->buff_size = sizeof(buff); cpio->buff_size = sizeof(buff);
#if defined(HAVE_SIGACTION) && defined(SIGPIPE)
{ /* Ignore SIGPIPE signals. */
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
}
#endif
/* Need lafe_progname before calling lafe_warnc. */ /* Need lafe_progname before calling lafe_warnc. */
if (*argv == NULL) if (*argv == NULL)
lafe_progname = "bsdcpio"; lafe_progname = "bsdcpio";
else { else {
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
lafe_progname = strrchr(*argv, '\\'); lafe_progname = strrchr(*argv, '\\');
#else if (strrchr(*argv, '/') > lafe_progname)
lafe_progname = strrchr(*argv, '/');
#endif #endif
lafe_progname = strrchr(*argv, '/');
if (lafe_progname != NULL) if (lafe_progname != NULL)
lafe_progname++; lafe_progname++;
else else
lafe_progname = *argv; lafe_progname = *argv;
} }
#if HAVE_SETLOCALE
if (setlocale(LC_ALL, "") == NULL)
lafe_warnc(0, "Failed to set default locale");
#endif
cpio->uid_override = -1; cpio->uid_override = -1;
cpio->gid_override = -1; cpio->gid_override = -1;
@ -187,9 +205,9 @@ main(int argc, char *argv[])
cpio->bytes_per_block = 5120; cpio->bytes_per_block = 5120;
break; break;
case 'C': /* NetBSD/OpenBSD */ case 'C': /* NetBSD/OpenBSD */
cpio->bytes_per_block = atoi(cpio->optarg); cpio->bytes_per_block = atoi(cpio->argument);
if (cpio->bytes_per_block <= 0) if (cpio->bytes_per_block <= 0)
lafe_errc(1, 0, "Invalid blocksize %s", cpio->optarg); lafe_errc(1, 0, "Invalid blocksize %s", cpio->argument);
break; break;
case 'c': /* POSIX 1997 */ case 'c': /* POSIX 1997 */
cpio->format = "odc"; cpio->format = "odc";
@ -199,22 +217,22 @@ main(int argc, char *argv[])
break; break;
case 'E': /* NetBSD/OpenBSD */ case 'E': /* NetBSD/OpenBSD */
lafe_include_from_file(&cpio->matching, lafe_include_from_file(&cpio->matching,
cpio->optarg, cpio->option_null); cpio->argument, cpio->option_null);
break; break;
case 'F': /* NetBSD/OpenBSD/GNU cpio */ case 'F': /* NetBSD/OpenBSD/GNU cpio */
cpio->filename = cpio->optarg; cpio->filename = cpio->argument;
break; break;
case 'f': /* POSIX 1997 */ case 'f': /* POSIX 1997 */
lafe_exclude(&cpio->matching, cpio->optarg); lafe_exclude(&cpio->matching, cpio->argument);
break; break;
case 'H': /* GNU cpio (also --format) */ case 'H': /* GNU cpio (also --format) */
cpio->format = cpio->optarg; cpio->format = cpio->argument;
break; break;
case 'h': case 'h':
long_help(); long_help();
break; break;
case 'I': /* NetBSD/OpenBSD */ case 'I': /* NetBSD/OpenBSD */
cpio->filename = cpio->optarg; cpio->filename = cpio->argument;
break; break;
case 'i': /* POSIX 1997 */ case 'i': /* POSIX 1997 */
if (cpio->mode != '\0') if (cpio->mode != '\0')
@ -251,7 +269,7 @@ main(int argc, char *argv[])
cpio->extract_flags &= ~ARCHIVE_EXTRACT_OWNER; cpio->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
break; break;
case 'O': /* GNU cpio */ case 'O': /* GNU cpio */
cpio->filename = cpio->optarg; cpio->filename = cpio->argument;
break; break;
case 'o': /* POSIX 1997 */ case 'o': /* POSIX 1997 */
if (cpio->mode != '\0') if (cpio->mode != '\0')
@ -275,7 +293,7 @@ main(int argc, char *argv[])
case 'R': /* GNU cpio, also --owner */ case 'R': /* GNU cpio, also --owner */
/* TODO: owner_parse should return uname/gname /* TODO: owner_parse should return uname/gname
* also; use that to set [ug]name_override. */ * also; use that to set [ug]name_override. */
errmsg = owner_parse(cpio->optarg, &uid, &gid); errmsg = owner_parse(cpio->argument, &uid, &gid);
if (errmsg) { if (errmsg) {
lafe_warnc(-1, "%s", errmsg); lafe_warnc(-1, "%s", errmsg);
usage(); usage();
@ -302,6 +320,9 @@ main(int argc, char *argv[])
case 'v': /* POSIX 1997 */ case 'v': /* POSIX 1997 */
cpio->verbose++; cpio->verbose++;
break; break;
case 'V': /* GNU cpio */
cpio->dot++;
break;
case OPTION_VERSION: /* GNU convention */ case OPTION_VERSION: /* GNU convention */
version(); version();
break; break;
@ -345,6 +366,12 @@ main(int argc, char *argv[])
/* -l requires -p */ /* -l requires -p */
if (cpio->option_link && cpio->mode != 'p') if (cpio->option_link && cpio->mode != 'p')
lafe_errc(1, 0, "Option -l requires -p"); lafe_errc(1, 0, "Option -l requires -p");
/* -v overrides -V */
if (cpio->dot && cpio->verbose)
cpio->dot = 0;
/* -v overrides -V */
if (cpio->dot && cpio->verbose)
cpio->dot = 0;
/* TODO: Flag other nonsensical combinations. */ /* TODO: Flag other nonsensical combinations. */
switch (cpio->mode) { switch (cpio->mode) {
@ -402,7 +429,7 @@ static const char *long_help_msg =
"First option must be a mode specifier:\n" "First option must be a mode specifier:\n"
" -i Input -o Output -p Pass\n" " -i Input -o Output -p Pass\n"
"Common Options:\n" "Common Options:\n"
" -v Verbose\n" " -v Verbose filenames -V one dot per file\n"
"Create: %p -o [options] < [list of files] > [archive]\n" "Create: %p -o [options] < [list of files] > [archive]\n"
" -J,-y,-z,--lzma Compress archive with xz/bzip2/gzip/lzma\n" " -J,-y,-z,--lzma Compress archive with xz/bzip2/gzip/lzma\n"
" --format {odc|newc|ustar} Select archive format\n" " --format {odc|newc|ustar} Select archive format\n"
@ -451,7 +478,7 @@ version(void)
{ {
fprintf(stdout,"bsdcpio %s -- %s\n", fprintf(stdout,"bsdcpio %s -- %s\n",
BSDCPIO_VERSION_STRING, BSDCPIO_VERSION_STRING,
archive_version()); archive_version_string());
exit(0); exit(0);
} }
@ -533,6 +560,8 @@ mode_out(struct cpio *cpio)
} }
r = archive_write_close(cpio->archive); r = archive_write_close(cpio->archive);
if (cpio->dot)
fprintf(stderr, "\n");
if (r != ARCHIVE_OK) if (r != ARCHIVE_OK)
lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); lafe_errc(1, 0, "%s", archive_error_string(cpio->archive));
@ -543,7 +572,50 @@ mode_out(struct cpio *cpio)
fprintf(stderr, "%lu %s\n", (unsigned long)blocks, fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
blocks == 1 ? "block" : "blocks"); blocks == 1 ? "block" : "blocks");
} }
archive_write_finish(cpio->archive); archive_write_free(cpio->archive);
}
static const char *
remove_leading_slash(const char *p)
{
const char *rp;
/* Remove leading "//./" or "//?/" or "//?/UNC/"
* (absolute path prefixes used by Windows API) */
if ((p[0] == '/' || p[0] == '\\') &&
(p[1] == '/' || p[1] == '\\') &&
(p[2] == '.' || p[2] == '?') &&
(p[3] == '/' || p[3] == '\\'))
{
if (p[2] == '?' &&
(p[4] == 'U' || p[4] == 'u') &&
(p[5] == 'N' || p[5] == 'n') &&
(p[6] == 'C' || p[6] == 'c') &&
(p[7] == '/' || p[7] == '\\'))
p += 8;
else
p += 4;
}
do {
rp = p;
/* Remove leading drive letter from archives created
* on Windows. */
if (((p[0] >= 'a' && p[0] <= 'z') ||
(p[0] >= 'A' && p[0] <= 'Z')) &&
p[1] == ':') {
p += 2;
}
/* Remove leading "/../", "//", etc. */
while (p[0] == '/' || p[0] == '\\') {
if (p[1] == '.' && p[2] == '.' &&
(p[3] == '/' || p[3] == '\\')) {
p += 3; /* Remove "/..", leave "/"
* for next pass. */
} else
p += 1; /* Remove "/". */
}
} while (rp != p);
return (p);
} }
/* /*
@ -557,7 +629,6 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
const char *destpath; const char *destpath;
struct archive_entry *entry, *spare; struct archive_entry *entry, *spare;
size_t len; size_t len;
const char *p;
int r; int r;
/* /*
@ -611,10 +682,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
"Can't allocate path buffer"); "Can't allocate path buffer");
} }
strcpy(cpio->pass_destpath, cpio->destdir); strcpy(cpio->pass_destpath, cpio->destdir);
p = srcpath; strcat(cpio->pass_destpath, remove_leading_slash(srcpath));
while (p[0] == '/')
++p;
strcat(cpio->pass_destpath, p);
destpath = cpio->pass_destpath; destpath = cpio->pass_destpath;
} }
if (cpio->option_rename) if (cpio->option_rename)
@ -656,6 +724,8 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
/* Print out the destination name to the user. */ /* Print out the destination name to the user. */
if (cpio->verbose) if (cpio->verbose)
fprintf(stderr,"%s", destpath); fprintf(stderr,"%s", destpath);
if (cpio->dot)
fprintf(stderr, ".");
/* /*
* Option_link only makes sense in pass mode and for * Option_link only makes sense in pass mode and for
@ -725,7 +795,7 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
if (r == ARCHIVE_FATAL) if (r == ARCHIVE_FATAL)
exit(1); exit(1);
if (r >= ARCHIVE_WARN && fd >= 0) { if (r >= ARCHIVE_WARN && archive_entry_size(entry) > 0 && fd >= 0) {
bytes_read = read(fd, cpio->buff, cpio->buff_size); bytes_read = read(fd, cpio->buff, cpio->buff_size);
while (bytes_read > 0) { while (bytes_read > 0) {
r = archive_write_data(cpio->archive, r = archive_write_data(cpio->archive,
@ -825,7 +895,7 @@ mode_in(struct cpio *cpio)
a = archive_read_new(); a = archive_read_new();
if (a == NULL) if (a == NULL)
lafe_errc(1, 0, "Couldn't allocate archive object"); lafe_errc(1, 0, "Couldn't allocate archive object");
archive_read_support_compression_all(a); archive_read_support_filter_all(a);
archive_read_support_format_all(a); archive_read_support_format_all(a);
if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block)) if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
@ -849,7 +919,9 @@ mode_in(struct cpio *cpio)
if (destpath == NULL) if (destpath == NULL)
continue; continue;
if (cpio->verbose) if (cpio->verbose)
fprintf(stdout, "%s\n", destpath); fprintf(stderr, "%s\n", destpath);
if (cpio->dot)
fprintf(stderr, ".");
if (cpio->uid_override >= 0) if (cpio->uid_override >= 0)
archive_entry_set_uid(entry, cpio->uid_override); archive_entry_set_uid(entry, cpio->uid_override);
if (cpio->gid_override >= 0) if (cpio->gid_override >= 0)
@ -859,13 +931,16 @@ mode_in(struct cpio *cpio)
fprintf(stderr, "%s: %s\n", fprintf(stderr, "%s: %s\n",
archive_entry_pathname(entry), archive_entry_pathname(entry),
archive_error_string(ext)); archive_error_string(ext));
} else if (archive_entry_size(entry) > 0) { } else if (!archive_entry_size_is_set(entry)
|| archive_entry_size(entry) > 0) {
r = extract_data(a, ext); r = extract_data(a, ext);
if (r != ARCHIVE_OK) if (r != ARCHIVE_OK)
cpio->return_value = 1; cpio->return_value = 1;
} }
} }
r = archive_read_close(a); r = archive_read_close(a);
if (cpio->dot)
fprintf(stderr, "\n");
if (r != ARCHIVE_OK) if (r != ARCHIVE_OK)
lafe_errc(1, 0, "%s", archive_error_string(a)); lafe_errc(1, 0, "%s", archive_error_string(a));
r = archive_write_close(ext); r = archive_write_close(ext);
@ -877,8 +952,8 @@ mode_in(struct cpio *cpio)
fprintf(stderr, "%lu %s\n", (unsigned long)blocks, fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
blocks == 1 ? "block" : "blocks"); blocks == 1 ? "block" : "blocks");
} }
archive_read_finish(a); archive_read_free(a);
archive_write_finish(ext); archive_write_free(ext);
exit(cpio->return_value); exit(cpio->return_value);
} }
@ -892,7 +967,7 @@ extract_data(struct archive *ar, struct archive *aw)
int r; int r;
size_t size; size_t size;
const void *block; const void *block;
off_t offset; int64_t offset;
for (;;) { for (;;) {
r = archive_read_data_block(ar, &block, &size, &offset); r = archive_read_data_block(ar, &block, &size, &offset);
@ -922,7 +997,7 @@ mode_list(struct cpio *cpio)
a = archive_read_new(); a = archive_read_new();
if (a == NULL) if (a == NULL)
lafe_errc(1, 0, "Couldn't allocate archive object"); lafe_errc(1, 0, "Couldn't allocate archive object");
archive_read_support_compression_all(a); archive_read_support_filter_all(a);
archive_read_support_format_all(a); archive_read_support_format_all(a);
if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block)) if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
@ -952,7 +1027,7 @@ mode_list(struct cpio *cpio)
fprintf(stderr, "%lu %s\n", (unsigned long)blocks, fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
blocks == 1 ? "block" : "blocks"); blocks == 1 ? "block" : "blocks");
} }
archive_read_finish(a); archive_read_free(a);
exit(0); exit(0);
} }
@ -989,11 +1064,11 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
/* Use uname if it's present, else lookup name from uid. */ /* Use uname if it's present, else lookup name from uid. */
uname = archive_entry_uname(entry); uname = archive_entry_uname(entry);
if (uname == NULL) if (uname == NULL)
uname = lookup_uname(cpio, archive_entry_uid(entry)); uname = lookup_uname(cpio, (uid_t)archive_entry_uid(entry));
/* Use gname if it's present, else lookup name from gid. */ /* Use gname if it's present, else lookup name from gid. */
gname = archive_entry_gname(entry); gname = archive_entry_gname(entry);
if (gname == NULL) if (gname == NULL)
gname = lookup_gname(cpio, archive_entry_gid(entry)); gname = lookup_gname(cpio, (uid_t)archive_entry_gid(entry));
} }
/* Print device number or file size. */ /* Print device number or file size. */
@ -1075,6 +1150,8 @@ mode_pass(struct cpio *cpio, const char *destdir)
archive_entry_linkresolver_free(cpio->linkresolver); archive_entry_linkresolver_free(cpio->linkresolver);
r = archive_write_close(cpio->archive); r = archive_write_close(cpio->archive);
if (cpio->dot)
fprintf(stderr, "\n");
if (r != ARCHIVE_OK) if (r != ARCHIVE_OK)
lafe_errc(1, 0, "%s", archive_error_string(cpio->archive)); lafe_errc(1, 0, "%s", archive_error_string(cpio->archive));
@ -1086,7 +1163,7 @@ mode_pass(struct cpio *cpio, const char *destdir)
blocks == 1 ? "block" : "blocks"); blocks == 1 ? "block" : "blocks");
} }
archive_write_finish(cpio->archive); archive_write_free(cpio->archive);
} }
/* /*
@ -1102,12 +1179,24 @@ cpio_rename(const char *name)
static char buff[1024]; static char buff[1024];
FILE *t; FILE *t;
char *p, *ret; char *p, *ret;
#if defined(_WIN32) && !defined(__CYGWIN__)
FILE *to;
t = fopen("CONIN$", "r");
if (t == NULL)
return (name);
to = fopen("CONOUT$", "w");
if (to == NULL)
return (name);
fprintf(to, "%s (Enter/./(new name))? ", name);
fclose(to);
#else
t = fopen("/dev/tty", "r+"); t = fopen("/dev/tty", "r+");
if (t == NULL) if (t == NULL)
return (name); return (name);
fprintf(t, "%s (Enter/./(new name))? ", name); fprintf(t, "%s (Enter/./(new name))? ", name);
fflush(t); fflush(t);
#endif
p = fgets(buff, sizeof(buff), t); p = fgets(buff, sizeof(buff), t);
fclose(t); fclose(t);
@ -1260,8 +1349,9 @@ lookup_gname_helper(struct cpio *cpio, const char **name, id_t id)
const char * const char *
cpio_i64toa(int64_t n0) cpio_i64toa(int64_t n0)
{ {
// 2^64 =~ 1.8 * 10^19, so 20 decimal digits suffice. /* 2^64 =~ 1.8 * 10^19, so 20 decimal digits suffice.
// We also need 1 byte for '-' and 1 for '\0'. * We also need 1 byte for '-' and 1 for '\0'.
*/
static char buff[22]; static char buff[22];
int64_t n = n0 < 0 ? -n0 : n0; int64_t n = n0 < 0 ? -n0 : n0;
char *p = buff + sizeof(buff); char *p = buff + sizeof(buff);

View File

@ -43,18 +43,18 @@
*/ */
struct cpio { struct cpio {
/* Option parsing */ /* Option parsing */
const char *optarg; const char *argument;
/* Options */ /* Options */
const char *filename; const char *filename;
char mode; /* -i -o -p */ int mode; /* -i -o -p */
char compress; /* -j, -y, or -z */ int compress; /* -j, -y, or -z */
const char *format; /* -H format */ const char *format; /* -H format */
int bytes_per_block; /* -b block_size */ int bytes_per_block; /* -b block_size */
int verbose; /* -v */ int verbose; /* -v */
int dot; /* -V */
int quiet; /* --quiet */ int quiet; /* --quiet */
int extract_flags; /* Flags for extract operation */ int extract_flags; /* Flags for extract operation */
char symlink_mode; /* H or L, per BSD conventions */
const char *compress_program; const char *compress_program;
int option_append; /* -A, only relevant for -o */ int option_append; /* -A, only relevant for -o */
int option_atime_restore; /* -a */ int option_atime_restore; /* -a */

File diff suppressed because it is too large Load Diff

View File

@ -48,9 +48,6 @@
#include <sys/types.h> /* Windows requires this before sys/stat.h */ #include <sys/types.h> /* Windows requires this before sys/stat.h */
#include <sys/stat.h> #include <sys/stat.h>
#ifdef USE_DMALLOC
#include <dmalloc.h>
#endif
#if HAVE_DIRENT_H #if HAVE_DIRENT_H
#include <dirent.h> #include <dirent.h>
#endif #endif
@ -63,6 +60,9 @@
#ifdef HAVE_IO_H #ifdef HAVE_IO_H
#include <io.h> #include <io.h>
#endif #endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -83,13 +83,9 @@
/* Windows (including Visual Studio and MinGW but not Cygwin) */ /* Windows (including Visual Studio and MinGW but not Cygwin) */
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
#include "../cpio_windows.h"
#if !defined(__BORLANDC__) #if !defined(__BORLANDC__)
#define strdup _strdup #define strdup _strdup
#endif #endif
#define LOCALE_DE "deu"
#else
#define LOCALE_DE "de_DE.UTF-8"
#endif #endif
/* Visual Studio */ /* Visual Studio */
@ -97,13 +93,11 @@
#define snprintf sprintf_s #define snprintf sprintf_s
#endif #endif
/* Cygwin */ #if defined(__BORLANDC__)
#if defined(__CYGWIN__) #pragma warn -8068 /* Constant out of range in comparison. */
/* Cygwin-1.7.x is lazy about populating nlinks, so don't
* expect it to be accurate. */
# define NLINKS_INACCURATE_FOR_DIRS
#endif #endif
/* Haiku OS and QNX */
#if defined(__HAIKU__) || defined(__QNXNTO__) #if defined(__HAIKU__) || defined(__QNXNTO__)
/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */ /* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */
#include <stdint.h> #include <stdint.h>
@ -139,24 +133,24 @@
assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
/* Assert two strings are the same. Reports value of each one if not. */ /* Assert two strings are the same. Reports value of each one if not. */
#define assertEqualString(v1,v2) \ #define assertEqualString(v1,v2) \
assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0)
#define assertEqualUTF8String(v1,v2) \
assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1)
/* As above, but v1 and v2 are wchar_t * */ /* As above, but v1 and v2 are wchar_t * */
#define assertEqualWString(v1,v2) \ #define assertEqualWString(v1,v2) \
assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL) assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
/* As above, but raw blocks of bytes. */ /* As above, but raw blocks of bytes. */
#define assertEqualMem(v1, v2, l) \ #define assertEqualMem(v1, v2, l) \
assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL) assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
/* Assert two files are the same; allow printf-style expansion of second name. /* Assert two files are the same. */
* See below for comments about variable arguments here... #define assertEqualFile(f1, f2) \
*/ assertion_equal_file(__FILE__, __LINE__, (f1), (f2))
#define assertEqualFile \ /* Assert that a file is empty. */
assertion_setup(__FILE__, __LINE__);assertion_equal_file #define assertEmptyFile(pathname) \
/* Assert that a file is empty; supports printf-style arguments. */ assertion_empty_file(__FILE__, __LINE__, (pathname))
#define assertEmptyFile \ /* Assert that a file is not empty. */
assertion_setup(__FILE__, __LINE__);assertion_empty_file #define assertNonEmptyFile(pathname) \
/* Assert that a file is not empty; supports printf-style arguments. */ assertion_non_empty_file(__FILE__, __LINE__, (pathname))
#define assertNonEmptyFile \
assertion_setup(__FILE__, __LINE__);assertion_non_empty_file
#define assertFileAtime(pathname, sec, nsec) \ #define assertFileAtime(pathname, sec, nsec) \
assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec) assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec)
#define assertFileAtimeRecent(pathname) \ #define assertFileAtimeRecent(pathname) \
@ -166,14 +160,14 @@
#define assertFileBirthtimeRecent(pathname) \ #define assertFileBirthtimeRecent(pathname) \
assertion_file_birthtime_recent(__FILE__, __LINE__, pathname) assertion_file_birthtime_recent(__FILE__, __LINE__, pathname)
/* Assert that a file exists; supports printf-style arguments. */ /* Assert that a file exists; supports printf-style arguments. */
#define assertFileExists \ #define assertFileExists(pathname) \
assertion_setup(__FILE__, __LINE__);assertion_file_exists assertion_file_exists(__FILE__, __LINE__, pathname)
/* Assert that a file exists; supports printf-style arguments. */ /* Assert that a file exists. */
#define assertFileNotExists \ #define assertFileNotExists(pathname) \
assertion_setup(__FILE__, __LINE__);assertion_file_not_exists assertion_file_not_exists(__FILE__, __LINE__, pathname)
/* Assert that file contents match a string; supports printf-style arguments. */ /* Assert that file contents match a string. */
#define assertFileContents \ #define assertFileContents(data, data_size, pathname) \
assertion_setup(__FILE__, __LINE__);assertion_file_contents assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname)
#define assertFileMtime(pathname, sec, nsec) \ #define assertFileMtime(pathname, sec, nsec) \
assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec) assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
#define assertFileMtimeRecent(pathname) \ #define assertFileMtimeRecent(pathname) \
@ -182,8 +176,10 @@
assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks) assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
#define assertFileSize(pathname, size) \ #define assertFileSize(pathname, size) \
assertion_file_size(__FILE__, __LINE__, pathname, size) assertion_file_size(__FILE__, __LINE__, pathname, size)
#define assertTextFileContents \ #define assertTextFileContents(text, pathname) \
assertion_setup(__FILE__, __LINE__);assertion_text_file_contents assertion_text_file_contents(__FILE__, __LINE__, text, pathname)
#define assertFileContainsLinesAnyOrder(pathname, lines) \
assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines)
#define assertIsDir(pathname, mode) \ #define assertIsDir(pathname, mode) \
assertion_is_dir(__FILE__, __LINE__, pathname, mode) assertion_is_dir(__FILE__, __LINE__, pathname, mode)
#define assertIsHardlink(path1, path2) \ #define assertIsHardlink(path1, path2) \
@ -205,6 +201,8 @@
assertion_make_symlink(__FILE__, __LINE__, newfile, linkto) assertion_make_symlink(__FILE__, __LINE__, newfile, linkto)
#define assertUmask(mask) \ #define assertUmask(mask) \
assertion_umask(__FILE__, __LINE__, mask) assertion_umask(__FILE__, __LINE__, mask)
#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec) \
assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec)
/* /*
* This would be simple with C99 variadic macros, but I don't want to * This would be simple with C99 variadic macros, but I don't want to
@ -213,28 +211,29 @@
* but effective. * but effective.
*/ */
#define skipping \ #define skipping \
assertion_setup(__FILE__, __LINE__);test_skipping skipping_setup(__FILE__, __LINE__);test_skipping
/* Function declarations. These are defined in test_utility.c. */ /* Function declarations. These are defined in test_utility.c. */
void failure(const char *fmt, ...); void failure(const char *fmt, ...);
int assertion_assert(const char *, int, int, const char *, void *); int assertion_assert(const char *, int, int, const char *, void *);
int assertion_chdir(const char *, int, const char *); int assertion_chdir(const char *, int, const char *);
int assertion_empty_file(const char *, ...); int assertion_empty_file(const char *, int, const char *);
int assertion_equal_file(const char *, const char *, ...); int assertion_equal_file(const char *, int, const char *, const char *);
int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *); int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *);
int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *); int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *);
int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *); int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int);
int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *); int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
int assertion_file_atime(const char *, int, const char *, long, long); int assertion_file_atime(const char *, int, const char *, long, long);
int assertion_file_atime_recent(const char *, int, const char *); int assertion_file_atime_recent(const char *, int, const char *);
int assertion_file_birthtime(const char *, int, const char *, long, long); int assertion_file_birthtime(const char *, int, const char *, long, long);
int assertion_file_birthtime_recent(const char *, int, const char *); int assertion_file_birthtime_recent(const char *, int, const char *);
int assertion_file_contents(const void *, int, const char *, ...); int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **);
int assertion_file_exists(const char *, ...); int assertion_file_contents(const char *, int, const void *, int, const char *);
int assertion_file_exists(const char *, int, const char *);
int assertion_file_mtime(const char *, int, const char *, long, long); int assertion_file_mtime(const char *, int, const char *, long, long);
int assertion_file_mtime_recent(const char *, int, const char *); int assertion_file_mtime_recent(const char *, int, const char *);
int assertion_file_nlinks(const char *, int, const char *, int); int assertion_file_nlinks(const char *, int, const char *, int);
int assertion_file_not_exists(const char *, ...); int assertion_file_not_exists(const char *, int, const char *);
int assertion_file_size(const char *, int, const char *, long); int assertion_file_size(const char *, int, const char *, long);
int assertion_is_dir(const char *, int, const char *, int); int assertion_is_dir(const char *, int, const char *, int);
int assertion_is_hardlink(const char *, int, const char *, const char *); int assertion_is_hardlink(const char *, int, const char *, const char *);
@ -245,11 +244,12 @@ 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, const char *);
int assertion_make_hardlink(const char *, int, const char *newpath, const char *); 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_make_symlink(const char *, int, const char *newpath, const char *);
int assertion_non_empty_file(const char *, ...); int assertion_non_empty_file(const char *, int, const char *);
int assertion_text_file_contents(const char *buff, const char *f); int assertion_text_file_contents(const char *, int, const char *buff, const char *f);
int assertion_umask(const char *, int, int); int assertion_umask(const char *, int, int);
void assertion_setup(const char *, int); int assertion_utimes(const char *, int, const char *, long, long, long, long );
void skipping_setup(const char *, int);
void test_skipping(const char *fmt, ...); void test_skipping(const char *fmt, ...);
/* Like sprintf, then system() */ /* Like sprintf, then system() */
@ -267,6 +267,9 @@ int canGzip(void);
/* Return true if this platform can run the "gunzip" program. */ /* Return true if this platform can run the "gunzip" program. */
int canGunzip(void); int canGunzip(void);
/* Return true if the file has large i-node number(>0xffffffff). */
int is_LargeInode(const char *);
/* Suck file into string allocated via malloc(). Call free() when done. */ /* Suck file into string allocated via malloc(). Call free() when done. */
/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */ /* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
char *slurpfile(size_t *, const char *fmt, ...); char *slurpfile(size_t *, const char *fmt, ...);
@ -274,6 +277,9 @@ char *slurpfile(size_t *, const char *fmt, ...);
/* Extracts named reference file to the current directory. */ /* Extracts named reference file to the current directory. */
void extract_reference_file(const char *); void extract_reference_file(const char *);
/* Path to working directory for current test */
const char *testworkdir;
/* /*
* Special interfaces for program test harness. * Special interfaces for program test harness.
*/ */
@ -283,3 +289,7 @@ const char *testprogfile;
/* Name of exe to use in printf-formatted command strings. */ /* Name of exe to use in printf-formatted command strings. */
/* On Windows, this includes leading/trailing quotes. */ /* On Windows, this includes leading/trailing quotes. */
const char *testprog; const char *testprog;
#ifdef USE_DMALLOC
#include <dmalloc.h>
#endif

View File

@ -40,15 +40,23 @@ DEFINE_TEST(test_0)
struct stat st; struct stat st;
failure("File %s does not exist?!", testprogfile); failure("File %s does not exist?!", testprogfile);
if (!assertEqualInt(0, stat(testprogfile, &st))) if (!assertEqualInt(0, stat(testprogfile, &st))) {
fprintf(stderr,
"\nFile %s does not exist; aborting test.\n\n",
testprog);
exit(1); exit(1);
}
failure("%s is not executable?!", testprogfile); failure("%s is not executable?!", testprogfile);
if (!assert((st.st_mode & 0111) != 0)) if (!assert((st.st_mode & 0111) != 0)) {
fprintf(stderr,
"\nFile %s not executable; aborting test.\n\n",
testprog);
exit(1); exit(1);
}
/* /*
* Try to succesfully run the program; this requires that * Try to successfully run the program; this requires that
* we know some option that will succeed. * we know some option that will succeed.
*/ */
if (0 == systemf("%s --version >" DEV_NULL, testprog)) { if (0 == systemf("%s --version >" DEV_NULL, testprog)) {

View File

@ -33,12 +33,15 @@ verify_files(const char *msg)
*/ */
/* Regular file with 2 links. */ /* Regular file with 2 links. */
failure(msg);
assertIsReg("file", 0644); assertIsReg("file", 0644);
failure(msg); failure(msg);
assertFileSize("file", 10); assertFileSize("file", 10);
failure(msg);
assertFileNLinks("file", 2); assertFileNLinks("file", 2);
/* Another name for the same file. */ /* Another name for the same file. */
failure(msg);
assertIsHardlink("linkfile", "file"); assertIsHardlink("linkfile", "file");
/* Symlink */ /* Symlink */
@ -46,8 +49,11 @@ verify_files(const char *msg)
assertIsSymlink("symlink", "file"); assertIsSymlink("symlink", "file");
/* Another file with 1 link and different permissions. */ /* Another file with 1 link and different permissions. */
failure(msg);
assertIsReg("file2", 0777); assertIsReg("file2", 0777);
failure(msg);
assertFileSize("file2", 10); assertFileSize("file2", 10);
failure(msg);
assertFileNLinks("file2", 1); assertFileNLinks("file2", 1);
/* dir */ /* dir */
@ -58,7 +64,7 @@ static void
basic_cpio(const char *target, basic_cpio(const char *target,
const char *pack_options, const char *pack_options,
const char *unpack_options, const char *unpack_options,
const char *se) const char *se, const char *se2)
{ {
int r; int r;
@ -87,7 +93,7 @@ basic_cpio(const char *target,
/* Verify stderr. */ /* Verify stderr. */
failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target); failure("Error invoking %s -i %s in dir %s", testprog, unpack_options, target);
assertTextFileContents(se, "unpack.err"); assertTextFileContents(se2, "unpack.err");
verify_files(pack_options); verify_files(pack_options);
@ -125,6 +131,7 @@ DEFINE_TEST(test_basic)
{ {
FILE *filelist; FILE *filelist;
const char *msg; const char *msg;
char result[1024];
assertUmask(0); assertUmask(0);
@ -132,28 +139,56 @@ DEFINE_TEST(test_basic)
* Create an assortment of files on disk. * Create an assortment of files on disk.
*/ */
filelist = fopen("filelist", "w"); filelist = fopen("filelist", "w");
memset(result, 0, sizeof(result));
/* File with 10 bytes content. */ /* File with 10 bytes content. */
assertMakeFile("file", 0644, "1234567890"); assertMakeFile("file", 0644, "1234567890");
fprintf(filelist, "file\n"); fprintf(filelist, "file\n");
if (is_LargeInode("file"))
strncat(result,
"bsdcpio: file: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result));
/* hardlink to above file. */ /* hardlink to above file. */
assertMakeHardlink("linkfile", "file"); assertMakeHardlink("linkfile", "file");
fprintf(filelist, "linkfile\n"); fprintf(filelist, "linkfile\n");
if (is_LargeInode("linkfile"))
strncat(result,
"bsdcpio: linkfile: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result));
/* Symlink to above file. */ /* Symlink to above file. */
if (canSymlink()) { if (canSymlink()) {
assertMakeSymlink("symlink", "file"); assertMakeSymlink("symlink", "file");
fprintf(filelist, "symlink\n"); fprintf(filelist, "symlink\n");
if (is_LargeInode("symlink"))
strncat(result,
"bsdcpio: symlink: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result));
} }
/* Another file with different permissions. */ /* Another file with different permissions. */
assertMakeFile("file2", 0777, "1234567890"); assertMakeFile("file2", 0777, "1234567890");
fprintf(filelist, "file2\n"); fprintf(filelist, "file2\n");
if (is_LargeInode("file2"))
strncat(result,
"bsdcpio: file2: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result));
/* Directory. */ /* Directory. */
assertMakeDir("dir", 0775); assertMakeDir("dir", 0775);
fprintf(filelist, "dir\n"); fprintf(filelist, "dir\n");
if (is_LargeInode("dir"))
strncat(result,
"bsdcpio: dir: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result));
strncat(result, "2 blocks\n", sizeof(result) - strlen(result));
/* All done. */ /* All done. */
fclose(filelist); fclose(filelist);
@ -161,12 +196,12 @@ DEFINE_TEST(test_basic)
/* Archive/dearchive with a variety of options. */ /* Archive/dearchive with a variety of options. */
msg = canSymlink() ? "2 blocks\n" : "1 block\n"; msg = canSymlink() ? "2 blocks\n" : "1 block\n";
basic_cpio("copy", "", "", msg); basic_cpio("copy", "", "", msg, msg);
basic_cpio("copy_odc", "--format=odc", "", msg); basic_cpio("copy_odc", "--format=odc", "", msg, msg);
basic_cpio("copy_newc", "-H newc", "", "2 blocks\n"); basic_cpio("copy_newc", "-H newc", "", result, "2 blocks\n");
basic_cpio("copy_cpio", "-H odc", "", msg); basic_cpio("copy_cpio", "-H odc", "", msg, msg);
msg = canSymlink() ? "9 blocks\n" : "8 blocks\n"; msg = canSymlink() ? "9 blocks\n" : "8 blocks\n";
basic_cpio("copy_ustar", "-H ustar", "", msg); basic_cpio("copy_ustar", "-H ustar", "", msg, msg);
/* Copy in one step using -p */ /* Copy in one step using -p */
passthrough("passthrough"); passthrough("passthrough");

View File

@ -68,6 +68,16 @@ from_hex(const char *p, size_t l)
return (r); return (r);
} }
#if !defined(_WIN32) || defined(__CYGWIN__)
static int
nlinks(const char *p)
{
struct stat st;
assertEqualInt(0, stat(p, &st));
return st.st_nlink;
}
#endif
DEFINE_TEST(test_format_newc) DEFINE_TEST(test_format_newc)
{ {
FILE *list; FILE *list;
@ -77,6 +87,7 @@ DEFINE_TEST(test_format_newc)
time_t t, t2, now; time_t t, t2, now;
char *p, *e; char *p, *e;
size_t s, fs, ns; size_t s, fs, ns;
char result[1024];
assertUmask(0); assertUmask(0);
@ -111,6 +122,29 @@ DEFINE_TEST(test_format_newc)
assertMakeDir("dir", 0775); assertMakeDir("dir", 0775);
fprintf(list, "dir\n"); fprintf(list, "dir\n");
/* Setup result message. */
memset(result, 0, sizeof(result));
if (is_LargeInode("file1"))
strncat(result,
"bsdcpio: file1: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result) -1);
if (canSymlink() && is_LargeInode("symlink"))
strncat(result,
"bsdcpio: symlink: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result) -1);
if (is_LargeInode("dir"))
strncat(result,
"bsdcpio: dir: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result) -1);
if (is_LargeInode("hardlink"))
strncat(result,
"bsdcpio: hardlink: large inode number truncated: "
"Numerical result out of range\n",
sizeof(result) - strlen(result) -1);
/* Record some facts about what we just created: */ /* Record some facts about what we just created: */
now = time(NULL); /* They were all created w/in last two seconds. */ now = time(NULL); /* They were all created w/in last two seconds. */
@ -123,10 +157,11 @@ DEFINE_TEST(test_format_newc)
/* Verify that nothing went to stderr. */ /* Verify that nothing went to stderr. */
if (canSymlink()) { if (canSymlink()) {
assertTextFileContents("2 blocks\n", "newc.err"); strncat(result, "2 blocks\n", sizeof(result) - strlen(result));
} else { } else {
assertTextFileContents("1 block\n", "newc.err"); strncat(result, "1 block\n", sizeof(result) - strlen(result));
} }
assertTextFileContents(result, "newc.err");
/* Verify that stdout is a well-formed cpio file in "newc" format. */ /* Verify that stdout is a well-formed cpio file in "newc" format. */
p = slurpfile(&s, "newc.out"); p = slurpfile(&s, "newc.out");
@ -216,10 +251,10 @@ DEFINE_TEST(test_format_newc)
/* Mode: sgid bit sometimes propagates from parent dirs, ignore it. */ /* Mode: sgid bit sometimes propagates from parent dirs, ignore it. */
assertEqualInt(040775, from_hex(e + 14, 8) & ~02000); assertEqualInt(040775, from_hex(e + 14, 8) & ~02000);
#endif #endif
assertEqualInt(from_hex(e + 22, 8), uid); /* uid */ assertEqualInt(uid, from_hex(e + 22, 8)); /* uid */
assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */ assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
#ifndef NLINKS_INACCURATE_FOR_DIRS #if !defined(_WIN32) || defined(__CYGWIN__)
assertEqualMem(e + 38, "00000002", 8); /* nlink */ assertEqualInt(nlinks("dir"), from_hex(e + 38, 8)); /* nlinks */
#endif #endif
t2 = from_hex(e + 46, 8); /* mtime */ t2 = from_hex(e + 46, 8); /* mtime */
failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2); failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2);

View File

@ -0,0 +1,92 @@
/*-
* Copyright (c) 2003-2010 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$");
DEFINE_TEST(test_option_0)
{
FILE *filelist;
int r;
assertUmask(0);
/* Create a few files. */
assertMakeFile("file1", 0644, "1234567890");
assertMakeFile("file2", 0644, "1234567890");
assertMakeFile("file3", 0644, "1234567890");
assertMakeFile("file4", 0644, "1234567890");
/* Create a file list of filenames with varying end-of-line. */
filelist = fopen("filelist", "wb");
assertEqualInt(fwrite("file1\x0a", 1, 6, filelist), 6);
assertEqualInt(fwrite("file2\x0d", 1, 6, filelist), 6);
assertEqualInt(fwrite("file3\x0a\x0d", 1, 7, filelist), 7);
assertEqualInt(fwrite("file4", 1, 5, filelist), 5);
fclose(filelist);
/* Create a file list of null-delimited names. */
filelist = fopen("filelistNull", "wb");
assertEqualInt(fwrite("file1\0", 1, 6, filelist), 6);
assertEqualInt(fwrite("file2\0", 1, 6, filelist), 6);
assertEqualInt(fwrite("file3\0", 1, 6, filelist), 6);
assertEqualInt(fwrite("file4", 1, 5, filelist), 5);
fclose(filelist);
assertUmask(022);
/* Pack up using the file list with text line endings. */
r = systemf("%s -o < filelist > archive 2> stderr1.txt", testprog);
assertEqualInt(r, 0);
/* Extract into a new dir. */
assertMakeDir("copy", 0775);
assertChdir("copy");
r = systemf("%s -i < ../archive > stdout3.txt 2> stderr3.txt", testprog);
assertEqualInt(r, 0);
/* Verify the files. */
assertIsReg("file1", 0644);
assertIsReg("file2", 0644);
assertIsReg("file3", 0644);
assertIsReg("file4", 0644);
assertChdir("..");
/* Pack up using the file list with nulls. */
r = systemf("%s -o0 < filelistNull > archiveNull 2> stderr2.txt", testprog);
assertEqualInt(r, 0);
/* Extract into a new dir. */
assertMakeDir("copyNull", 0775);
assertChdir("copyNull");
r = systemf("%s -i < ../archiveNull > stdout4.txt 2> stderr4.txt", testprog);
assertEqualInt(r, 0);
/* Verify the files. */
assertIsReg("file1", 0644);
assertIsReg("file2", 0644);
assertIsReg("file3", 0644);
assertIsReg("file4", 0644);
}

View File

@ -51,6 +51,16 @@ from_octal(const char *p, size_t l)
return (r); return (r);
} }
#if !defined(_WIN32) || defined(__CYGWIN__)
static int
nlinks(const char *p)
{
struct stat st;
assertEqualInt(0, stat(p, &st));
return st.st_nlink;
}
#endif
DEFINE_TEST(test_option_c) DEFINE_TEST(test_option_c)
{ {
FILE *filelist; FILE *filelist;
@ -181,17 +191,19 @@ DEFINE_TEST(test_option_c)
/* Group members bits and others bits do not work. */ /* Group members bits and others bits do not work. */
assertEqualMem(e + 18, "040777", 6); /* Mode */ assertEqualMem(e + 18, "040777", 6); /* Mode */
#else #else
/* Accept 042775 to accomodate systems where sgid bit propagates. */ /* Accept 042775 to accommodate systems where sgid bit propagates. */
if (memcmp(e + 18, "042775", 6) != 0) if (memcmp(e + 18, "042775", 6) != 0)
assertEqualMem(e + 18, "040775", 6); /* Mode */ assertEqualMem(e + 18, "040775", 6); /* Mode */
#endif #endif
assertEqualInt(from_octal(e + 24, 6), uid); /* uid */ assertEqualInt(uid, from_octal(e + 24, 6)); /* uid */
/* Gid should be same as first entry. */ /* Gid should be same as first entry. */
assert(is_octal(e + 30, 6)); /* gid */ assert(is_octal(e + 30, 6)); /* gid */
assertEqualInt(gid, from_octal(e + 30, 6)); assertEqualInt(gid, from_octal(e + 30, 6));
#ifndef NLINKS_INACCURATE_FOR_DIRS
assertEqualMem(e + 36, "000002", 6); /* Nlink */ #if !defined(_WIN32) || defined(__CYGWIN__)
assertEqualInt(nlinks("dir"), from_octal(e + 36, 6)); /* Nlink */
#endif #endif
t = from_octal(e + 48, 11); /* mtime */ t = from_octal(e + 48, 11); /* mtime */
assert(t <= now); /* File wasn't created in future. */ assert(t <= now); /* File wasn't created in future. */
assert(t >= now - 2); /* File was created w/in last 2 secs. */ assert(t >= now - 2); /* File was created w/in last 2 secs. */

View File

@ -25,11 +25,17 @@
#include "test.h" #include "test.h"
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
DEFINE_TEST(test_option_t) DEFINE_TEST(test_option_t)
{ {
char *p; char *p;
int r; int r;
time_t mtime;
char date[32];
char date2[32];
/* List reference archive, make sure the TOC is correct. */ /* List reference archive, make sure the TOC is correct. */
extract_reference_file("test_option_t.cpio"); extract_reference_file("test_option_t.cpio");
@ -75,17 +81,20 @@ DEFINE_TEST(test_option_t)
/* Since -n uses numeric UID/GID, this part should be the /* Since -n uses numeric UID/GID, this part should be the
* same on every system. */ * same on every system. */
assertEqualMem(p, "-rw-r--r-- 1 1000 1000 0 ",42); assertEqualMem(p, "-rw-r--r-- 1 1000 1000 0 ",42);
/* Date varies depending on local timezone. */
if (memcmp(p + 42, "Dec 31 1969", 12) == 0) { /* Date varies depending on local timezone and locale. */
/* East of Greenwich we get Dec 31, 1969. */ mtime = 1;
} else { #ifdef HAVE_LOCALE_H
/* West of Greenwich get Jan 1, 1970 */ setlocale(LC_ALL, "");
assertEqualMem(p + 42, "Jan ", 4); #endif
/* Some systems format "Jan 01", some "Jan 1" */ #if defined(_WIN32) && !defined(__CYGWIN__)
assert(p[46] == ' ' || p[46] == '0'); strftime(date2, sizeof(date), "%b %d %Y", localtime(&mtime));
assertEqualMem(p + 47, "1 1970 ", 8); _snprintf(date, sizeof(date)-1, "%12s file", date2);
} #else
assertEqualMem(p + 54, " file", 5); strftime(date2, sizeof(date), "%b %e %Y", localtime(&mtime));
snprintf(date, sizeof(date)-1, "%12s file", date2);
#endif
assertEqualMem(p + 42, date, strlen(date));
free(p); free(p);
/* But "-n" without "-t" is an error. */ /* But "-n" without "-t" is an error. */

View File

@ -41,7 +41,7 @@ DEFINE_TEST(test_option_u)
assertMakeFile("f", 0644, "a"); assertMakeFile("f", 0644, "a");
/* Copy the file to the "copy" dir. */ /* Copy the file to the "copy" dir. */
r = systemf("echo f | %s -pd copy >copy.out 2>copy.err", r = systemf("echo f| %s -pd copy >copy.out 2>copy.err",
testprog); testprog);
assertEqualInt(r, 0); assertEqualInt(r, 0);
@ -60,7 +60,7 @@ DEFINE_TEST(test_option_u)
assertEqualInt(0, utime("f", &times)); assertEqualInt(0, utime("f", &times));
/* Copy the file to the "copy" dir. */ /* Copy the file to the "copy" dir. */
r = systemf("echo f | %s -pd copy >copy.out 2>copy.err", r = systemf("echo f| %s -pd copy >copy.out 2>copy.err",
testprog); testprog);
assertEqualInt(r, 0); assertEqualInt(r, 0);
@ -70,7 +70,7 @@ DEFINE_TEST(test_option_u)
assertEqualMem(p, "a", 1); assertEqualMem(p, "a", 1);
/* Copy the file to the "copy" dir with -u (force) */ /* Copy the file to the "copy" dir with -u (force) */
r = systemf("echo f | %s -pud copy >copy.out 2>copy.err", r = systemf("echo f| %s -pud copy >copy.out 2>copy.err",
testprog); testprog);
assertEqualInt(r, 0); assertEqualInt(r, 0);

View File

@ -30,9 +30,8 @@ __FBSDID("$FreeBSD$");
#if !defined(_WIN32) #if !defined(_WIN32)
#define ROOT "root" #define ROOT "root"
static int root_uids[] = { 0 }; static const int root_uids[] = { 0 };
/* Solaris 9 root has gid 1 (other) */ static const int root_gids[] = { 0, 1 };
static int root_gids[] = { 0, 1 };
#elif defined(__CYGWIN__) #elif defined(__CYGWIN__)
/* On cygwin, the Administrator user most likely exists (unless /* On cygwin, the Administrator user most likely exists (unless
* it has been renamed or is in a non-English localization), but * it has been renamed or is in a non-English localization), but
@ -43,13 +42,13 @@ static int root_gids[] = { 0, 1 };
* Use CreateWellKnownSID() and LookupAccountName()? * Use CreateWellKnownSID() and LookupAccountName()?
*/ */
#define ROOT "Administrator" #define ROOT "Administrator"
static int root_uids[] = { 500 }; static const int root_uids[] = { 500 };
static int root_gids[] = { 513, 545, 544 }; static const int root_gids[] = { 513, 545, 544 };
#endif #endif
#if defined(ROOT) #if defined(ROOT)
static int static int
int_in_list(int i, int *l, size_t n) int_in_list(int i, const int *l, size_t n)
{ {
while (n-- > 0) while (n-- > 0)
if (*l++ == i) if (*l++ == i)

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2003-2010 Tim Kientzle
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -28,6 +28,10 @@
#ifndef ARCHIVE_H_INCLUDED #ifndef ARCHIVE_H_INCLUDED
#define ARCHIVE_H_INCLUDED #define ARCHIVE_H_INCLUDED
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
#include <stdio.h> /* For FILE * */
/* /*
* Note: archive.h is for use outside of libarchive; the configuration * Note: archive.h is for use outside of libarchive; the configuration
* headers (config.h, archive_platform.h, etc.) are purely internal. * headers (config.h, archive_platform.h, etc.) are purely internal.
@ -36,22 +40,15 @@
* platform macros. * platform macros.
*/ */
#if defined(__BORLANDC__) && __BORLANDC__ >= 0x560 #if defined(__BORLANDC__) && __BORLANDC__ >= 0x560
# define __LA_STDINT_H <stdint.h> # include <stdint.h>
#elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) #elif !defined(__WATCOMC__) && !defined(_MSC_VER) && !defined(__INTERIX) && !defined(__BORLANDC__) && !defined(_SCO_DS)
# define __LA_STDINT_H <inttypes.h> # include <inttypes.h>
#endif #endif
#include <sys/stat.h>
#include <sys/types.h> /* Linux requires this for off_t */
#ifdef __LA_STDINT_H
# include __LA_STDINT_H /* int64_t, etc. */
#endif
#include <stdio.h> /* For FILE * */
/* Get appropriate definitions of standard POSIX-style types. */ /* Get appropriate definitions of standard POSIX-style types. */
/* These should match the types used in 'struct stat' */ /* These should match the types used in 'struct stat' */
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
#define __LA_INT64_T __int64 # define __LA_INT64_T __int64
# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_) # if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
# define __LA_SSIZE_T ssize_t # define __LA_SSIZE_T ssize_t
# elif defined(_WIN64) # elif defined(_WIN64)
@ -67,11 +64,15 @@
# define __LA_GID_T short # define __LA_GID_T short
# endif # endif
#else #else
#include <unistd.h> /* ssize_t, uid_t, and gid_t */ # include <unistd.h> /* ssize_t, uid_t, and gid_t */
#define __LA_INT64_T int64_t # if defined(_SCO_DS)
#define __LA_SSIZE_T ssize_t # define __LA_INT64_T long long
#define __LA_UID_T uid_t # else
#define __LA_GID_T gid_t # define __LA_INT64_T int64_t
# endif
# define __LA_SSIZE_T ssize_t
# define __LA_UID_T uid_t
# define __LA_GID_T gid_t
#endif #endif
/* /*
@ -88,7 +89,7 @@
# endif # endif
# else # else
# ifdef __GNUC__ # ifdef __GNUC__
# define __LA_DECL __attribute__((dllimport)) extern # define __LA_DECL
# else # else
# define __LA_DECL __declspec(dllimport) # define __LA_DECL __declspec(dllimport)
# endif # endif
@ -98,7 +99,7 @@
# define __LA_DECL # define __LA_DECL
#endif #endif
#if defined(__GNUC__) && __GNUC__ >= 3 #if defined(__GNUC__) && __GNUC__ >= 3 && !defined(__MINGW32__)
#define __LA_PRINTF(fmtarg, firstvararg) \ #define __LA_PRINTF(fmtarg, firstvararg) \
__attribute__((__format__ (__printf__, fmtarg, firstvararg))) __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
#else #else
@ -123,50 +124,18 @@ extern "C" {
* easy to compare versions at build time: for version a.b.c, the * easy to compare versions at build time: for version a.b.c, the
* version number is printf("%d%03d%03d",a,b,c). For example, if you * version number is printf("%d%03d%03d",a,b,c). For example, if you
* know your application requires version 2.12.108 or later, you can * know your application requires version 2.12.108 or later, you can
* assert that ARCHIVE_VERSION >= 2012108. * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*
* This single-number format was introduced with libarchive 1.9.0 in
* the libarchive 1.x family and libarchive 2.2.4 in the libarchive
* 2.x family. The following may be useful if you really want to do
* feature detection for earlier libarchive versions (which defined
* ARCHIVE_API_VERSION and ARCHIVE_API_FEATURE instead):
*
* #ifndef ARCHIVE_VERSION_NUMBER
* #define ARCHIVE_VERSION_NUMBER \
* (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
* #endif
*/ */
#define ARCHIVE_VERSION_NUMBER 2008005 /* Note: Compiler will complain if this does not match archive_entry.h! */
#define ARCHIVE_VERSION_NUMBER 3000003
__LA_DECL int archive_version_number(void); __LA_DECL int archive_version_number(void);
/* /*
* Textual name/version of the library, useful for version displays. * Textual name/version of the library, useful for version displays.
*/ */
#define ARCHIVE_VERSION_STRING "libarchive 2.8.5" #define ARCHIVE_VERSION_STRING "libarchive 3.0.3"
__LA_DECL const char * archive_version_string(void); __LA_DECL const char * archive_version_string(void);
#if ARCHIVE_VERSION_NUMBER < 3000000
/*
* Deprecated; these are older names that will be removed in favor of
* the simpler definitions above.
*/
#define ARCHIVE_VERSION_STAMP ARCHIVE_VERSION_NUMBER
__LA_DECL int archive_version_stamp(void);
#define ARCHIVE_LIBRARY_VERSION ARCHIVE_VERSION_STRING
__LA_DECL const char * archive_version(void);
#define ARCHIVE_API_VERSION (ARCHIVE_VERSION_NUMBER / 1000000)
__LA_DECL int archive_api_version(void);
#define ARCHIVE_API_FEATURE ((ARCHIVE_VERSION_NUMBER / 1000) % 1000)
__LA_DECL int archive_api_feature(void);
#endif
#if ARCHIVE_VERSION_NUMBER < 3000000
/* This should never have been here in the first place. */
/* Legacy of old tar assumptions, will be removed in libarchive 3.0. */
#define ARCHIVE_BYTES_PER_RECORD 512
#define ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240
#endif
/* Declare our basic types. */ /* Declare our basic types. */
struct archive; struct archive;
struct archive_entry; struct archive_entry;
@ -210,48 +179,56 @@ struct archive_entry;
typedef __LA_SSIZE_T archive_read_callback(struct archive *, typedef __LA_SSIZE_T archive_read_callback(struct archive *,
void *_client_data, const void **_buffer); void *_client_data, const void **_buffer);
/* Skips at most request bytes from archive and returns the skipped amount */ /* Skips at most request bytes from archive and returns the skipped amount.
#if ARCHIVE_VERSION_NUMBER < 2000000 * This may skip fewer bytes than requested; it may even skip zero bytes.
/* Libarchive 1.0 used ssize_t for the return, which is only 32 bits * If you do skip fewer bytes than requested, libarchive will invoke your
* on most 32-bit platforms; not large enough. */ * read callback and discard data as necessary to make up the full skip.
typedef __LA_SSIZE_T archive_skip_callback(struct archive *, */
void *_client_data, size_t request);
#elif ARCHIVE_VERSION_NUMBER < 3000000
/* Libarchive 2.0 used off_t here, but that is a bad idea on Linux and a
* few other platforms where off_t varies with build settings. */
typedef off_t archive_skip_callback(struct archive *,
void *_client_data, off_t request);
#else
/* Libarchive 3.0 uses int64_t here, which is actually guaranteed to be
* 64 bits on every platform. */
typedef __LA_INT64_T archive_skip_callback(struct archive *, typedef __LA_INT64_T archive_skip_callback(struct archive *,
void *_client_data, __LA_INT64_T request); void *_client_data, __LA_INT64_T request);
#endif
/* Seeks to specified location in the file and returns the position.
* Whence values are SEEK_SET, SEEK_CUR, SEEK_END from stdio.h.
* Return ARCHIVE_FATAL if the seek fails for any reason.
*/
typedef __LA_INT64_T archive_seek_callback(struct archive *,
void *_client_data, __LA_INT64_T offset, int whence);
/* Returns size actually written, zero on EOF, -1 on error. */ /* Returns size actually written, zero on EOF, -1 on error. */
typedef __LA_SSIZE_T archive_write_callback(struct archive *, typedef __LA_SSIZE_T archive_write_callback(struct archive *,
void *_client_data, void *_client_data,
const void *_buffer, size_t _length); const void *_buffer, size_t _length);
#if ARCHIVE_VERSION_NUMBER < 3000000
/* Open callback is actually never needed; remove it in libarchive 3.0. */
typedef int archive_open_callback(struct archive *, void *_client_data); typedef int archive_open_callback(struct archive *, void *_client_data);
#endif
typedef int archive_close_callback(struct archive *, void *_client_data); typedef int archive_close_callback(struct archive *, void *_client_data);
/* /*
* Codes for archive_compression. * Codes to identify various stream filters.
*/ */
#define ARCHIVE_COMPRESSION_NONE 0 #define ARCHIVE_FILTER_NONE 0
#define ARCHIVE_COMPRESSION_GZIP 1 #define ARCHIVE_FILTER_GZIP 1
#define ARCHIVE_COMPRESSION_BZIP2 2 #define ARCHIVE_FILTER_BZIP2 2
#define ARCHIVE_COMPRESSION_COMPRESS 3 #define ARCHIVE_FILTER_COMPRESS 3
#define ARCHIVE_COMPRESSION_PROGRAM 4 #define ARCHIVE_FILTER_PROGRAM 4
#define ARCHIVE_COMPRESSION_LZMA 5 #define ARCHIVE_FILTER_LZMA 5
#define ARCHIVE_COMPRESSION_XZ 6 #define ARCHIVE_FILTER_XZ 6
#define ARCHIVE_COMPRESSION_UU 7 #define ARCHIVE_FILTER_UU 7
#define ARCHIVE_COMPRESSION_RPM 8 #define ARCHIVE_FILTER_RPM 8
#define ARCHIVE_FILTER_LZIP 9
#if ARCHIVE_VERSION_NUMBER < 4000000
#define ARCHIVE_COMPRESSION_NONE ARCHIVE_FILTER_NONE
#define ARCHIVE_COMPRESSION_GZIP ARCHIVE_FILTER_GZIP
#define ARCHIVE_COMPRESSION_BZIP2 ARCHIVE_FILTER_BZIP2
#define ARCHIVE_COMPRESSION_COMPRESS ARCHIVE_FILTER_COMPRESS
#define ARCHIVE_COMPRESSION_PROGRAM ARCHIVE_FILTER_PROGRAM
#define ARCHIVE_COMPRESSION_LZMA ARCHIVE_FILTER_LZMA
#define ARCHIVE_COMPRESSION_XZ ARCHIVE_FILTER_XZ
#define ARCHIVE_COMPRESSION_UU ARCHIVE_FILTER_UU
#define ARCHIVE_COMPRESSION_RPM ARCHIVE_FILTER_RPM
#define ARCHIVE_COMPRESSION_LZIP ARCHIVE_FILTER_LZIP
#endif
/* /*
* Codes returned by archive_format. * Codes returned by archive_format.
@ -265,7 +242,7 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
* will change the format code to indicate the extended format that * will change the format code to indicate the extended format that
* was used). In other cases, it's because different tools have * was used). In other cases, it's because different tools have
* modified the archive and so different parts of the archive * modified the archive and so different parts of the archive
* actually have slightly different formts. (Both tar and cpio store * actually have slightly different formats. (Both tar and cpio store
* format codes in each entry, so it is quite possible for each * format codes in each entry, so it is quite possible for each
* entry to be in a different format.) * entry to be in a different format.)
*/ */
@ -276,6 +253,7 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
#define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3) #define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3)
#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4) #define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4)
#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5) #define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5)
#define ARCHIVE_FORMAT_CPIO_AFIO_LARGE (ARCHIVE_FORMAT_CPIO | 6)
#define ARCHIVE_FORMAT_SHAR 0x20000 #define ARCHIVE_FORMAT_SHAR 0x20000
#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1) #define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1)
#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2) #define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2)
@ -294,6 +272,10 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
#define ARCHIVE_FORMAT_MTREE 0x80000 #define ARCHIVE_FORMAT_MTREE 0x80000
#define ARCHIVE_FORMAT_RAW 0x90000 #define ARCHIVE_FORMAT_RAW 0x90000
#define ARCHIVE_FORMAT_XAR 0xA0000 #define ARCHIVE_FORMAT_XAR 0xA0000
#define ARCHIVE_FORMAT_LHA 0xB0000
#define ARCHIVE_FORMAT_CAB 0xC0000
#define ARCHIVE_FORMAT_RAR 0xD0000
#define ARCHIVE_FORMAT_7ZIP 0xE0000
/*- /*-
* Basic outline for reading an archive: * Basic outline for reading an archive:
@ -316,40 +298,81 @@ __LA_DECL struct archive *archive_read_new(void);
* support_compression_bzip2(). The "all" functions provide the * support_compression_bzip2(). The "all" functions provide the
* obvious shorthand. * obvious shorthand.
*/ */
__LA_DECL int archive_read_support_compression_all(struct archive *);
__LA_DECL int archive_read_support_compression_bzip2(struct archive *); #if ARCHIVE_VERSION_NUMBER < 4000000
__LA_DECL int archive_read_support_compression_compress(struct archive *); __LA_DECL int archive_read_support_compression_all(struct archive *);
__LA_DECL int archive_read_support_compression_gzip(struct archive *); __LA_DECL int archive_read_support_compression_bzip2(struct archive *);
__LA_DECL int archive_read_support_compression_lzma(struct archive *); __LA_DECL int archive_read_support_compression_compress(struct archive *);
__LA_DECL int archive_read_support_compression_none(struct archive *); __LA_DECL int archive_read_support_compression_gzip(struct archive *);
__LA_DECL int archive_read_support_compression_program(struct archive *, __LA_DECL int archive_read_support_compression_lzip(struct archive *);
__LA_DECL int archive_read_support_compression_lzma(struct archive *);
__LA_DECL int archive_read_support_compression_none(struct archive *);
__LA_DECL int archive_read_support_compression_program(struct archive *,
const char *command); const char *command);
__LA_DECL int archive_read_support_compression_program_signature __LA_DECL int archive_read_support_compression_program_signature
(struct archive *, const char *, (struct archive *, const char *,
const void * /* match */, size_t); const void * /* match */, size_t);
__LA_DECL int archive_read_support_compression_rpm(struct archive *); __LA_DECL int archive_read_support_compression_rpm(struct archive *);
__LA_DECL int archive_read_support_compression_uu(struct archive *); __LA_DECL int archive_read_support_compression_uu(struct archive *);
__LA_DECL int archive_read_support_compression_xz(struct archive *); __LA_DECL int archive_read_support_compression_xz(struct archive *);
#endif
__LA_DECL int archive_read_support_format_all(struct archive *); __LA_DECL int archive_read_support_filter_all(struct archive *);
__LA_DECL int archive_read_support_format_ar(struct archive *); __LA_DECL int archive_read_support_filter_bzip2(struct archive *);
__LA_DECL int archive_read_support_format_cpio(struct archive *); __LA_DECL int archive_read_support_filter_compress(struct archive *);
__LA_DECL int archive_read_support_format_empty(struct archive *); __LA_DECL int archive_read_support_filter_gzip(struct archive *);
__LA_DECL int archive_read_support_format_gnutar(struct archive *); __LA_DECL int archive_read_support_filter_lzip(struct archive *);
__LA_DECL int archive_read_support_format_iso9660(struct archive *); __LA_DECL int archive_read_support_filter_lzma(struct archive *);
__LA_DECL int archive_read_support_format_mtree(struct archive *); __LA_DECL int archive_read_support_filter_none(struct archive *);
__LA_DECL int archive_read_support_format_raw(struct archive *); __LA_DECL int archive_read_support_filter_program(struct archive *,
__LA_DECL int archive_read_support_format_tar(struct archive *); const char *command);
__LA_DECL int archive_read_support_format_xar(struct archive *); __LA_DECL int archive_read_support_filter_program_signature
__LA_DECL int archive_read_support_format_zip(struct archive *); (struct archive *, const char *,
const void * /* match */, size_t);
__LA_DECL int archive_read_support_filter_rpm(struct archive *);
__LA_DECL int archive_read_support_filter_uu(struct archive *);
__LA_DECL int archive_read_support_filter_xz(struct archive *);
/* Open the archive using callbacks for archive I/O. */ __LA_DECL int archive_read_support_format_7zip(struct archive *);
__LA_DECL int archive_read_open(struct archive *, void *_client_data, __LA_DECL int archive_read_support_format_all(struct archive *);
__LA_DECL int archive_read_support_format_ar(struct archive *);
__LA_DECL int archive_read_support_format_by_code(struct archive *, int);
__LA_DECL int archive_read_support_format_cab(struct archive *);
__LA_DECL int archive_read_support_format_cpio(struct archive *);
__LA_DECL int archive_read_support_format_empty(struct archive *);
__LA_DECL int archive_read_support_format_gnutar(struct archive *);
__LA_DECL int archive_read_support_format_iso9660(struct archive *);
__LA_DECL int archive_read_support_format_lha(struct archive *);
__LA_DECL int archive_read_support_format_mtree(struct archive *);
__LA_DECL int archive_read_support_format_rar(struct archive *);
__LA_DECL int archive_read_support_format_raw(struct archive *);
__LA_DECL int archive_read_support_format_tar(struct archive *);
__LA_DECL int archive_read_support_format_xar(struct archive *);
__LA_DECL int archive_read_support_format_zip(struct archive *);
/* Set various callbacks. */
__LA_DECL int archive_read_set_open_callback(struct archive *,
archive_open_callback *);
__LA_DECL int archive_read_set_read_callback(struct archive *,
archive_read_callback *);
__LA_DECL int archive_read_set_seek_callback(struct archive *,
archive_seek_callback *);
__LA_DECL int archive_read_set_skip_callback(struct archive *,
archive_skip_callback *);
__LA_DECL int archive_read_set_close_callback(struct archive *,
archive_close_callback *);
/* The callback data is provided to all of the callbacks above. */
__LA_DECL int archive_read_set_callback_data(struct archive *, void *);
/* Opening freezes the callbacks. */
__LA_DECL int archive_read_open1(struct archive *);
/* Convenience wrappers around the above. */
__LA_DECL int archive_read_open(struct archive *, void *_client_data,
archive_open_callback *, archive_read_callback *, archive_open_callback *, archive_read_callback *,
archive_close_callback *); archive_close_callback *);
__LA_DECL int archive_read_open2(struct archive *, void *_client_data, __LA_DECL int archive_read_open2(struct archive *, void *_client_data,
archive_open_callback *, archive_read_callback *, archive_open_callback *, archive_read_callback *,
archive_skip_callback *, archive_close_callback *); archive_skip_callback *, archive_close_callback *);
@ -359,30 +382,32 @@ __LA_DECL int archive_read_open2(struct archive *, void *_client_data,
* accept a block size handle tape blocking correctly. * accept a block size handle tape blocking correctly.
*/ */
/* Use this if you know the filename. Note: NULL indicates stdin. */ /* Use this if you know the filename. Note: NULL indicates stdin. */
__LA_DECL int archive_read_open_filename(struct archive *, __LA_DECL int archive_read_open_filename(struct archive *,
const char *_filename, size_t _block_size); const char *_filename, size_t _block_size);
__LA_DECL int archive_read_open_filename_w(struct archive *,
const wchar_t *_filename, size_t _block_size);
/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */ /* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
__LA_DECL int archive_read_open_file(struct archive *, __LA_DECL int archive_read_open_file(struct archive *,
const char *_filename, size_t _block_size); const char *_filename, size_t _block_size);
/* Read an archive that's stored in memory. */ /* Read an archive that's stored in memory. */
__LA_DECL int archive_read_open_memory(struct archive *, __LA_DECL int archive_read_open_memory(struct archive *,
void * buff, size_t size); void * buff, size_t size);
/* A more involved version that is only used for internal testing. */ /* A more involved version that is only used for internal testing. */
__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff, __LA_DECL int archive_read_open_memory2(struct archive *a, void *buff,
size_t size, size_t read_size); size_t size, size_t read_size);
/* Read an archive that's already open, using the file descriptor. */ /* Read an archive that's already open, using the file descriptor. */
__LA_DECL int archive_read_open_fd(struct archive *, int _fd, __LA_DECL int archive_read_open_fd(struct archive *, int _fd,
size_t _block_size); size_t _block_size);
/* Read an archive that's already open, using a FILE *. */ /* Read an archive that's already open, using a FILE *. */
/* Note: DO NOT use this with tape drives. */ /* Note: DO NOT use this with tape drives. */
__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file); __LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file);
/* Parses and returns next entry header. */ /* Parses and returns next entry header. */
__LA_DECL int archive_read_next_header(struct archive *, __LA_DECL int archive_read_next_header(struct archive *,
struct archive_entry **); struct archive_entry **);
/* Parses and returns next entry header using the archive_entry passed in */ /* Parses and returns next entry header using the archive_entry passed in */
__LA_DECL int archive_read_next_header2(struct archive *, __LA_DECL int archive_read_next_header2(struct archive *,
struct archive_entry *); struct archive_entry *);
/* /*
@ -401,14 +426,8 @@ __LA_DECL __LA_SSIZE_T archive_read_data(struct archive *,
* the desired size of the block. The API does guarantee that offsets will * the desired size of the block. The API does guarantee that offsets will
* be strictly increasing and that returned blocks will not overlap. * be strictly increasing and that returned blocks will not overlap.
*/ */
#if ARCHIVE_VERSION_NUMBER < 3000000 __LA_DECL int archive_read_data_block(struct archive *a,
__LA_DECL int archive_read_data_block(struct archive *a, const void **buff, size_t *size, __LA_INT64_T *offset);
const void **buff, size_t *size, off_t *offset);
#else
__LA_DECL int archive_read_data_block(struct archive *a,
const void **buff, size_t *size,
__LA_INT64_T *offset);
#endif
/*- /*-
* Some convenience functions that are built on archive_read_data: * Some convenience functions that are built on archive_read_data:
@ -416,23 +435,27 @@ __LA_DECL int archive_read_data_block(struct archive *a,
* 'into_buffer': writes data into memory buffer that you provide * 'into_buffer': writes data into memory buffer that you provide
* 'into_fd': writes data to specified filedes * 'into_fd': writes data to specified filedes
*/ */
__LA_DECL int archive_read_data_skip(struct archive *); __LA_DECL int archive_read_data_skip(struct archive *);
__LA_DECL int archive_read_data_into_buffer(struct archive *, __LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
void *buffer, __LA_SSIZE_T len);
__LA_DECL int archive_read_data_into_fd(struct archive *, int fd);
/* /*
* Set read options. * Set read options.
*/ */
/* Apply option string to the format only. */ /* Apply option to the format only. */
__LA_DECL int archive_read_set_format_options(struct archive *_a, __LA_DECL int archive_read_set_format_option(struct archive *_a,
const char *s); const char *m, const char *o,
/* Apply option string to the filter only. */ const char *v);
__LA_DECL int archive_read_set_filter_options(struct archive *_a, /* Apply option to the filter only. */
const char *s); __LA_DECL int archive_read_set_filter_option(struct archive *_a,
const char *m, const char *o,
const char *v);
/* Apply option to both the format and the filter. */
__LA_DECL int archive_read_set_option(struct archive *_a,
const char *m, const char *o,
const char *v);
/* Apply option string to both the format and the filter. */ /* Apply option string to both the format and the filter. */
__LA_DECL int archive_read_set_options(struct archive *_a, __LA_DECL int archive_read_set_options(struct archive *_a,
const char *s); const char *opts);
/*- /*-
* Convenience function to recreate the current entry (whose header * Convenience function to recreate the current entry (whose header
@ -477,10 +500,13 @@ __LA_DECL int archive_read_set_options(struct archive *_a,
#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800) #define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800)
/* Detect blocks of 0 and write holes instead. */ /* Detect blocks of 0 and write holes instead. */
#define ARCHIVE_EXTRACT_SPARSE (0x1000) #define ARCHIVE_EXTRACT_SPARSE (0x1000)
/* Default: Do not restore Mac extended metadata. */
/* This has no effect except on Mac OS. */
#define ARCHIVE_EXTRACT_MAC_METADATA (0x2000)
__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *, __LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
int flags); int flags);
__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *, __LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *,
struct archive * /* dest */); struct archive * /* dest */);
__LA_DECL void archive_read_extract_set_progress_callback(struct archive *, __LA_DECL void archive_read_extract_set_progress_callback(struct archive *,
void (*_progress_func)(void *), void *_user_data); void (*_progress_func)(void *), void *_user_data);
@ -488,7 +514,7 @@ __LA_DECL void archive_read_extract_set_progress_callback(struct archive *,
/* Record the dev/ino of a file that will not be written. This is /* Record the dev/ino of a file that will not be written. This is
* generally set to the dev/ino of the archive being read. */ * generally set to the dev/ino of the archive being read. */
__LA_DECL void archive_read_extract_set_skip_file(struct archive *, __LA_DECL void archive_read_extract_set_skip_file(struct archive *,
dev_t, ino_t); __LA_INT64_T, __LA_INT64_T);
/* Close the file and release most resources. */ /* Close the file and release most resources. */
__LA_DECL int archive_read_close(struct archive *); __LA_DECL int archive_read_close(struct archive *);
@ -502,7 +528,7 @@ __LA_DECL int archive_read_finish(struct archive *);
/*- /*-
* To create an archive: * To create an archive:
* 1) Ask archive_write_new for a archive writer object. * 1) Ask archive_write_new for an archive writer object.
* 2) Set any global properties. In particular, you should set * 2) Set any global properties. In particular, you should set
* the compression and format to use. * the compression and format to use.
* 3) Call archive_write_open to open the file (most people * 3) Call archive_write_open to open the file (most people
@ -516,85 +542,93 @@ __LA_DECL int archive_read_finish(struct archive *);
* 6) archive_write_free to cleanup the writer and release resources * 6) archive_write_free to cleanup the writer and release resources
*/ */
__LA_DECL struct archive *archive_write_new(void); __LA_DECL struct archive *archive_write_new(void);
__LA_DECL int archive_write_set_bytes_per_block(struct archive *, __LA_DECL int archive_write_set_bytes_per_block(struct archive *,
int bytes_per_block); int bytes_per_block);
__LA_DECL int archive_write_get_bytes_per_block(struct archive *); __LA_DECL int archive_write_get_bytes_per_block(struct archive *);
/* XXX This is badly misnamed; suggestions appreciated. XXX */ /* XXX This is badly misnamed; suggestions appreciated. XXX */
__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *, __LA_DECL int archive_write_set_bytes_in_last_block(struct archive *,
int bytes_in_last_block); int bytes_in_last_block);
__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *); __LA_DECL int archive_write_get_bytes_in_last_block(struct archive *);
/* The dev/ino of a file that won't be archived. This is used /* The dev/ino of a file that won't be archived. This is used
* to avoid recursively adding an archive to itself. */ * to avoid recursively adding an archive to itself. */
__LA_DECL int archive_write_set_skip_file(struct archive *, dev_t, ino_t); __LA_DECL int archive_write_set_skip_file(struct archive *,
__LA_INT64_T, __LA_INT64_T);
__LA_DECL int archive_write_set_compression_bzip2(struct archive *); #if ARCHIVE_VERSION_NUMBER < 4000000
__LA_DECL int archive_write_set_compression_compress(struct archive *); __LA_DECL int archive_write_set_compression_bzip2(struct archive *);
__LA_DECL int archive_write_set_compression_gzip(struct archive *); __LA_DECL int archive_write_set_compression_compress(struct archive *);
__LA_DECL int archive_write_set_compression_lzma(struct archive *); __LA_DECL int archive_write_set_compression_gzip(struct archive *);
__LA_DECL int archive_write_set_compression_none(struct archive *); __LA_DECL int archive_write_set_compression_lzip(struct archive *);
__LA_DECL int archive_write_set_compression_program(struct archive *, __LA_DECL int archive_write_set_compression_lzma(struct archive *);
__LA_DECL int archive_write_set_compression_none(struct archive *);
__LA_DECL int archive_write_set_compression_program(struct archive *,
const char *cmd); const char *cmd);
__LA_DECL int archive_write_set_compression_xz(struct archive *); __LA_DECL int archive_write_set_compression_xz(struct archive *);
#endif
__LA_DECL int archive_write_add_filter_bzip2(struct archive *);
__LA_DECL int archive_write_add_filter_compress(struct archive *);
__LA_DECL int archive_write_add_filter_gzip(struct archive *);
__LA_DECL int archive_write_add_filter_lzip(struct archive *);
__LA_DECL int archive_write_add_filter_lzma(struct archive *);
__LA_DECL int archive_write_add_filter_none(struct archive *);
__LA_DECL int archive_write_add_filter_program(struct archive *,
const char *cmd);
__LA_DECL int archive_write_add_filter_xz(struct archive *);
/* A convenience function to set the format based on the code or name. */ /* A convenience function to set the format based on the code or name. */
__LA_DECL int archive_write_set_format(struct archive *, int format_code); __LA_DECL int archive_write_set_format(struct archive *, int format_code);
__LA_DECL int archive_write_set_format_by_name(struct archive *, __LA_DECL int archive_write_set_format_by_name(struct archive *,
const char *name); const char *name);
/* To minimize link pollution, use one or more of the following. */ /* To minimize link pollution, use one or more of the following. */
__LA_DECL int archive_write_set_format_ar_bsd(struct archive *); __LA_DECL int archive_write_set_format_7zip(struct archive *);
__LA_DECL int archive_write_set_format_ar_svr4(struct archive *); __LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
__LA_DECL int archive_write_set_format_cpio(struct archive *); __LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
__LA_DECL int archive_write_set_format_cpio_newc(struct archive *); __LA_DECL int archive_write_set_format_cpio(struct archive *);
__LA_DECL int archive_write_set_format_mtree(struct archive *); __LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
__LA_DECL int archive_write_set_format_gnutar(struct archive *);
__LA_DECL int archive_write_set_format_iso9660(struct archive *);
__LA_DECL int archive_write_set_format_mtree(struct archive *);
/* TODO: int archive_write_set_format_old_tar(struct archive *); */ /* TODO: int archive_write_set_format_old_tar(struct archive *); */
__LA_DECL int archive_write_set_format_pax(struct archive *); __LA_DECL int archive_write_set_format_pax(struct archive *);
__LA_DECL int archive_write_set_format_pax_restricted(struct archive *); __LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
__LA_DECL int archive_write_set_format_shar(struct archive *); __LA_DECL int archive_write_set_format_shar(struct archive *);
__LA_DECL int archive_write_set_format_shar_dump(struct archive *); __LA_DECL int archive_write_set_format_shar_dump(struct archive *);
__LA_DECL int archive_write_set_format_ustar(struct archive *); __LA_DECL int archive_write_set_format_ustar(struct archive *);
__LA_DECL int archive_write_set_format_zip(struct archive *); __LA_DECL int archive_write_set_format_xar(struct archive *);
__LA_DECL int archive_write_open(struct archive *, void *, __LA_DECL int archive_write_set_format_zip(struct archive *);
__LA_DECL int archive_write_open(struct archive *, void *,
archive_open_callback *, archive_write_callback *, archive_open_callback *, archive_write_callback *,
archive_close_callback *); archive_close_callback *);
__LA_DECL int archive_write_open_fd(struct archive *, int _fd); __LA_DECL int archive_write_open_fd(struct archive *, int _fd);
__LA_DECL int archive_write_open_filename(struct archive *, const char *_file); __LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
__LA_DECL int archive_write_open_filename_w(struct archive *,
const wchar_t *_file);
/* A deprecated synonym for archive_write_open_filename() */ /* A deprecated synonym for archive_write_open_filename() */
__LA_DECL int archive_write_open_file(struct archive *, const char *_file); __LA_DECL int archive_write_open_file(struct archive *, const char *_file);
__LA_DECL int archive_write_open_FILE(struct archive *, FILE *); __LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
/* _buffSize is the size of the buffer, _used refers to a variable that /* _buffSize is the size of the buffer, _used refers to a variable that
* will be updated after each write into the buffer. */ * will be updated after each write into the buffer. */
__LA_DECL int archive_write_open_memory(struct archive *, __LA_DECL int archive_write_open_memory(struct archive *,
void *_buffer, size_t _buffSize, size_t *_used); void *_buffer, size_t _buffSize, size_t *_used);
/* /*
* Note that the library will truncate writes beyond the size provided * Note that the library will truncate writes beyond the size provided
* to archive_write_header or pad if the provided data is short. * to archive_write_header or pad if the provided data is short.
*/ */
__LA_DECL int archive_write_header(struct archive *, __LA_DECL int archive_write_header(struct archive *,
struct archive_entry *); struct archive_entry *);
#if ARCHIVE_VERSION_NUMBER < 2000000 __LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
/* This was erroneously declared to return "int" in libarchive 1.x. */
__LA_DECL int archive_write_data(struct archive *,
const void *, size_t); const void *, size_t);
#else
/* Libarchive 2.0 and later return ssize_t here. */
__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
const void *, size_t);
#endif
#if ARCHIVE_VERSION_NUMBER < 3000000 /* This interface is currently only available for archive_write_disk handles. */
/* Libarchive 1.x and 2.x use off_t for the argument, but that's not
* stable on Linux. */
__LA_DECL __LA_SSIZE_T archive_write_data_block(struct archive *,
const void *, size_t, off_t);
#else
/* Libarchive 3.0 uses explicit int64_t to ensure consistent 64-bit support. */
__LA_DECL __LA_SSIZE_T archive_write_data_block(struct archive *, __LA_DECL __LA_SSIZE_T archive_write_data_block(struct archive *,
const void *, size_t, __LA_INT64_T); const void *, size_t, __LA_INT64_T);
#endif
__LA_DECL int archive_write_finish_entry(struct archive *); __LA_DECL int archive_write_finish_entry(struct archive *);
__LA_DECL int archive_write_close(struct archive *); __LA_DECL int archive_write_close(struct archive *);
/* This can fail if the archive wasn't already closed, in which case /* This can fail if the archive wasn't already closed, in which case
* archive_write_free() will implicitly call archive_write_close(). */ * archive_write_free() will implicitly call archive_write_close(). */
__LA_DECL int archive_write_free(struct archive *); __LA_DECL int archive_write_free(struct archive *);
@ -606,16 +640,21 @@ __LA_DECL int archive_write_finish(struct archive *);
/* /*
* Set write options. * Set write options.
*/ */
/* Apply option string to the format only. */ /* Apply option to the format only. */
__LA_DECL int archive_write_set_format_options(struct archive *_a, __LA_DECL int archive_write_set_format_option(struct archive *_a,
const char *s); const char *m, const char *o,
/* Apply option string to the compressor only. */ const char *v);
__LA_DECL int archive_write_set_compressor_options(struct archive *_a, /* Apply option to the filter only. */
const char *s); __LA_DECL int archive_write_set_filter_option(struct archive *_a,
/* Apply option string to both the format and the compressor. */ const char *m, const char *o,
__LA_DECL int archive_write_set_options(struct archive *_a, const char *v);
const char *s); /* Apply option to both the format and the filter. */
__LA_DECL int archive_write_set_option(struct archive *_a,
const char *m, const char *o,
const char *v);
/* Apply option string to both the format and the filter. */
__LA_DECL int archive_write_set_options(struct archive *_a,
const char *opts);
/*- /*-
* ARCHIVE_WRITE_DISK API * ARCHIVE_WRITE_DISK API
@ -635,8 +674,8 @@ __LA_DECL int archive_write_set_options(struct archive *_a,
*/ */
__LA_DECL struct archive *archive_write_disk_new(void); __LA_DECL struct archive *archive_write_disk_new(void);
/* This file will not be overwritten. */ /* This file will not be overwritten. */
__LA_DECL int archive_write_disk_set_skip_file(struct archive *, __LA_DECL int archive_write_disk_set_skip_file(struct archive *,
dev_t, ino_t); __LA_INT64_T, __LA_INT64_T);
/* Set flags to control how the next item gets created. /* Set flags to control how the next item gets created.
* This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */ * This accepts a bitmask of ARCHIVE_EXTRACT_XXX flags defined above. */
__LA_DECL int archive_write_disk_set_options(struct archive *, __LA_DECL int archive_write_disk_set_options(struct archive *,
@ -664,14 +703,16 @@ __LA_DECL int archive_write_disk_set_standard_lookup(struct archive *);
* your needs, you can write your own and register them. Be sure to * your needs, you can write your own and register them. Be sure to
* include a cleanup function if you have allocated private data. * include a cleanup function if you have allocated private data.
*/ */
__LA_DECL int archive_write_disk_set_group_lookup(struct archive *, __LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
void * /* private_data */, void * /* private_data */,
__LA_GID_T (*)(void *, const char *, __LA_GID_T), __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
void (* /* cleanup */)(void *)); void (* /* cleanup */)(void *));
__LA_DECL int archive_write_disk_set_user_lookup(struct archive *, __LA_DECL int archive_write_disk_set_user_lookup(struct archive *,
void * /* private_data */, void * /* private_data */,
__LA_UID_T (*)(void *, const char *, __LA_UID_T), __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
void (* /* cleanup */)(void *)); void (* /* cleanup */)(void *));
__LA_DECL __LA_INT64_T archive_write_disk_gid(struct archive *, const char *, __LA_INT64_T);
__LA_DECL __LA_INT64_T archive_write_disk_uid(struct archive *, const char *, __LA_INT64_T);
/* /*
* ARCHIVE_READ_DISK API * ARCHIVE_READ_DISK API
@ -692,32 +733,64 @@ __LA_DECL int archive_read_disk_entry_from_file(struct archive *,
struct archive_entry *, int /* fd */, const struct stat *); struct archive_entry *, int /* fd */, const struct stat *);
/* Look up gname for gid or uname for uid. */ /* Look up gname for gid or uname for uid. */
/* Default implementations are very, very stupid. */ /* Default implementations are very, very stupid. */
__LA_DECL const char *archive_read_disk_gname(struct archive *, __LA_GID_T); __LA_DECL const char *archive_read_disk_gname(struct archive *, __LA_INT64_T);
__LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_UID_T); __LA_DECL const char *archive_read_disk_uname(struct archive *, __LA_INT64_T);
/* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the /* "Standard" implementation uses getpwuid_r, getgrgid_r and caches the
* results for performance. */ * results for performance. */
__LA_DECL int archive_read_disk_set_standard_lookup(struct archive *); __LA_DECL int archive_read_disk_set_standard_lookup(struct archive *);
/* You can install your own lookups if you like. */ /* You can install your own lookups if you like. */
__LA_DECL int archive_read_disk_set_gname_lookup(struct archive *, __LA_DECL int archive_read_disk_set_gname_lookup(struct archive *,
void * /* private_data */, void * /* private_data */,
const char *(* /* lookup_fn */)(void *, __LA_GID_T), const char *(* /* lookup_fn */)(void *, __LA_INT64_T),
void (* /* cleanup_fn */)(void *)); void (* /* cleanup_fn */)(void *));
__LA_DECL int archive_read_disk_set_uname_lookup(struct archive *, __LA_DECL int archive_read_disk_set_uname_lookup(struct archive *,
void * /* private_data */, void * /* private_data */,
const char *(* /* lookup_fn */)(void *, __LA_UID_T), const char *(* /* lookup_fn */)(void *, __LA_INT64_T),
void (* /* cleanup_fn */)(void *)); void (* /* cleanup_fn */)(void *));
/* Start traversal. */
__LA_DECL int archive_read_disk_open(struct archive *, const char *);
__LA_DECL int archive_read_disk_open_w(struct archive *, const wchar_t *);
/*
* 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.
*/
__LA_DECL int archive_read_disk_descend(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem_is_synthetic(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem_is_remote(struct archive *);
/* Request that the access time of the entry visited by travesal be restored. */
__LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
/* /*
* Accessor functions to read/set various information in * Accessor functions to read/set various information in
* the struct archive object: * the struct archive object:
*/ */
/* Bytes written after compression or read before decompression. */
__LA_DECL __LA_INT64_T archive_position_compressed(struct archive *);
/* Bytes written to compressor or read from decompressor. */
__LA_DECL __LA_INT64_T archive_position_uncompressed(struct archive *);
/* Number of filters in the current filter pipeline. */
/* Filter #0 is the one closest to the format, -1 is a synonym for the
* last filter, which is always the pseudo-filter that wraps the
* client callbacks. */
__LA_DECL int archive_filter_count(struct archive *);
__LA_DECL __LA_INT64_T archive_filter_bytes(struct archive *, int);
__LA_DECL int archive_filter_code(struct archive *, int);
__LA_DECL const char * archive_filter_name(struct archive *, int);
#if ARCHIVE_VERSION_NUMBER < 4000000
/* These don't properly handle multiple filters, so are deprecated and
* will eventually be removed. */
/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
__LA_DECL __LA_INT64_T archive_position_compressed(struct archive *);
/* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
__LA_DECL __LA_INT64_T archive_position_uncompressed(struct archive *);
/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
__LA_DECL const char *archive_compression_name(struct archive *); __LA_DECL const char *archive_compression_name(struct archive *);
/* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
__LA_DECL int archive_compression(struct archive *); __LA_DECL int archive_compression(struct archive *);
#endif
__LA_DECL int archive_errno(struct archive *); __LA_DECL int archive_errno(struct archive *);
__LA_DECL const char *archive_error_string(struct archive *); __LA_DECL const char *archive_error_string(struct archive *);
__LA_DECL const char *archive_format_name(struct archive *); __LA_DECL const char *archive_format_name(struct archive *);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,87 @@
/*-
* Copyright (c) 2003-2010 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$
*/
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_ACL_PRIVATE_H_INCLUDED
#define ARCHIVE_ACL_PRIVATE_H_INCLUDED
#include "archive_string.h"
struct archive_acl_entry {
struct archive_acl_entry *next;
int type; /* E.g., access or default */
int tag; /* E.g., user/group/other/mask */
int permset; /* r/w/x bits */
int id; /* uid/gid for user/group */
struct archive_mstring name; /* uname/gname */
};
struct archive_acl {
mode_t mode;
struct archive_acl_entry *acl_head;
struct archive_acl_entry *acl_p;
int acl_state; /* See acl_next for details. */
wchar_t *acl_text_w;
char *acl_text;
int acl_types;
};
void archive_acl_clear(struct archive_acl *);
void archive_acl_copy(struct archive_acl *, struct archive_acl *);
int archive_acl_count(struct archive_acl *, int);
int archive_acl_reset(struct archive_acl *, int);
int archive_acl_next(struct archive *, struct archive_acl *, int,
int *, int *, int *, int *, const char **);
int archive_acl_add_entry(struct archive_acl *, int, int, int, int, const char *);
int archive_acl_add_entry_w_len(struct archive_acl *,
int, int, int, int, const wchar_t *, size_t);
int archive_acl_add_entry_len(struct archive_acl *,
int, int, int, int, const char *, size_t);
const wchar_t *archive_acl_text_w(struct archive *, struct archive_acl *, int);
int archive_acl_text_l(struct archive_acl *, int, const char **, size_t *,
struct archive_string_conv *);
/*
* Private ACL parser. This is private because it handles some
* very weird formats that clients should not be messing with.
* Clients should only deal with their platform-native formats.
* Because of the need to support many formats cleanly, new arguments
* are likely to get added on a regular basis. Clients who try to use
* this interface are likely to be surprised when it changes.
*/
int archive_acl_parse_w(struct archive_acl *,
const wchar_t *, int /* type */);
int archive_acl_parse_l(struct archive_acl *,
const char *, int /* type */,
struct archive_string_conv *);
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2003-2010 Tim Kientzle
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -86,49 +86,89 @@ state_name(unsigned s)
} }
} }
static const char *
archive_handle_type_name(unsigned m)
{
switch (m) {
case ARCHIVE_WRITE_MAGIC: return ("archive_write");
case ARCHIVE_READ_MAGIC: return ("archive_read");
case ARCHIVE_WRITE_DISK_MAGIC: return ("archive_write_disk");
case ARCHIVE_READ_DISK_MAGIC: return ("archive_read_disk");
default: return NULL;
}
}
static void
write_all_states(unsigned int states) static char *
write_all_states(char *buff, unsigned int states)
{ {
unsigned int lowbit; unsigned int lowbit;
buff[0] = '\0';
/* A trick for computing the lowest set bit. */ /* A trick for computing the lowest set bit. */
while ((lowbit = states & (1 + ~states)) != 0) { while ((lowbit = states & (1 + ~states)) != 0) {
states &= ~lowbit; /* Clear the low bit. */ states &= ~lowbit; /* Clear the low bit. */
errmsg(state_name(lowbit)); strcat(buff, state_name(lowbit));
if (states != 0) if (states != 0)
errmsg("/"); strcat(buff, "/");
} }
return buff;
} }
/* /*
* Check magic value and current state; bail if it isn't valid. * Check magic value and current state.
* Magic value mismatches are fatal and result in calls to abort().
* State mismatches return ARCHIVE_FATAL.
* Otherwise, returns ARCHIVE_OK.
* *
* This is designed to catch serious programming errors that violate * This is designed to catch serious programming errors that violate
* the libarchive API. * the libarchive API.
*/ */
void int
__archive_check_magic(struct archive *a, unsigned int magic, __archive_check_magic(struct archive *a, unsigned int magic,
unsigned int state, const char *function) unsigned int state, const char *function)
{ {
if (a->magic != magic) { char states1[64];
errmsg("INTERNAL ERROR: Function "); char states2[64];
const char *handle_type;
/*
* If this isn't some form of archive handle,
* then the library user has screwed up so bad that
* we don't even have a reliable way to report an error.
*/
handle_type = archive_handle_type_name(a->magic);
if (!handle_type) {
errmsg("PROGRAMMER ERROR: Function ");
errmsg(function); errmsg(function);
errmsg(" invoked with invalid struct archive structure.\n"); errmsg(" invoked with invalid archive handle.\n");
diediedie(); diediedie();
} }
if (state == ARCHIVE_STATE_ANY) if (a->magic != magic) {
return; archive_set_error(a, -1,
"PROGRAMMER ERROR: Function '%s' invoked"
" on '%s' archive object, which is not supported.",
function,
handle_type);
a->state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
if ((a->state & state) == 0) { if ((a->state & state) == 0) {
errmsg("INTERNAL ERROR: Function '"); /* If we're already FATAL, don't overwrite the error. */
errmsg(function); if (a->state != ARCHIVE_STATE_FATAL)
errmsg("' invoked with archive structure in state '"); archive_set_error(a, -1,
write_all_states(a->state); "INTERNAL ERROR: Function '%s' invoked with"
errmsg("', should be in state '"); " archive structure in state '%s',"
write_all_states(state); " should be in state '%s'",
errmsg("'\n"); function,
diediedie(); write_all_states(states1, a->state),
write_all_states(states2, state));
a->state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
} }
return ARCHIVE_OK;
} }

View File

@ -60,6 +60,18 @@ crc32(unsigned long crc, const void *_p, size_t len)
} }
crc = crc ^ 0xffffffffUL; crc = crc ^ 0xffffffffUL;
/* A use of this loop is about 20% - 30% faster than
* no use version in any optimization option of gcc. */
for (;len >= 8; len -= 8) {
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
}
while (len--) while (len--)
crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8); crc = crc_tbl[(crc ^ *p++) & 0xff] ^ (crc >> 8);
return (crc ^ 0xffffffffUL); return (crc ^ 0xffffffffUL);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,376 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2011 Andres Mejia
* 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.
*/
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
#define ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
/*
* Crypto support in various Operating Systems:
*
* NetBSD:
* - MD5 and SHA1 in libc: without _ after algorithm name
* - SHA2 in libc: with _ after algorithm name
*
* OpenBSD:
* - MD5, SHA1 and SHA2 in libc: without _ after algorithm name
* - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name
*
* DragonFly and FreeBSD:
* - MD5 libmd: without _ after algorithm name
* - SHA1, SHA256 and SHA512 in libmd: with _ after algorithm name
*
* Mac OS X (10.4 and later):
* - MD5, SHA1 and SHA2 in libSystem: with CC_ prefix and _ after algorithm name
*
* OpenSSL:
* - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name
*
* Windows:
* - MD5, SHA1 and SHA2 in archive_crypto.c using Windows crypto API
*/
/* libc crypto headers */
#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
#include <md5.h>
#endif
#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
#include <rmd160.h>
#endif
#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
#include <sha1.h>
#endif
#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
#include <sha2.h>
#endif
/* libmd crypto headers */
#if defined(ARCHIVE_CRYPTO_MD5_LIBMD) ||\
defined(ARCHIVE_CRYPTO_RMD160_LIBMD) ||\
defined(ARCHIVE_CRYPTO_SHA1_LIBMD) ||\
defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
#define ARCHIVE_CRYPTO_LIBMD 1
#endif
#if defined(ARCHIVE_CRYPTO_MD5_LIBMD)
#include <md5.h>
#endif
#if defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
#include <ripemd.h>
#endif
#if defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
#include <sha.h>
#endif
#if defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
#include <sha256.h>
#endif
#if defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
#include <sha512.h>
#endif
/* libSystem crypto headers */
#if defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
#include <CommonCrypto/CommonDigest.h>
#endif
/* Nettle crypto headers */
#if defined(ARCHIVE_CRYPTO_MD5_NETTLE)
#include <nettle/md5.h>
#endif
#if defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
#include <nettle/ripemd160.h>
#endif
#if defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
#include <nettle/sha.h>
#endif
/* OpenSSL crypto headers */
#if defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_RMD160_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
#define ARCHIVE_CRYPTO_OPENSSL 1
#include <openssl/evp.h>
#endif
/* Windows crypto headers */
#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
defined(ARCHIVE_CRYPTO_SHA512_WIN)
#include <wincrypt.h>
typedef struct {
int valid;
HCRYPTPROV cryptProv;
HCRYPTHASH hash;
} Digest_CTX;
#endif
/* typedefs */
#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
typedef MD5_CTX archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
typedef MD5_CTX archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
typedef CC_MD5_CTX archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
typedef struct md5_ctx archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
typedef EVP_MD_CTX archive_md5_ctx;
#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
typedef Digest_CTX archive_md5_ctx;
#else
typedef unsigned char archive_md5_ctx;
#endif
#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
typedef RMD160_CTX archive_rmd160_ctx;
#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
typedef RIPEMD160_CTX archive_rmd160_ctx;
#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
typedef struct ripemd160_ctx archive_rmd160_ctx;
#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
typedef EVP_MD_CTX archive_rmd160_ctx;
#else
typedef unsigned char archive_rmd160_ctx;
#endif
#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
typedef SHA1_CTX archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
typedef SHA1_CTX archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
typedef CC_SHA1_CTX archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
typedef struct sha1_ctx archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
typedef EVP_MD_CTX archive_sha1_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
typedef Digest_CTX archive_sha1_ctx;
#else
typedef unsigned char archive_sha1_ctx;
#endif
#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
typedef SHA256_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
typedef SHA256_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
typedef SHA2_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
typedef SHA256_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
typedef CC_SHA256_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
typedef struct sha256_ctx archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
typedef EVP_MD_CTX archive_sha256_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
typedef Digest_CTX archive_sha256_ctx;
#else
typedef unsigned char archive_sha256_ctx;
#endif
#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
typedef SHA384_CTX archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
typedef SHA384_CTX archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
typedef SHA2_CTX archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
typedef CC_SHA512_CTX archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
typedef struct sha384_ctx archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
typedef EVP_MD_CTX archive_sha384_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
typedef Digest_CTX archive_sha384_ctx;
#else
typedef unsigned char archive_sha384_ctx;
#endif
#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
typedef SHA512_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
typedef SHA512_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
typedef SHA2_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
typedef SHA512_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
typedef CC_SHA512_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
typedef struct sha512_ctx archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
typedef EVP_MD_CTX archive_sha512_ctx;
#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
typedef Digest_CTX archive_sha512_ctx;
#else
typedef unsigned char archive_sha512_ctx;
#endif
/* defines */
#if defined(ARCHIVE_CRYPTO_MD5_LIBC) ||\
defined(ARCHIVE_CRYPTO_MD5_LIBMD) || \
defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_MD5_NETTLE) ||\
defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_MD5_WIN)
#define ARCHIVE_HAS_MD5
#endif
#define archive_md5_init(ctx)\
__archive_crypto.md5init(ctx)
#define archive_md5_final(ctx, md)\
__archive_crypto.md5final(ctx, md)
#define archive_md5_update(ctx, buf, n)\
__archive_crypto.md5update(ctx, buf, n)
#if defined(ARCHIVE_CRYPTO_RMD160_LIBC) ||\
defined(ARCHIVE_CRYPTO_RMD160_NETTLE) ||\
defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
#define ARCHIVE_HAS_RMD160
#endif
#define archive_rmd160_init(ctx)\
__archive_crypto.rmd160init(ctx)
#define archive_rmd160_final(ctx, md)\
__archive_crypto.rmd160final(ctx, md)
#define archive_rmd160_update(ctx, buf, n)\
__archive_crypto.rmd160update(ctx, buf, n)
#if defined(ARCHIVE_CRYPTO_SHA1_LIBC) ||\
defined(ARCHIVE_CRYPTO_SHA1_LIBMD) || \
defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA1_WIN)
#define ARCHIVE_HAS_SHA1
#endif
#define archive_sha1_init(ctx)\
__archive_crypto.sha1init(ctx)
#define archive_sha1_final(ctx, md)\
__archive_crypto.sha1final(ctx, md)
#define archive_sha1_update(ctx, buf, n)\
__archive_crypto.sha1update(ctx, buf, n)
#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA256_WIN)
#define ARCHIVE_HAS_SHA256
#endif
#define archive_sha256_init(ctx)\
__archive_crypto.sha256init(ctx)
#define archive_sha256_final(ctx, md)\
__archive_crypto.sha256final(ctx, md)
#define archive_sha256_update(ctx, buf, n)\
__archive_crypto.sha256update(ctx, buf, n)
#if defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA384_WIN)
#define ARCHIVE_HAS_SHA384
#endif
#define archive_sha384_init(ctx)\
__archive_crypto.sha384init(ctx)
#define archive_sha384_final(ctx, md)\
__archive_crypto.sha384final(ctx, md)
#define archive_sha384_update(ctx, buf, n)\
__archive_crypto.sha384update(ctx, buf, n)
#if defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBC3) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBMD) ||\
defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM) ||\
defined(ARCHIVE_CRYPTO_SHA512_NETTLE) ||\
defined(ARCHIVE_CRYPTO_SHA512_OPENSSL) ||\
defined(ARCHIVE_CRYPTO_SHA512_WIN)
#define ARCHIVE_HAS_SHA512
#endif
#define archive_sha512_init(ctx)\
__archive_crypto.sha512init(ctx)
#define archive_sha512_final(ctx, md)\
__archive_crypto.sha512final(ctx, md)
#define archive_sha512_update(ctx, buf, n)\
__archive_crypto.sha512update(ctx, buf, n)
/* Minimal interface to crypto functionality for internal use in libarchive */
struct archive_crypto
{
/* Message Digest */
int (*md5init)(archive_md5_ctx *ctx);
int (*md5update)(archive_md5_ctx *, const void *, size_t);
int (*md5final)(archive_md5_ctx *, void *);
int (*rmd160init)(archive_rmd160_ctx *);
int (*rmd160update)(archive_rmd160_ctx *, const void *, size_t);
int (*rmd160final)(archive_rmd160_ctx *, void *);
int (*sha1init)(archive_sha1_ctx *);
int (*sha1update)(archive_sha1_ctx *, const void *, size_t);
int (*sha1final)(archive_sha1_ctx *, void *);
int (*sha256init)(archive_sha256_ctx *);
int (*sha256update)(archive_sha256_ctx *, const void *, size_t);
int (*sha256final)(archive_sha256_ctx *, void *);
int (*sha384init)(archive_sha384_ctx *);
int (*sha384update)(archive_sha384_ctx *, const void *, size_t);
int (*sha384final)(archive_sha384_ctx *, void *);
int (*sha512init)(archive_sha512_ctx *);
int (*sha512update)(archive_sha512_ctx *, const void *, size_t);
int (*sha512final)(archive_sha512_ctx *, void *);
};
extern const struct archive_crypto __archive_crypto;
#endif

View File

@ -1,4 +1,5 @@
.\" Copyright (c) 2003-2007 Tim Kientzle .\" Copyright (c) 2003-2007 Tim Kientzle
.\" Copyright (c) 2010 Joerg Sonnenberger
.\" All rights reserved. .\" All rights reserved.
.\" .\"
.\" Redistribution and use in source and binary forms, with or without .\" Redistribution and use in source and binary forms, with or without
@ -24,267 +25,25 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd May 12, 2008 .Dd Feburary 22, 2010
.Dt ARCHIVE_ENTRY 3 .Dt ARCHIVE_ENTRY 3
.Os .Os
.Sh NAME .Sh NAME
.Nm archive_entry_acl_add_entry ,
.Nm archive_entry_acl_add_entry_w ,
.Nm archive_entry_acl_clear ,
.Nm archive_entry_acl_count ,
.Nm archive_entry_acl_next ,
.Nm archive_entry_acl_next_w ,
.Nm archive_entry_acl_reset ,
.Nm archive_entry_acl_text_w ,
.Nm archive_entry_atime ,
.Nm archive_entry_atime_nsec ,
.Nm archive_entry_clear , .Nm archive_entry_clear ,
.Nm archive_entry_clone , .Nm archive_entry_clone ,
.Nm archive_entry_copy_fflags_text ,
.Nm archive_entry_copy_fflags_text_w ,
.Nm archive_entry_copy_gname ,
.Nm archive_entry_copy_gname_w ,
.Nm archive_entry_copy_hardlink ,
.Nm archive_entry_copy_hardlink_w ,
.Nm archive_entry_copy_link ,
.Nm archive_entry_copy_link_w ,
.Nm archive_entry_copy_pathname_w ,
.Nm archive_entry_copy_sourcepath ,
.Nm archive_entry_copy_stat ,
.Nm archive_entry_copy_symlink ,
.Nm archive_entry_copy_symlink_w ,
.Nm archive_entry_copy_uname ,
.Nm archive_entry_copy_uname_w ,
.Nm archive_entry_dev ,
.Nm archive_entry_devmajor ,
.Nm archive_entry_devminor ,
.Nm archive_entry_filetype ,
.Nm archive_entry_fflags ,
.Nm archive_entry_fflags_text ,
.Nm archive_entry_free , .Nm archive_entry_free ,
.Nm archive_entry_gid ,
.Nm archive_entry_gname ,
.Nm archive_entry_hardlink ,
.Nm archive_entry_ino ,
.Nm archive_entry_mode ,
.Nm archive_entry_mtime ,
.Nm archive_entry_mtime_nsec ,
.Nm archive_entry_nlink ,
.Nm archive_entry_new , .Nm archive_entry_new ,
.Nm archive_entry_pathname , .Nd functions for managing archive entry descriptions
.Nm archive_entry_pathname_w ,
.Nm archive_entry_rdev ,
.Nm archive_entry_rdevmajor ,
.Nm archive_entry_rdevminor ,
.Nm archive_entry_set_atime ,
.Nm archive_entry_set_ctime ,
.Nm archive_entry_set_dev ,
.Nm archive_entry_set_devmajor ,
.Nm archive_entry_set_devminor ,
.Nm archive_entry_set_filetype ,
.Nm archive_entry_set_fflags ,
.Nm archive_entry_set_gid ,
.Nm archive_entry_set_gname ,
.Nm archive_entry_set_hardlink ,
.Nm archive_entry_set_link ,
.Nm archive_entry_set_mode ,
.Nm archive_entry_set_mtime ,
.Nm archive_entry_set_pathname ,
.Nm archive_entry_set_rdevmajor ,
.Nm archive_entry_set_rdevminor ,
.Nm archive_entry_set_size ,
.Nm archive_entry_set_symlink ,
.Nm archive_entry_set_uid ,
.Nm archive_entry_set_uname ,
.Nm archive_entry_size ,
.Nm archive_entry_sourcepath ,
.Nm archive_entry_stat ,
.Nm archive_entry_symlink ,
.Nm archive_entry_uid ,
.Nm archive_entry_uname
.Nd functions for manipulating archive entry descriptions
.Sh SYNOPSIS .Sh SYNOPSIS
.In archive_entry.h .In archive_entry.h
.Ft void
.Fo archive_entry_acl_add_entry
.Fa "struct archive_entry *"
.Fa "int type"
.Fa "int permset"
.Fa "int tag"
.Fa "int qual"
.Fa "const char *name"
.Fc
.Ft void
.Fo archive_entry_acl_add_entry_w
.Fa "struct archive_entry *"
.Fa "int type"
.Fa "int permset"
.Fa "int tag"
.Fa "int qual"
.Fa "const wchar_t *name"
.Fc
.Ft void
.Fn archive_entry_acl_clear "struct archive_entry *"
.Ft int
.Fn archive_entry_acl_count "struct archive_entry *" "int type"
.Ft int
.Fo archive_entry_acl_next
.Fa "struct archive_entry *"
.Fa "int want_type"
.Fa "int *type"
.Fa "int *permset"
.Fa "int *tag"
.Fa "int *qual"
.Fa "const char **name"
.Fc
.Ft int
.Fo archive_entry_acl_next_w
.Fa "struct archive_entry *"
.Fa "int want_type"
.Fa "int *type"
.Fa "int *permset"
.Fa "int *tag"
.Fa "int *qual"
.Fa "const wchar_t **name"
.Fc
.Ft int
.Fn archive_entry_acl_reset "struct archive_entry *" "int want_type"
.Ft const wchar_t *
.Fn archive_entry_acl_text_w "struct archive_entry *" "int flags"
.Ft time_t
.Fn archive_entry_atime "struct archive_entry *"
.Ft long
.Fn archive_entry_atime_nsec "struct archive_entry *"
.Ft "struct archive_entry *" .Ft "struct archive_entry *"
.Fn archive_entry_clear "struct archive_entry *" .Fn archive_entry_clear "struct archive_entry *"
.Ft struct archive_entry * .Ft struct archive_entry *
.Fn archive_entry_clone "struct archive_entry *" .Fn archive_entry_clone "struct archive_entry *"
.Ft const char * *
.Fn archive_entry_copy_fflags_text_w "struct archive_entry *" "const char *"
.Ft const wchar_t *
.Fn archive_entry_copy_fflags_text_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_gname "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_copy_gname_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_hardlink "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_copy_hardlink_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_sourcepath "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_copy_pathname_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_stat "struct archive_entry *" "const struct stat *"
.Ft void
.Fn archive_entry_copy_symlink "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_copy_symlink_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_uname "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_copy_uname_w "struct archive_entry *" "const wchar_t *"
.Ft dev_t
.Fn archive_entry_dev "struct archive_entry *"
.Ft dev_t
.Fn archive_entry_devmajor "struct archive_entry *"
.Ft dev_t
.Fn archive_entry_devminor "struct archive_entry *"
.Ft mode_t
.Fn archive_entry_filetype "struct archive_entry *"
.Ft void
.Fo archive_entry_fflags
.Fa "struct archive_entry *"
.Fa "unsigned long *set"
.Fa "unsigned long *clear"
.Fc
.Ft const char *
.Fn archive_entry_fflags_text "struct archive_entry *"
.Ft void .Ft void
.Fn archive_entry_free "struct archive_entry *" .Fn archive_entry_free "struct archive_entry *"
.Ft const char *
.Fn archive_entry_gname "struct archive_entry *"
.Ft const char *
.Fn archive_entry_hardlink "struct archive_entry *"
.Ft ino_t
.Fn archive_entry_ino "struct archive_entry *"
.Ft mode_t
.Fn archive_entry_mode "struct archive_entry *"
.Ft time_t
.Fn archive_entry_mtime "struct archive_entry *"
.Ft long
.Fn archive_entry_mtime_nsec "struct archive_entry *"
.Ft unsigned int
.Fn archive_entry_nlink "struct archive_entry *"
.Ft struct archive_entry * .Ft struct archive_entry *
.Fn archive_entry_new "void" .Fn archive_entry_new "void"
.Ft const char *
.Fn archive_entry_pathname "struct archive_entry *"
.Ft const wchar_t *
.Fn archive_entry_pathname_w "struct archive_entry *"
.Ft dev_t
.Fn archive_entry_rdev "struct archive_entry *"
.Ft dev_t
.Fn archive_entry_rdevmajor "struct archive_entry *"
.Ft dev_t
.Fn archive_entry_rdevminor "struct archive_entry *"
.Ft void
.Fn archive_entry_set_dev "struct archive_entry *" "dev_t"
.Ft void
.Fn archive_entry_set_devmajor "struct archive_entry *" "dev_t"
.Ft void
.Fn archive_entry_set_devminor "struct archive_entry *" "dev_t"
.Ft void
.Fn archive_entry_set_filetype "struct archive_entry *" "unsigned int"
.Ft void
.Fo archive_entry_set_fflags
.Fa "struct archive_entry *"
.Fa "unsigned long set"
.Fa "unsigned long clear"
.Fc
.Ft void
.Fn archive_entry_set_gid "struct archive_entry *" "gid_t"
.Ft void
.Fn archive_entry_set_gname "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_set_hardlink "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_set_ino "struct archive_entry *" "unsigned long"
.Ft void
.Fn archive_entry_set_link "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_set_mode "struct archive_entry *" "mode_t"
.Ft void
.Fn archive_entry_set_mtime "struct archive_entry *" "time_t" "long nanos"
.Ft void
.Fn archive_entry_set_nlink "struct archive_entry *" "unsigned int"
.Ft void
.Fn archive_entry_set_pathname "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_set_rdev "struct archive_entry *" "dev_t"
.Ft void
.Fn archive_entry_set_rdevmajor "struct archive_entry *" "dev_t"
.Ft void
.Fn archive_entry_set_rdevminor "struct archive_entry *" "dev_t"
.Ft void
.Fn archive_entry_set_size "struct archive_entry *" "int64_t"
.Ft void
.Fn archive_entry_set_symlink "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_set_uid "struct archive_entry *" "uid_t"
.Ft void
.Fn archive_entry_set_uname "struct archive_entry *" "const char *"
.Ft int64_t
.Fn archive_entry_size "struct archive_entry *"
.Ft const char *
.Fn archive_entry_sourcepath "struct archive_entry *"
.Ft const struct stat *
.Fn archive_entry_stat "struct archive_entry *"
.Ft const char *
.Fn archive_entry_symlink "struct archive_entry *"
.Ft const char *
.Fn archive_entry_uname "struct archive_entry *"
.Sh DESCRIPTION .Sh DESCRIPTION
These functions create and manipulate data objects that These functions create and manipulate data objects that
represent entries within an archive. represent entries within an archive.
@ -320,8 +79,24 @@ Allocate and return a blank
.Tn struct archive_entry .Tn struct archive_entry
object. object.
.El .El
.Ss Set and Get Functions .Ss Function groups
Most of the functions here set or read entries in an object. Due to high number of functions, the accessor functions can be found in
man pages grouped by the purpose.
.Bl -tag -width ".Xr archive_entry_perms 3"
.It Xr archive_entry_acl 3
Access Control List manipulation
.It Xr archive_entry_paths 3
Path name manipulation
.It Xr archive_entry_perms 3
User, group and mode manipulation
.It Xr archive_entry_stat 3
Functions not in the other groups and copying to/from
.Vt struct stat .
.It Xr archive_entry_time 3
Time field manipulation
.El
.Pp
Most of the functions set or read entries in an object.
Such functions have one of the following forms: Such functions have one of the following forms:
.Bl -tag -compact -width indent .Bl -tag -compact -width indent
.It Fn archive_entry_set_XXXX .It Fn archive_entry_set_XXXX
@ -350,75 +125,15 @@ Similarly, if you store a wide string and then store a
narrow string for the same data, the previously-set wide string will narrow string for the same data, the previously-set wide string will
be discarded in favor of the new data. be discarded in favor of the new data.
.Pp .Pp
There are a few set/get functions that merit additional description:
.Bl -tag -compact -width indent
.It Fn archive_entry_set_link
This function sets the symlink field if it is already set.
Otherwise, it sets the hardlink field.
.El
.Ss File Flags
File flags are transparently converted between a bitmap
representation and a textual format.
For example, if you set the bitmap and ask for text, the library
will build a canonical text format.
However, if you set a text format and request a text format,
you will get back the same text, even if it is ill-formed.
If you need to canonicalize a textual flags string, you should first set the
text form, then request the bitmap form, then use that to set the bitmap form.
Setting the bitmap format will clear the internal text representation
and force it to be reconstructed when you next request the text form.
.Pp
The bitmap format consists of two integers, one containing bits
that should be set, the other specifying bits that should be
cleared.
Bits not mentioned in either bitmap will be ignored.
Usually, the bitmap of bits to be cleared will be set to zero.
In unusual circumstances, you can force a fully-specified set
of file flags by setting the bitmap of flags to clear to the complement
of the bitmap of flags to set.
(This differs from
.Xr fflagstostr 3 ,
which only includes names for set bits.)
Converting a bitmap to a textual string is a platform-specific
operation; bits that are not meaningful on the current platform
will be ignored.
.Pp
The canonical text format is a comma-separated list of flag names.
The
.Fn archive_entry_copy_fflags_text
and
.Fn archive_entry_copy_fflags_text_w
functions parse the provided text and sets the internal bitmap values.
This is a platform-specific operation; names that are not meaningful
on the current platform will be ignored.
The function returns a pointer to the start of the first name that was not
recognized, or NULL if every name was recognized.
Note that every name--including names that follow an unrecognized name--will
be evaluated, and the bitmaps will be set to reflect every name that is
recognized.
(In particular, this differs from
.Xr strtofflags 3 ,
which stops parsing at the first unrecognized name.)
.Ss ACL Handling
XXX This needs serious help.
XXX
.Pp
An
.Dq Access Control List
(ACL) is a list of permissions that grant access to particular users or
groups beyond what would normally be provided by standard POSIX mode bits.
The ACL handling here addresses some deficiencies in the POSIX.1e draft 17 ACL
specification.
In particular, POSIX.1e draft 17 specifies several different formats, but
none of those formats include both textual user/group names and numeric
UIDs/GIDs.
.Pp
XXX explain ACL stuff XXX
.\" .Sh EXAMPLE .\" .Sh EXAMPLE
.\" .Sh RETURN VALUES .\" .Sh RETURN VALUES
.\" .Sh ERRORS .\" .Sh ERRORS
.Sh SEE ALSO .Sh SEE ALSO
.Xr archive 3 .Xr archive 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_entry_paths 3 ,
.Xr archive_entry_perms 3 ,
.Xr archive_entry_time 3
.Sh HISTORY .Sh HISTORY
The The
.Nm libarchive .Nm libarchive

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,9 @@
#ifndef ARCHIVE_ENTRY_H_INCLUDED #ifndef ARCHIVE_ENTRY_H_INCLUDED
#define ARCHIVE_ENTRY_H_INCLUDED #define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
#define ARCHIVE_VERSION_NUMBER 3000003
/* /*
* Note: archive_entry.h is for use outside of libarchive; the * Note: archive_entry.h is for use outside of libarchive; the
* configuration headers (config.h, archive_platform.h, etc.) are * configuration headers (config.h, archive_platform.h, etc.) are
@ -49,30 +52,31 @@
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
#define __LA_INT64_T __int64 #define __LA_INT64_T __int64
# if defined(__BORLANDC__) # if defined(__BORLANDC__)
# define __LA_UID_T uid_t # define __LA_UID_T uid_t /* Remove in libarchive 3.2 */
# define __LA_GID_T gid_t # define __LA_GID_T gid_t /* Remove in libarchive 3.2 */
# define __LA_DEV_T dev_t # define __LA_DEV_T dev_t
# define __LA_MODE_T mode_t # define __LA_MODE_T mode_t
# else # else
# define __LA_UID_T short # define __LA_UID_T short /* Remove in libarchive 3.2 */
# define __LA_GID_T short # define __LA_GID_T short /* Remove in libarchive 3.2 */
# define __LA_DEV_T unsigned int # define __LA_DEV_T unsigned int
# define __LA_MODE_T unsigned short # define __LA_MODE_T unsigned short
# endif # endif
#else #else
#include <unistd.h> #include <unistd.h>
#define __LA_INT64_T int64_t # if defined(_SCO_DS)
#define __LA_UID_T uid_t # define __LA_INT64_T long long
#define __LA_GID_T gid_t # else
#define __LA_DEV_T dev_t # define __LA_INT64_T int64_t
#define __LA_MODE_T mode_t # endif
# define __LA_UID_T uid_t /* Remove in libarchive 3.2 */
# define __LA_GID_T gid_t /* Remove in libarchive 3.2 */
# define __LA_DEV_T dev_t
# define __LA_MODE_T mode_t
#endif #endif
/* /*
* XXX Is this defined for all Windows compilers? If so, in what * Remove this for libarchive 3.2, since ino_t is no longer used.
* header? It would be nice to remove the __LA_INO_T indirection and
* just use plain ino_t everywhere. Likewise for the other types just
* above.
*/ */
#define __LA_INO_T ino_t #define __LA_INO_T ino_t
@ -91,7 +95,7 @@
# endif # endif
# else # else
# ifdef __GNUC__ # ifdef __GNUC__
# define __LA_DECL __attribute__((dllimport)) extern # define __LA_DECL
# else # else
# define __LA_DECL __declspec(dllimport) # define __LA_DECL __declspec(dllimport)
# endif # endif
@ -121,6 +125,7 @@ extern "C" {
* applications (e.g., a package manager could attach special * applications (e.g., a package manager could attach special
* package-management attributes to each entry). * package-management attributes to each entry).
*/ */
struct archive;
struct archive_entry; struct archive_entry;
/* /*
@ -163,6 +168,15 @@ __LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *);
__LA_DECL void archive_entry_free(struct archive_entry *); __LA_DECL void archive_entry_free(struct archive_entry *);
__LA_DECL struct archive_entry *archive_entry_new(void); __LA_DECL struct archive_entry *archive_entry_new(void);
/*
* This form of archive_entry_new2() will pull character-set
* conversion information from the specified archive handle. The
* older archive_entry_new(void) form is equivalent to calling
* archive_entry_new2(NULL) and will result in the use of an internal
* default character-set conversion.
*/
__LA_DECL struct archive_entry *archive_entry_new2(struct archive *);
/* /*
* Retrieve fields from an archive_entry. * Retrieve fields from an archive_entry.
* *
@ -192,6 +206,7 @@ __LA_DECL time_t archive_entry_ctime(struct archive_entry *);
__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *); __LA_DECL long archive_entry_ctime_nsec(struct archive_entry *);
__LA_DECL int archive_entry_ctime_is_set(struct archive_entry *); __LA_DECL int archive_entry_ctime_is_set(struct archive_entry *);
__LA_DECL dev_t archive_entry_dev(struct archive_entry *); __LA_DECL dev_t archive_entry_dev(struct archive_entry *);
__LA_DECL int archive_entry_dev_is_set(struct archive_entry *);
__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *); __LA_DECL dev_t archive_entry_devmajor(struct archive_entry *);
__LA_DECL dev_t archive_entry_devminor(struct archive_entry *); __LA_DECL dev_t archive_entry_devminor(struct archive_entry *);
__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *); __LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *);
@ -199,13 +214,14 @@ __LA_DECL void archive_entry_fflags(struct archive_entry *,
unsigned long * /* set */, unsigned long * /* set */,
unsigned long * /* clear */); unsigned long * /* clear */);
__LA_DECL const char *archive_entry_fflags_text(struct archive_entry *); __LA_DECL const char *archive_entry_fflags_text(struct archive_entry *);
__LA_DECL __LA_GID_T archive_entry_gid(struct archive_entry *); __LA_DECL __LA_INT64_T archive_entry_gid(struct archive_entry *);
__LA_DECL const char *archive_entry_gname(struct archive_entry *); __LA_DECL const char *archive_entry_gname(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *);
__LA_DECL const char *archive_entry_hardlink(struct archive_entry *); __LA_DECL const char *archive_entry_hardlink(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *);
__LA_DECL __LA_INO_T archive_entry_ino(struct archive_entry *); __LA_DECL __LA_INT64_T archive_entry_ino(struct archive_entry *);
__LA_DECL __LA_INT64_T archive_entry_ino64(struct archive_entry *); __LA_DECL __LA_INT64_T archive_entry_ino64(struct archive_entry *);
__LA_DECL int archive_entry_ino_is_set(struct archive_entry *);
__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *); __LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *);
__LA_DECL time_t archive_entry_mtime(struct archive_entry *); __LA_DECL time_t archive_entry_mtime(struct archive_entry *);
__LA_DECL long archive_entry_mtime_nsec(struct archive_entry *); __LA_DECL long archive_entry_mtime_nsec(struct archive_entry *);
@ -213,35 +229,34 @@ __LA_DECL int archive_entry_mtime_is_set(struct archive_entry *);
__LA_DECL unsigned int archive_entry_nlink(struct archive_entry *); __LA_DECL unsigned int archive_entry_nlink(struct archive_entry *);
__LA_DECL const char *archive_entry_pathname(struct archive_entry *); __LA_DECL const char *archive_entry_pathname(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *);
__LA_DECL __LA_MODE_T archive_entry_perm(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdev(struct archive_entry *); __LA_DECL dev_t archive_entry_rdev(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *); __LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *);
__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *); __LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *);
__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *); __LA_DECL const char *archive_entry_sourcepath(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_sourcepath_w(struct archive_entry *);
__LA_DECL __LA_INT64_T archive_entry_size(struct archive_entry *); __LA_DECL __LA_INT64_T archive_entry_size(struct archive_entry *);
__LA_DECL int archive_entry_size_is_set(struct archive_entry *); __LA_DECL int archive_entry_size_is_set(struct archive_entry *);
__LA_DECL const char *archive_entry_strmode(struct archive_entry *); __LA_DECL const char *archive_entry_strmode(struct archive_entry *);
__LA_DECL const char *archive_entry_symlink(struct archive_entry *); __LA_DECL const char *archive_entry_symlink(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *);
__LA_DECL __LA_UID_T archive_entry_uid(struct archive_entry *); __LA_DECL __LA_INT64_T archive_entry_uid(struct archive_entry *);
__LA_DECL const char *archive_entry_uname(struct archive_entry *); __LA_DECL const char *archive_entry_uname(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *); __LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *);
/* /*
* Set fields in an archive_entry. * Set fields in an archive_entry.
* *
* Note that string 'set' functions do not copy the string, only the pointer. * Note: Before libarchive 2.4, there were 'set' and 'copy' versions
* In contrast, 'copy' functions do copy the object pointed to. * of the string setters. 'copy' copied the actual string, 'set' just
* * stored the pointer. In libarchive 2.4 and later, strings are
* Note: As of libarchive 2.4, 'set' functions do copy the string and * always copied.
* are therefore exact synonyms for the 'copy' versions. The 'copy'
* names will be retired in libarchive 3.0.
*/ */
__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long); __LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_unset_atime(struct archive_entry *); __LA_DECL void archive_entry_unset_atime(struct archive_entry *);
#if defined(_WIN32) && !defined(__CYGWIN__) #if defined(_WIN32) && !defined(__CYGWIN__)
__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, __LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, BY_HANDLE_FILE_INFORMATION *);
BY_HANDLE_FILE_INFORMATION *);
#endif #endif
__LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long); __LA_DECL void archive_entry_set_birthtime(struct archive_entry *, time_t, long);
__LA_DECL void archive_entry_unset_birthtime(struct archive_entry *); __LA_DECL void archive_entry_unset_birthtime(struct archive_entry *);
@ -259,7 +274,7 @@ __LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *,
const char *); const char *);
__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *, __LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *,
const wchar_t *); const wchar_t *);
__LA_DECL void archive_entry_set_gid(struct archive_entry *, __LA_GID_T); __LA_DECL void archive_entry_set_gid(struct archive_entry *, __LA_INT64_T);
__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *); __LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *); __LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
@ -268,12 +283,7 @@ __LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *); __LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *); __LA_DECL int archive_entry_update_hardlink_utf8(struct archive_entry *, const char *);
#if ARCHIVE_VERSION_NUMBER >= 3000000
/* Starting with libarchive 3.0, this will be synonym for ino64. */
__LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T); __LA_DECL void archive_entry_set_ino(struct archive_entry *, __LA_INT64_T);
#else
__LA_DECL void archive_entry_set_ino(struct archive_entry *, unsigned long);
#endif
__LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INT64_T); __LA_DECL void archive_entry_set_ino64(struct archive_entry *, __LA_INT64_T);
__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *); __LA_DECL void archive_entry_set_link(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *);
@ -294,11 +304,12 @@ __LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t);
__LA_DECL void archive_entry_set_size(struct archive_entry *, __LA_INT64_T); __LA_DECL void archive_entry_set_size(struct archive_entry *, __LA_INT64_T);
__LA_DECL void archive_entry_unset_size(struct archive_entry *); __LA_DECL void archive_entry_unset_size(struct archive_entry *);
__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_sourcepath_w(struct archive_entry *, const wchar_t *);
__LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *); __LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *); __LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *);
__LA_DECL int archive_entry_update_symlink_utf8(struct archive_entry *, const char *); __LA_DECL int archive_entry_update_symlink_utf8(struct archive_entry *, const char *);
__LA_DECL void archive_entry_set_uid(struct archive_entry *, __LA_UID_T); __LA_DECL void archive_entry_set_uid(struct archive_entry *, __LA_INT64_T);
__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *); __LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *); __LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *);
__LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *); __LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
@ -315,6 +326,15 @@ __LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char
__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *); __LA_DECL const struct stat *archive_entry_stat(struct archive_entry *);
__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *); __LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
/*
* Storage for Mac OS-specific AppleDouble metadata information.
* Apple-format tar files store a separate binary blob containing
* encoded metadata with ACL, extended attributes, etc.
* This provides a place to store that blob.
*/
__LA_DECL const void * archive_entry_mac_metadata(struct archive_entry *, size_t *);
__LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const void *, size_t);
/* /*
* ACL routines. This used to simply store and return text-format ACL * ACL routines. This used to simply store and return text-format ACL
@ -326,32 +346,95 @@ __LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat
* *
* This last point, in particular, forces me to implement a reasonably * This last point, in particular, forces me to implement a reasonably
* complete set of ACL support routines. * complete set of ACL support routines.
*
* TODO: Extend this to support NFSv4/NTFS permissions. That should
* allow full ACL support on Mac OS, in particular, which uses
* POSIX.1e-style interfaces to manipulate NFSv4/NTFS permissions.
*/ */
/* /*
* Permission bits mimic POSIX.1e. Note that I've not followed POSIX.1e's * Permission bits.
* "permset"/"perm" abstract type nonsense. A permset is just a simple
* bitmap, following long-standing Unix tradition.
*/ */
#define ARCHIVE_ENTRY_ACL_EXECUTE 1 #define ARCHIVE_ENTRY_ACL_EXECUTE 0x00000001
#define ARCHIVE_ENTRY_ACL_WRITE 2 #define ARCHIVE_ENTRY_ACL_WRITE 0x00000002
#define ARCHIVE_ENTRY_ACL_READ 4 #define ARCHIVE_ENTRY_ACL_READ 0x00000004
#define ARCHIVE_ENTRY_ACL_READ_DATA 0x00000008
#define ARCHIVE_ENTRY_ACL_LIST_DIRECTORY 0x00000008
#define ARCHIVE_ENTRY_ACL_WRITE_DATA 0x00000010
#define ARCHIVE_ENTRY_ACL_ADD_FILE 0x00000010
#define ARCHIVE_ENTRY_ACL_APPEND_DATA 0x00000020
#define ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY 0x00000020
#define ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS 0x00000040
#define ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS 0x00000080
#define ARCHIVE_ENTRY_ACL_DELETE_CHILD 0x00000100
#define ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES 0x00000200
#define ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES 0x00000400
#define ARCHIVE_ENTRY_ACL_DELETE 0x00000800
#define ARCHIVE_ENTRY_ACL_READ_ACL 0x00001000
#define ARCHIVE_ENTRY_ACL_WRITE_ACL 0x00002000
#define ARCHIVE_ENTRY_ACL_WRITE_OWNER 0x00004000
#define ARCHIVE_ENTRY_ACL_SYNCHRONIZE 0x00008000
/* We need to be able to specify either or both of these. */ #define ARCHIVE_ENTRY_ACL_PERMS_POSIX1E \
#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 256 (ARCHIVE_ENTRY_ACL_EXECUTE \
#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 512 | ARCHIVE_ENTRY_ACL_WRITE \
| ARCHIVE_ENTRY_ACL_READ)
#define ARCHIVE_ENTRY_ACL_PERMS_NFS4 \
(ARCHIVE_ENTRY_ACL_EXECUTE \
| ARCHIVE_ENTRY_ACL_READ_DATA \
| ARCHIVE_ENTRY_ACL_LIST_DIRECTORY \
| ARCHIVE_ENTRY_ACL_WRITE_DATA \
| ARCHIVE_ENTRY_ACL_ADD_FILE \
| ARCHIVE_ENTRY_ACL_APPEND_DATA \
| ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY \
| ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS \
| ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS \
| ARCHIVE_ENTRY_ACL_DELETE_CHILD \
| ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES \
| ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES \
| ARCHIVE_ENTRY_ACL_DELETE \
| ARCHIVE_ENTRY_ACL_READ_ACL \
| ARCHIVE_ENTRY_ACL_WRITE_ACL \
| ARCHIVE_ENTRY_ACL_WRITE_OWNER \
| ARCHIVE_ENTRY_ACL_SYNCHRONIZE)
/*
* Inheritance values (NFS4 ACLs only); included in permset.
*/
#define ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT 0x02000000
#define ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT 0x04000000
#define ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT 0x08000000
#define ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY 0x10000000
#define ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS 0x20000000
#define ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS 0x40000000
#define ARCHIVE_ENTRY_ACL_INHERITANCE_NFS4 \
(ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT \
| ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT \
| ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT \
| ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY \
| ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS \
| ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS)
/* We need to be able to specify combinations of these. */
#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 256 /* POSIX.1e only */
#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 512 /* POSIX.1e only */
#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 1024 /* NFS4 only */
#define ARCHIVE_ENTRY_ACL_TYPE_DENY 2048 /* NFS4 only */
#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 4096 /* NFS4 only */
#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 8192 /* NFS4 only */
#define ARCHIVE_ENTRY_ACL_TYPE_POSIX1E (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \
| ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
#define ARCHIVE_ENTRY_ACL_TYPE_NFS4 (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \
| ARCHIVE_ENTRY_ACL_TYPE_DENY \
| ARCHIVE_ENTRY_ACL_TYPE_AUDIT \
| ARCHIVE_ENTRY_ACL_TYPE_ALARM)
/* Tag values mimic POSIX.1e */ /* Tag values mimic POSIX.1e */
#define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */ #define ARCHIVE_ENTRY_ACL_USER 10001 /* Specified user. */
#define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */ #define ARCHIVE_ENTRY_ACL_USER_OBJ 10002 /* User who owns the file. */
#define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */ #define ARCHIVE_ENTRY_ACL_GROUP 10003 /* Specified group. */
#define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */ #define ARCHIVE_ENTRY_ACL_GROUP_OBJ 10004 /* Group who owns the file. */
#define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access. */ #define ARCHIVE_ENTRY_ACL_MASK 10005 /* Modify group access (POSIX.1e only) */
#define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public. */ #define ARCHIVE_ENTRY_ACL_OTHER 10006 /* Public (POSIX.1e only) */
#define ARCHIVE_ENTRY_ACL_EVERYONE 10107 /* Everyone (NFS4 only) */
/* /*
* Set the ACL by clearing it and adding entries one at a time. * Set the ACL by clearing it and adding entries one at a time.
@ -363,17 +446,17 @@ __LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat
* default and access information in a single ACL list. * default and access information in a single ACL list.
*/ */
__LA_DECL void archive_entry_acl_clear(struct archive_entry *); __LA_DECL void archive_entry_acl_clear(struct archive_entry *);
__LA_DECL void archive_entry_acl_add_entry(struct archive_entry *, __LA_DECL int archive_entry_acl_add_entry(struct archive_entry *,
int /* type */, int /* permset */, int /* tag */, int /* type */, int /* permset */, int /* tag */,
int /* qual */, const char * /* name */); int /* qual */, const char * /* name */);
__LA_DECL void archive_entry_acl_add_entry_w(struct archive_entry *, __LA_DECL int archive_entry_acl_add_entry_w(struct archive_entry *,
int /* type */, int /* permset */, int /* tag */, int /* type */, int /* permset */, int /* tag */,
int /* qual */, const wchar_t * /* name */); int /* qual */, const wchar_t * /* name */);
/* /*
* To retrieve the ACL, first "reset", then repeatedly ask for the * To retrieve the ACL, first "reset", then repeatedly ask for the
* "next" entry. The want_type parameter allows you to request only * "next" entry. The want_type parameter allows you to request only
* access entries or only default entries. * certain types of entries.
*/ */
__LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */); __LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */);
__LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */, __LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */,
@ -387,36 +470,29 @@ __LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type
* Construct a text-format ACL. The flags argument is a bitmask that * Construct a text-format ACL. The flags argument is a bitmask that
* can include any of the following: * can include any of the following:
* *
* ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include access entries. * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries.
* ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include default entries. * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries.
* ARCHIVE_ENTRY_ACL_TYPE_NFS4 - Include NFS4 entries.
* ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
* each ACL entry. (As used by 'star'.) * each ACL entry. ('star' introduced this for POSIX.1e, this flag
* also applies to NFS4.)
* ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
* default ACL entry. * default ACL entry, as used in old Solaris ACLs.
*/ */
#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024 #define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048 #define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *, __LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
int /* flags */); int /* flags */);
__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
int /* flags */);
/* Return a count of entries matching 'want_type' */ /* Return a count of entries matching 'want_type' */
__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */); __LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */);
/* /* Return an opaque ACL object. */
* Private ACL parser. This is private because it handles some /* There's not yet anything clients can actually do with this... */
* very weird formats that clients should not be messing with. struct archive_acl;
* Clients should only deal with their platform-native formats. __LA_DECL struct archive_acl *archive_entry_acl(struct archive_entry *);
* Because of the need to support many formats cleanly, new arguments
* are likely to get added on a regular basis. Clients who try to use
* this interface are likely to be surprised when it changes.
*
* You were warned!
*
* TODO: Move this declaration out of the public header and into
* a private header. Warnings above are silly.
*/
__LA_DECL int __archive_entry_acl_parse_w(struct archive_entry *,
const wchar_t *, int /* type */);
/* /*
* extended attributes * extended attributes
@ -437,6 +513,24 @@ __LA_DECL int archive_entry_xattr_reset(struct archive_entry *);
__LA_DECL int archive_entry_xattr_next(struct archive_entry *, __LA_DECL int archive_entry_xattr_next(struct archive_entry *,
const char ** /* name */, const void ** /* value */, size_t *); const char ** /* name */, const void ** /* value */, size_t *);
/*
* sparse
*/
__LA_DECL void archive_entry_sparse_clear(struct archive_entry *);
__LA_DECL void archive_entry_sparse_add_entry(struct archive_entry *,
__LA_INT64_T /* offset */, __LA_INT64_T /* length */);
/*
* To retrieve the xattr list, first "reset", then repeatedly ask for the
* "next" entry.
*/
__LA_DECL int archive_entry_sparse_count(struct archive_entry *);
__LA_DECL int archive_entry_sparse_reset(struct archive_entry *);
__LA_DECL int archive_entry_sparse_next(struct archive_entry *,
__LA_INT64_T * /* offset */, __LA_INT64_T * /* length */);
/* /*
* Utility to match up hardlinks. * Utility to match up hardlinks.
* *
@ -449,7 +543,7 @@ __LA_DECL int archive_entry_xattr_next(struct archive_entry *,
* be written. * be written.
* 4. Call archive_entry_linkify(resolver, NULL) until * 4. Call archive_entry_linkify(resolver, NULL) until
* no more entries are returned. * no more entries are returned.
* 5. Call archive_entry_link_resolver_free(resolver) to free resources. * 5. Call archive_entry_linkresolver_free(resolver) to free resources.
* *
* The entries returned have their hardlink and size fields updated * The entries returned have their hardlink and size fields updated
* appropriately. If an entry is passed in that does not refer to * appropriately. If an entry is passed in that does not refer to
@ -499,7 +593,7 @@ struct archive_entry_linkresolver;
* linkify(l2) => l1 * linkify(l2) => l1
* linkify(NULL) => l2 (at end, you retrieve remaining links) * linkify(NULL) => l2 (at end, you retrieve remaining links)
* As the name suggests, this strategy is used by newer cpio variants. * As the name suggests, this strategy is used by newer cpio variants.
* It's noticably more complex for the archiver, slightly more complex * It's noticeably more complex for the archiver, slightly more complex
* for the dearchiver than the tar strategy, but makes it straightforward * for the dearchiver than the tar strategy, but makes it straightforward
* to restore a file using any link by simply continuing to scan until * to restore a file using any link by simply continuing to scan until
* you see a link that is stored with a body. In contrast, the tar * you see a link that is stored with a body. In contrast, the tar
@ -513,6 +607,8 @@ __LA_DECL void archive_entry_linkresolver_set_strategy(
__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *); __LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *);
__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *, __LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *,
struct archive_entry **, struct archive_entry **); struct archive_entry **, struct archive_entry **);
__LA_DECL struct archive_entry *archive_entry_partial_links(
struct archive_entry_linkresolver *res, unsigned int *links);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -0,0 +1,233 @@
.\" Copyright (c) 2010 Joerg Sonnenberger
.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
.\"
.Dd February 21, 2010
.Dt ARCHIVE_ENTRY_ACL 3
.Os
.Sh NAME
.Nm archive_entry_acl_add_entry ,
.Nm archive_entry_acl_add_entry_w ,
.Nm archive_entry_acl_clear ,
.Nm archive_entry_acl_count ,
.Nm archive_entry_acl_next ,
.Nm archive_entry_acl_next_w ,
.Nm archive_entry_acl_reset ,
.Nm archive_entry_acl_text_w
.Nd functions for manipulating Access Control Lists in archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft void
.Fo archive_entry_acl_add_entry
.Fa "struct archive_entry *a"
.Fa "int type"
.Fa "int permset"
.Fa "int tag"
.Fa "int qualifier"
.Fa "const char *name"
.Fc
.Ft void
.Fo archive_entry_acl_add_entry_w
.Fa "struct archive_entry *a"
.Fa "int type"
.Fa "int permset"
.Fa "int tag"
.Fa "int qualifier"
.Fa "const wchar_t *name"
.Fc
.Ft void
.Fn archive_entry_acl_clear "struct archive_entry *a"
.Ft int
.Fn archive_entry_acl_count "struct archive_entry *a" "int type"
.Ft int
.Fo archive_entry_acl_next
.Fa "struct archive_entry *a"
.Fa "int type"
.Fa "int *ret_type"
.Fa "int *ret_permset"
.Fa "int *ret_tag"
.Fa "int *ret_qual"
.Fa "const char **ret_name"
.Fc
.Ft int
.Fo archive_entry_acl_next_w
.Fa "struct archive_entry *a"
.Fa "int type"
.Fa "int *ret_type"
.Fa "int *ret_permset"
.Fa "int *ret_tag"
.Fa "int *ret_qual"
.Fa "const wchar_t **ret_name"
.Fc
.Ft int
.Fn archive_entry_acl_reset "struct archive_entry *a" "int type"
.Ft const wchar_t *
.Fn archive_entry_acl_text_w "struct archive_entry *a" "int flags"
.\" enum?
.Sh DESCRIPTION
An
.Dq Access Control List
is a generalisation of the classic Unix permission system.
The ACL interface of
.Nm libarchive
is derived from the POSIX.1e draft, but restricted to simplify dealing
with practical implementations in various Operating Systems and archive formats.
.Pp
An ACL consists of a number of independent entries.
Each entry specifies the permission set as bitmask of basic permissions.
Valid permissions are:
.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_EXECUTE"
.It Dv ARCHIVE_ENTRY_ACL_EXECUTE
.It Dv ARCHIVE_ENTRY_ACL_WRITE
.It Dv ARCHIVE_ENTRY_ACL_READ
.El
The permissions correspond to the normal Unix permissions.
.Pp
The tag specifies the principal to which the permission applies.
Valid values are:
.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
.It Dv ARCHIVE_ENTRY_ACL_USER
The user specified by the name field.
.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ
The owner of the file.
.It Dv ARCHIVE_ENTRY_ACL_GROUP
The group specied by the name field.
.It Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
The group who owns the file.
.It Dv ARCHIVE_ENTRY_ACL_MASK
The maximum permissions to be obtained via group permissions.
.It Dv ARCHIVE_ENTRY_ACL_OTHER
Any principal who doesn't have a user or group entry.
.El
The principals
.Dv ARCHIVE_ENTRY_ACL_USER_OBJ ,
.Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
and
.Dv ARCHIVE_ENTRY_ACL_OTHER
are equivalent to user, group and other in the classic Unix permission
model and specify non-extended ACL entries.
.Pp
All files have an access ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS .
This specifies the permissions required for access to the file itself.
Directories have an additional ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT ,
which controls the initial access ACL for newly created directory entries.
.Pp
.Fn archive_entry_acl_add_entry
and
.Fn archive_entry_acl_add_entry_w
add a single ACL entry.
For the access ACL and non-extended principals, the classic Unix permissions
are updated.
.Pp
.Fn archive_entry_acl_clear
removes all ACL entries and resets the enumeration pointer.
.Pp
.Fn archive_entry_acl_count
counts the ACL entries that have the given type mask.
.Fa type
can be the bitwise-or of
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
and
.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT .
If
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
is included and at least one extended ACL entry is found,
the three non-extened ACLs are added.
.Pp
.Fn archive_entry_acl_next
and
.Fn archive_entry_acl_next_w
return the next entry of the ACL list.
This functions may only be called after
.Fn archive_entry_acl_reset
has indicated the presence of extended ACL entries.
.Pp
.Fn archive_entry_acl_reset
prepare reading the list of ACL entries with
.Fn archive_entry_acl_next
or
.Fn archive_entry_acl_next_w .
The function returns either 0, if no non-extended ACLs are found.
In this case, the access permissions should be obtained by
.Xr archive_entry_mode 3
or set using
.Xr chmod 2 .
Otherwise, the function returns the same value as
.Fn archive_entry_acl_count .
.Pp
.Fn archive_entry_acl_text_w
converts the ACL entries for the given type mask into a wide string.
In addition to the normal type flags,
.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
and
.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
can be specified to further customize the result.
The returned long string is valid until the next call to
.Fn archive_entry_acl_clear ,
.Fn archive_entry_acl_add_entry ,
.Fn archive_entry_acl_add_entry_w
or
.Fn archive_entry_acl_text_w .
.Sh RETURN VALUES
.Fn archive_entry_acl_count
and
.Fn archive_entry_acl_reset
returns the number of ACL entries that match the given type mask.
If the type mask includes
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
and at least one extended ACL entry exists, the three classic Unix
permissions are counted.
.Pp
.Fn archive_entry_acl_next
and
.Fn archive_entry_acl_next_w
return
.Dv ARCHIVE_OK
on success,
.Dv ARCHIVE_EOF
if no more ACL entries exist
and
.Dv ARCHIVE_WARN
if
.Fn archive_entry_acl_reset
has not been called first.
.Pp
.Fn archive_entry_text_w
returns a wide string representation of the ACL entrise matching the
given type mask.
The returned long string is valid until the next call to
.Fn archive_entry_acl_clear ,
.Fn archive_entry_acl_add_entry ,
.Fn archive_entry_acl_add_entry_w
or
.Fn archive_entry_acl_text_w .
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry 3
.Sh BUGS
.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
and
.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
are not documented.

View File

@ -30,6 +30,7 @@ __FBSDID("$FreeBSD$");
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
#include "archive.h"
#include "archive_entry.h" #include "archive_entry.h"
void void
@ -59,12 +60,13 @@ archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
archive_entry_set_atime(entry, st->st_atime, 0); archive_entry_set_atime(entry, st->st_atime, 0);
archive_entry_set_ctime(entry, st->st_ctime, 0); archive_entry_set_ctime(entry, st->st_ctime, 0);
archive_entry_set_mtime(entry, st->st_mtime, 0); archive_entry_set_mtime(entry, st->st_mtime, 0);
#if HAVE_STRUCT_STAT_ST_BIRTHTIME
archive_entry_set_birthtime(entry, st->st_birthtime, 0);
#endif
#endif #endif
#if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC #if HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC
archive_entry_set_birthtime(entry, st->st_birthtime, st->st_birthtimespec.tv_nsec); archive_entry_set_birthtime(entry, st->st_birthtime, st->st_birthtimespec.tv_nsec);
#elif HAVE_STRUCT_STAT_ST_BIRTHTIME
archive_entry_set_birthtime(entry, st->st_birthtime, 0);
#else
archive_entry_unset_birthtime(entry);
#endif #endif
archive_entry_set_dev(entry, st->st_dev); archive_entry_set_dev(entry, st->st_dev);
archive_entry_set_gid(entry, st->st_gid); archive_entry_set_gid(entry, st->st_gid);

View File

@ -70,10 +70,10 @@ __FBSDID("$FreeBSD$");
struct links_entry { struct links_entry {
struct links_entry *next; struct links_entry *next;
struct links_entry *previous; struct links_entry *previous;
int links; /* # links not yet seen */
int hash;
struct archive_entry *canonical; struct archive_entry *canonical;
struct archive_entry *entry; struct archive_entry *entry;
size_t hash;
unsigned int links; /* # links not yet seen */
}; };
struct archive_entry_linkresolver { struct archive_entry_linkresolver {
@ -84,32 +84,37 @@ struct archive_entry_linkresolver {
int strategy; int strategy;
}; };
#define NEXT_ENTRY_DEFERRED 1
#define NEXT_ENTRY_PARTIAL 2
#define NEXT_ENTRY_ALL (NEXT_ENTRY_DEFERRED | NEXT_ENTRY_PARTIAL)
static struct links_entry *find_entry(struct archive_entry_linkresolver *, static struct links_entry *find_entry(struct archive_entry_linkresolver *,
struct archive_entry *); struct archive_entry *);
static void grow_hash(struct archive_entry_linkresolver *); static void grow_hash(struct archive_entry_linkresolver *);
static struct links_entry *insert_entry(struct archive_entry_linkresolver *, static struct links_entry *insert_entry(struct archive_entry_linkresolver *,
struct archive_entry *); struct archive_entry *);
static struct links_entry *next_entry(struct archive_entry_linkresolver *); static struct links_entry *next_entry(struct archive_entry_linkresolver *,
int);
struct archive_entry_linkresolver * struct archive_entry_linkresolver *
archive_entry_linkresolver_new(void) archive_entry_linkresolver_new(void)
{ {
struct archive_entry_linkresolver *res; struct archive_entry_linkresolver *res;
size_t i;
res = malloc(sizeof(struct archive_entry_linkresolver)); /* Check for positive power-of-two */
if (links_cache_initial_size == 0 ||
(links_cache_initial_size & (links_cache_initial_size - 1)) != 0)
return (NULL);
res = calloc(1, sizeof(struct archive_entry_linkresolver));
if (res == NULL) if (res == NULL)
return (NULL); return (NULL);
memset(res, 0, sizeof(struct archive_entry_linkresolver));
res->number_buckets = links_cache_initial_size; res->number_buckets = links_cache_initial_size;
res->buckets = malloc(res->number_buckets * res->buckets = calloc(res->number_buckets, sizeof(res->buckets[0]));
sizeof(res->buckets[0]));
if (res->buckets == NULL) { if (res->buckets == NULL) {
free(res); free(res);
return (NULL); return (NULL);
} }
for (i = 0; i < res->number_buckets; i++)
res->buckets[i] = NULL;
return (res); return (res);
} }
@ -120,6 +125,11 @@ archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res,
int fmtbase = fmt & ARCHIVE_FORMAT_BASE_MASK; int fmtbase = fmt & ARCHIVE_FORMAT_BASE_MASK;
switch (fmtbase) { switch (fmtbase) {
case ARCHIVE_FORMAT_7ZIP:
case ARCHIVE_FORMAT_AR:
case ARCHIVE_FORMAT_ZIP:
res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO;
break;
case ARCHIVE_FORMAT_CPIO: case ARCHIVE_FORMAT_CPIO:
switch (fmt) { switch (fmt) {
case ARCHIVE_FORMAT_CPIO_SVR4_NOCRC: case ARCHIVE_FORMAT_CPIO_SVR4_NOCRC:
@ -134,11 +144,14 @@ archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res,
case ARCHIVE_FORMAT_MTREE: case ARCHIVE_FORMAT_MTREE:
res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE; res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE;
break; break;
case ARCHIVE_FORMAT_ISO9660:
case ARCHIVE_FORMAT_SHAR:
case ARCHIVE_FORMAT_TAR: case ARCHIVE_FORMAT_TAR:
case ARCHIVE_FORMAT_XAR:
res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_TAR; res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_TAR;
break; break;
default: default:
res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_TAR; res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO;
break; break;
} }
} }
@ -151,12 +164,9 @@ archive_entry_linkresolver_free(struct archive_entry_linkresolver *res)
if (res == NULL) if (res == NULL)
return; return;
if (res->buckets != NULL) { while ((le = next_entry(res, NEXT_ENTRY_ALL)) != NULL)
while ((le = next_entry(res)) != NULL) archive_entry_free(le->entry);
archive_entry_free(le->entry); free(res->buckets);
free(res->buckets);
res->buckets = NULL;
}
free(res); free(res);
} }
@ -170,7 +180,7 @@ archive_entry_linkify(struct archive_entry_linkresolver *res,
*f = NULL; /* Default: Don't return a second entry. */ *f = NULL; /* Default: Don't return a second entry. */
if (*e == NULL) { if (*e == NULL) {
le = next_entry(res); le = next_entry(res, NEXT_ENTRY_DEFERRED);
if (le != NULL) { if (le != NULL) {
*e = le->entry; *e = le->entry;
le->entry = NULL; le->entry = NULL;
@ -249,7 +259,7 @@ find_entry(struct archive_entry_linkresolver *res,
struct archive_entry *entry) struct archive_entry *entry)
{ {
struct links_entry *le; struct links_entry *le;
int hash, bucket; size_t hash, bucket;
dev_t dev; dev_t dev;
int64_t ino; int64_t ino;
@ -261,16 +271,12 @@ find_entry(struct archive_entry_linkresolver *res,
res->spare = NULL; res->spare = NULL;
} }
/* If the links cache overflowed and got flushed, don't bother. */
if (res->buckets == NULL)
return (NULL);
dev = archive_entry_dev(entry); dev = archive_entry_dev(entry);
ino = archive_entry_ino64(entry); ino = archive_entry_ino64(entry);
hash = (int)(dev ^ ino); hash = (size_t)(dev ^ ino);
/* Try to locate this entry in the links cache. */ /* Try to locate this entry in the links cache. */
bucket = hash % res->number_buckets; bucket = hash & (res->number_buckets - 1);
for (le = res->buckets[bucket]; le != NULL; le = le->next) { for (le = res->buckets[bucket]; le != NULL; le = le->next) {
if (le->hash == hash if (le->hash == hash
&& dev == archive_entry_dev(le->canonical) && dev == archive_entry_dev(le->canonical)
@ -301,7 +307,7 @@ find_entry(struct archive_entry_linkresolver *res,
} }
static struct links_entry * static struct links_entry *
next_entry(struct archive_entry_linkresolver *res) next_entry(struct archive_entry_linkresolver *res, int mode)
{ {
struct links_entry *le; struct links_entry *le;
size_t bucket; size_t bucket;
@ -309,22 +315,27 @@ next_entry(struct archive_entry_linkresolver *res)
/* Free a held entry. */ /* Free a held entry. */
if (res->spare != NULL) { if (res->spare != NULL) {
archive_entry_free(res->spare->canonical); archive_entry_free(res->spare->canonical);
archive_entry_free(res->spare->entry);
free(res->spare); free(res->spare);
res->spare = NULL; res->spare = NULL;
} }
/* If the links cache overflowed and got flushed, don't bother. */
if (res->buckets == NULL)
return (NULL);
/* Look for next non-empty bucket in the links cache. */ /* Look for next non-empty bucket in the links cache. */
for (bucket = 0; bucket < res->number_buckets; bucket++) { for (bucket = 0; bucket < res->number_buckets; bucket++) {
le = res->buckets[bucket]; for (le = res->buckets[bucket]; le != NULL; le = le->next) {
if (le != NULL) { if (le->entry != NULL &&
(mode & NEXT_ENTRY_DEFERRED) == 0)
continue;
if (le->entry == NULL &&
(mode & NEXT_ENTRY_PARTIAL) == 0)
continue;
/* Remove it from this hash bucket. */ /* Remove it from this hash bucket. */
if (le->next != NULL) if (le->next != NULL)
le->next->previous = le->previous; le->next->previous = le->previous;
res->buckets[bucket] = le->next; if (le->previous != NULL)
le->previous->next = le->next;
else
res->buckets[bucket] = le->next;
res->number_entries--; res->number_entries--;
/* Defer freeing this entry. */ /* Defer freeing this entry. */
res->spare = le; res->spare = le;
@ -339,13 +350,12 @@ insert_entry(struct archive_entry_linkresolver *res,
struct archive_entry *entry) struct archive_entry *entry)
{ {
struct links_entry *le; struct links_entry *le;
int hash, bucket; size_t hash, bucket;
/* Add this entry to the links cache. */ /* Add this entry to the links cache. */
le = malloc(sizeof(struct links_entry)); le = calloc(1, sizeof(struct links_entry));
if (le == NULL) if (le == NULL)
return (NULL); return (NULL);
memset(le, 0, sizeof(*le));
le->canonical = archive_entry_clone(entry); le->canonical = archive_entry_clone(entry);
/* If the links cache is getting too full, enlarge the hash table. */ /* If the links cache is getting too full, enlarge the hash table. */
@ -353,7 +363,7 @@ insert_entry(struct archive_entry_linkresolver *res,
grow_hash(res); grow_hash(res);
hash = archive_entry_dev(entry) ^ archive_entry_ino64(entry); hash = archive_entry_dev(entry) ^ archive_entry_ino64(entry);
bucket = hash % res->number_buckets; bucket = hash & (res->number_buckets - 1);
/* If we could allocate the entry, record it. */ /* If we could allocate the entry, record it. */
if (res->buckets[bucket] != NULL) if (res->buckets[bucket] != NULL)
@ -376,30 +386,59 @@ grow_hash(struct archive_entry_linkresolver *res)
/* Try to enlarge the bucket list. */ /* Try to enlarge the bucket list. */
new_size = res->number_buckets * 2; new_size = res->number_buckets * 2;
new_buckets = malloc(new_size * sizeof(struct links_entry *)); if (new_size < res->number_buckets)
return;
new_buckets = calloc(new_size, sizeof(struct links_entry *));
if (new_buckets != NULL) { if (new_buckets == NULL)
memset(new_buckets, 0, return;
new_size * sizeof(struct links_entry *));
for (i = 0; i < res->number_buckets; i++) {
while (res->buckets[i] != NULL) {
/* Remove entry from old bucket. */
le = res->buckets[i];
res->buckets[i] = le->next;
/* Add entry to new bucket. */ for (i = 0; i < res->number_buckets; i++) {
bucket = le->hash % new_size; while (res->buckets[i] != NULL) {
/* Remove entry from old bucket. */
le = res->buckets[i];
res->buckets[i] = le->next;
if (new_buckets[bucket] != NULL) /* Add entry to new bucket. */
new_buckets[bucket]->previous = bucket = le->hash & (new_size - 1);
le;
le->next = new_buckets[bucket]; if (new_buckets[bucket] != NULL)
le->previous = NULL; new_buckets[bucket]->previous = le;
new_buckets[bucket] = le; le->next = new_buckets[bucket];
} le->previous = NULL;
new_buckets[bucket] = le;
} }
free(res->buckets);
res->buckets = new_buckets;
res->number_buckets = new_size;
} }
free(res->buckets);
res->buckets = new_buckets;
res->number_buckets = new_size;
}
struct archive_entry *
archive_entry_partial_links(struct archive_entry_linkresolver *res,
unsigned int *links)
{
struct archive_entry *e;
struct links_entry *le;
/* Free a held entry. */
if (res->spare != NULL) {
archive_entry_free(res->spare->canonical);
archive_entry_free(res->spare->entry);
free(res->spare);
res->spare = NULL;
}
le = next_entry(res, NEXT_ENTRY_PARTIAL);
if (le != NULL) {
e = le->canonical;
if (links != NULL)
*links = le->links;
le->canonical = NULL;
} else {
e = NULL;
if (links != NULL)
*links = 0;
}
return (e);
} }

View File

@ -0,0 +1,224 @@
.\" Copyright (c) 2010 Joerg Sonnenberger
.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
.\"
.Dd February 20, 2010
.Dt ARCHIVE_ENTRY_LINKIFY 3
.Os
.Sh NAME
.Nm archive_entry_linkresolver ,
.Nm archive_entry_linkresolver_new ,
.Nm archive_entry_linkresolver_set_strategy ,
.Nm archive_entry_linkresolver_free ,
.Nm archive_entry_linkify
.Nd hardlink resolver functions
.Sh LIBRARY
.Lb libarchive
.Sh SYNOPSIS
.In archive_entry.h
.Ft struct archive_entry_linkresolver *
.Fn archive_entry_linkresolver_new void
.Ft void
.Fo archive_entry_linkresolver_set_strategy
.Fa "struct archive_entry_linkresolver *resolver"
.Fa "int format"
.Fc
.Ft void
.Fo archive_entry_linkresolver_free
.Fa "struct archive_entry_linkresolver *resolver"
.Fc
.Ft void
.Fo archive_entry_linkify
.Fa "struct archive_entry_linkresolver *resolver"
.Fa "struct archive_entry **entry"
.Fa "struct archive_entry **sparse"
.Fc
.Sh DESCRIPTION
Programs that want to create archives have to deal with hardlinks.
Hardlinks are handled in different ways by the archive formats.
The basic strategies are:
.Bl -enum
.It
Ignore hardlinks and store the body for each reference (old cpio, zip).
.It
Store the body the first time an inode is seen (ustar, pax).
.It
Store the body the last time an inode is seen (new cpio).
.El
.Pp
The
.Nm
functions help by providing a unified interface and handling the complexity
behind the scene.
.Pp
The
.Nm
functions assume that
.Vt archive_entry
instances have valid nlinks, inode and device values.
The inode and device value is used to match entries.
The nlinks value is used to determined if all references have been found and
if the internal references can be recycled.
.Pp
The
.Fn archive_entry_linkresolver_new
function allocates a new link resolver.
The instance can be freed using
.Fn archive_entry_linkresolver_free .
All deferred entries are flushed and the internal storage is freed.
.Pp
The
.Fn archive_entry_linkresolver_set_strategy
function selects the optimal hardlink strategy for the given format.
The format code can be obtained from
.Xr archive_format 3 .
The function can be called more than once, but it is recommended to
flush all deferred entries first.
.Pp
The
.Fn archive_entry_linkify
function is the core of
.Nm .
The
.Fn entry
argument points to the
.Vt archive_entry
that should be written.
Depending on the strategy one of the following actions is taken:
.Bl -enum
.It
For the simple archive formats
.Va *entry
is left unmodified and
.Va *sparse
is set to
.Dv NULL .
.It
For tar like archive formats,
.Va *sparse
is set to
.Dv NULL .
If
.Va *entry
is
.Dv NULL ,
no action is taken.
If the hardlink count of
.Va *entry
is larger than 1 and the file type is a regular file or symbolic link,
the internal list is searched for a matching inode.
If such an inode is found, the link count is decremented and the file size
of
.Va *entry
is set to 0 to notify that no body should be written.
If no such inode is found, a copy of the entry is added to the internal cache
with a link count reduced by one.
.It
For new cpio like archive formats a value for
.Va *entry
of
.Dv NULL
is used to flush deferred entries.
In that case
.Va *entry
is set to an arbitrary deferred entry and the entry itself is removed from the
internal list.
If the internal list is empty,
.Va *entry
is set to
.Dv NULL .
In either case,
.Va *sparse
is set to
.Dv NULL
and the function returns.
If the hardlink count of
.Va *entry
is one or the file type is a directory or device,
.Va *sparse
is set to
.Dv NULL
and no further action is taken.
Otherwise, the internal list is searched for a matching inode.
If such an inode is not found, the entry is added to the internal list,
both
.Va *entry
and
.Va *sparse
are set to
.Dv NULL
and the function returns.
If such an inode is found, the link count is decremented.
If it remains larger than one, the existing entry on the internal list
is swapped with
.Va *entry
after retaining the link count.
The existing entry is returned in
.Va *entry .
If the link count reached one, the new entry is also removed from the
internal list and returned in
.Va *sparse .
Otherwise
.Va *sparse
is set to
.Dv NULL .
.El
.Pp
The general usage is therefore:
.Bl -enum
.It
For each new archive entry, call
.Fn archive_entry_linkify .
.It
Keep in mind that the entries returned may have a size of 0 now.
.It
If
.Va *entry
is not
.Dv NULL ,
archive it.
.It
If
.Va *sparse
is not
.Dv NULL ,
archive it.
.It
After all entries have been written to disk, call
.Fn archive_entry_linkify
with
.Va *entry
set to
.Dv NULL
and archive the returned entry as long as it is not
.Dv NULL .
.El
.Sh RETURN VALUES
.Fn archive_entry_linkresolver_new
returns
.Dv NULL
on
.Xr malloc 3
failures.
.Sh SEE ALSO
.Xr archive_entry 3

View File

@ -0,0 +1,88 @@
/*-
* Copyright (c) 2011 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.
*
* $FreeBSD$
*/
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_ENTRY_LOCALE_H_INCLUDED
#define ARCHIVE_ENTRY_LOCALE_H_INCLUDED
struct archive_entry;
struct archive_string_conv;
/*
* Utility functions to set and get entry attributes by translating
* character-set. These are designed for use in format readers and writers.
*
* The return code and interface of these are quite different from other
* functions for archive_entry defined in archive_entry.h.
* Common return code are:
* Return 0 if the string conversion succeeded.
* Return -1 if the string conversion failed.
*/
#define archive_entry_gname_l _archive_entry_gname_l
int _archive_entry_gname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_hardlink_l _archive_entry_hardlink_l
int _archive_entry_hardlink_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_pathname_l _archive_entry_pathname_l
int _archive_entry_pathname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_symlink_l _archive_entry_symlink_l
int _archive_entry_symlink_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_uname_l _archive_entry_uname_l
int _archive_entry_uname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_acl_text_l _archive_entry_acl_text_l
int _archive_entry_acl_text_l(struct archive_entry *, int,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_copy_gname_l _archive_entry_copy_gname_l
int _archive_entry_copy_gname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_hardlink_l _archive_entry_copy_hardlink_l
int _archive_entry_copy_hardlink_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_link_l _archive_entry_copy_link_l
int _archive_entry_copy_link_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_pathname_l _archive_entry_copy_pathname_l
int _archive_entry_copy_pathname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_symlink_l _archive_entry_copy_symlink_l
int _archive_entry_copy_symlink_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#define archive_entry_copy_uname_l _archive_entry_copy_uname_l
int _archive_entry_copy_uname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
#endif /* ARCHIVE_ENTRY_LOCALE_H_INCLUDED */

View File

@ -0,0 +1,151 @@
.\" Copyright (c) 2010 Joerg Sonnenberger
.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
.\"
.Dd February 22, 2010
.Dt ARCHIVE_ENTRY_PATHS 3
.Os
.Sh NAME
.Nm archive_entry_hardlink ,
.Nm archive_entry_hardlink_w ,
.Nm archive_entry_set_hardlink ,
.Nm archive_entry_copy_hardlink ,
.Nm archive_entry_copy_hardlink_w ,
.Nm archve_entry_update_hardlink_utf8 ,
.Nm archive_entry_set_link ,
.Nm archive_entry_copy_link ,
.Nm archive_entry_copy_link_w ,
.Nm archve_entry_update_link_utf8 ,
.Nm archive_entry_pathname ,
.Nm archive_entry_pathname_w ,
.Nm archive_entry_set_pathname ,
.Nm archive_entry_copy_pathname ,
.Nm archive_entry_copy_pathname_w ,
.Nm archve_entry_update_pathname_utf8 ,
.Nm archive_entry_sourcepath ,
.Nm archive_entry_copy_sourcepath ,
.Nm archive_entry_symlink,
.Nm archive_entry_symlink_w,
.Nm archive_entry_set_symlink ,
.Nm archive_entry_copy_symlink ,
.Nm archive_entry_copy_symlink_w ,
.Nm archve_entry_update_symlink_utf8
.Nd functions for manipulating path names in archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft const char *
.Fn archive_entry_hardlink "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_hardlink_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_hardlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_hardlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_hardlink_w "struct archive_entry *a "const wchar_t *path"
.Ft int
.Fn archive_entry_update_hardlink_utf8 "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_set_link "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_link "struct archive_entry *a" " const char *path"
.Ft void
.Fn archive_entry_copy_link_w "struct archive_entry *a" " const wchar_t *path"
.Ft int
.Fn archive_entry_update_link_utf8 "struct archive_entry *a" " const char *path"
.Ft const char *
.Fn archive_entry_pathname "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_pathname_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_pathname "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_pathname "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_pathname_w "struct archive_entry *a" "const wchar_t *path"
.Ft int
.Fn archive_entry_update_pathname_utf8 "struct archive_entry *a" "const char *path"
.Ft const char *
.Fn archive_entry_sourcepath "struct archive_entry *a"
.Ft void
.Fn archive_entry_copy_sourcepath "struct archive_entry *a" "const char *path"
.Ft const char *
.Fn archive_entry_symlink "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_symlink_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_symlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_symlink "struct archive_entry *a" "const char *path"
.Ft void
.Fn archive_entry_copy_symlink_w "struct archive_entry *a" "const wchar_t *path"
.Ft int
.Fn archive_entry_update_symlink_utf8 "struct archive_entry *a" "const char *path"
.Sh DESCRIPTION
Path names supported by
.Xr archive_entry 3 :
.Bl -tag -width "sourcepath" -compact
.It hardlink
Destination of the hardlink.
.It link
Update only.
For a symlink, update the destination.
Otherwise, make the entry a hardlink and alter
the destination for that.
.It pathname
Path in the archive
.It sourcepath
Path on the disk for use by
.Xr archive_read_disk 3 .
.It symlink
Destination of the symbolic link.
.El
.Pp
Path names can be provided in one of three different ways:
.Bl -tag -width "wchar_t *"
.It char *
Multibyte strings in the current locale.
.It wchar_t *
Wide character strings in the current locale.
The accessor functions are named
.Fn XXX_w .
.It UTF-8
Unicode strings encoded as UTF-8.
This are convience functions to update both the multibyte and wide
character strings at the same time.
.El
.Pp
The sourcepath is a pure filesystem concept and never stored in an
archive directly.
.Pp
For that reason, it is only available as multibyte string.
The link path is a convience function for conditionally setting
hardlink or symlink destination.
It doesn't have a corresponding get accessor function.
.Pp
.Fn archive_entry_set_XXX
is an alias for
.Fn archive_entry_copy_XXX .
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry 3

View File

@ -0,0 +1,207 @@
.\" Copyright (c) 2003-2007 Tim Kientzle
.\" Copyright (c) 2010 Joerg Sonnenberger
.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
.\"
.Dd February 22, 2010
.Dt ARCHIVE_ENTRY_PERMS 3
.Os
.Sh NAME
.Nm archive_entry_gid ,
.Nm archive_entry_set_gid ,
.Nm archive_entry_uid ,
.Nm archive_entry_set_uid ,
.Nm archive_entry_perm ,
.Nm archive_entry_set_perm ,
.Nm archive_entry_strmode ,
.Nm archive_entry_uname
.Nm archive_entry_uname_w
.Nm archive_entry_set_uname ,
.Nm archive_entry_copy_uname ,
.Nm archive_entry_copy_uname_w ,
.Nm archive_entry_update_uname_utf8 ,
.Nm archive_entry_gname ,
.Nm archive_entry_gname_w ,
.Nm archive_entry_set_gname ,
.Nm archive_entry_copy_gname ,
.Nm archive_entry_copy_gname_w ,
.Nm archive_entry_update_gname_utf8 ,
.Nm archive_entry_fflags ,
.Nm archive_entry_fflags_text ,
.Nm archive_entry_set_fflags ,
.Nm archive_entry_copy_fflags_text ,
.Nm archive_entry_copy_fflags_text_w
.Nd functions for manipulating ownership and permissions in archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft gid_t
.Fn archive_entry_gid "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_gid "struct archive_entry *a" "gid_t gid"
.Ft uid_t
.Fn archive_entry_uid "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_uid "struct archive_entry *a" "uid_t uid"
.Ft mode_t
.Fn archive_entry_perm "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_perm "struct archive_entry *a" "mode_t mode"
.Ft const char *
.Fn archive_entry_strmode "struct archive_entry *a"
.Ft const char *
.Fn archive_entry_gname "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_gname_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_gname "struct archive_entry *a" "const char *a"
.Ft void
.Fn archive_entry_copy_gname "struct archive_entry *a" "const char *name"
.Ft void
.Fn archive_entry_copy_gname_w "struct archive_entry *a" "const wchar_t *name"
.Ft int
.Fn archive_entry_update_gname_utf8 "struct archive_entry *a" "const char *name"
.Ft const char *
.Fn archive_entry_uname "struct archive_entry *a"
.Ft const wchar_t *
.Fn archive_entry_uname_w "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_uname "struct archive_entry *a" "const char *name"
.Ft void
.Fn archive_entry_copy_uname "struct archive_entry *a" "const char *name"
.Ft void
.Fn archive_entry_copy_uname_w "struct archive_entry *a" "const wchar_t *name"
.Ft int
.Fn archive_entry_update_uname_utf8 "struct archive_entry *a" "const char *name"
.Ft void
.Fo archive_entry_fflags
.Fa "struct archive_entry *a"
.Fa "unsigned long *set_bits"
.Fa "unsigned long *clear_bits"
.Fc
.Ft const char *
.Fn archive_entry_fflags_text "struct archive_entry *a"
.Ft void
.Fo archive_entry_set_fflags
.Fa "struct archive_entry *a"
.Fa "unsigned long set_bits"
.Fa "unsigned long clear_bits"
.Fc
.Ft const char *
.Fn archive_entry_copy_fflags_text "struct archive_entry *a" "const char *text"
.Ft const wchar_t *
.Fn archive_entry_copy_fflags_text_w "struct archive_entry *a" "const wchar_t *text"
.Sh DESCRIPTION
.Ss User id, group id and mode
The functions
.Fn archive_entry_uid ,
.Fn archive_entry_gid ,
and
.Fn archive_entry_perm
can be used to extract the user id, group id and permission from the given entry.
The corresponding functions
.Fn archive_entry_set_uid ,
.Fn archive_entry_set_gid ,
and
.Fn archive_entry_set_perm
store the given user id, group id and permission in the entry.
The permission is also set as side effect of calling
.Fn archive_entry_set_mode .
.Pp
.Fn archive_entry_strmode
returns a string representation of the permission as used by the long mode of
.Xr ls 1 .
.Ss User and group name
User and group names can be provided in one of three different ways:
.Bl -tag -width "wchar_t *"
.It char *
Multibyte strings in the current locale.
.It wchar_t *
Wide character strings in the current locale.
The accessor functions are named
.Fn XXX_w .
.It UTF-8
Unicode strings encoded as UTF-8.
This are convience functions to update both the multibyte and wide
character strings at the same time.
.El
.Pp
.Fn archive_entry_set_XXX
is an alias for
.Fn archive_entry_copy_XXX .
.Ss File Flags
File flags are transparently converted between a bitmap
representation and a textual format.
For example, if you set the bitmap and ask for text, the library
will build a canonical text format.
However, if you set a text format and request a text format,
you will get back the same text, even if it is ill-formed.
If you need to canonicalize a textual flags string, you should first set the
text form, then request the bitmap form, then use that to set the bitmap form.
Setting the bitmap format will clear the internal text representation
and force it to be reconstructed when you next request the text form.
.Pp
The bitmap format consists of two integers, one containing bits
that should be set, the other specifying bits that should be
cleared.
Bits not mentioned in either bitmap will be ignored.
Usually, the bitmap of bits to be cleared will be set to zero.
In unusual circumstances, you can force a fully-specified set
of file flags by setting the bitmap of flags to clear to the complement
of the bitmap of flags to set.
(This differs from
.Xr fflagstostr 3 ,
which only includes names for set bits.)
Converting a bitmap to a textual string is a platform-specific
operation; bits that are not meaningful on the current platform
will be ignored.
.Pp
The canonical text format is a comma-separated list of flag names.
The
.Fn archive_entry_copy_fflags_text
and
.Fn archive_entry_copy_fflags_text_w
functions parse the provided text and sets the internal bitmap values.
This is a platform-specific operation; names that are not meaningful
on the current platform will be ignored.
The function returns a pointer to the start of the first name that was not
recognized, or NULL if every name was recognized.
Note that every name \(em including names that follow an unrecognized
name \(em will be evaluated, and the bitmaps will be set to reflect
every name that is recognized.
(In particular, this differs from
.Xr strtofflags 3 ,
which stops parsing at the first unrecognized name.)
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_read_disk 3 ,
.Xr archive_write_disk 3
.Sh BUGS
The platform types
.Vt uid_t
and
.Vt gid_t
are often 16 or 32 bit wide.
In this case it is possible that the ids can not be correctly restored
from archives and get truncated.

View File

@ -32,36 +32,9 @@
#ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED #ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
#define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED #define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
#include "archive_acl_private.h"
#include "archive_string.h" #include "archive_string.h"
/*
* Handle wide character (i.e., Unicode) and non-wide character
* strings transparently.
*/
struct aes {
struct archive_string aes_mbs;
struct archive_string aes_utf8;
const wchar_t *aes_wcs;
/* Bitmap of which of the above are valid. Because we're lazy
* about malloc-ing and reusing the underlying storage, we
* can't rely on NULL pointers to indicate whether a string
* has been set. */
int aes_set;
#define AES_SET_MBS 1
#define AES_SET_UTF8 2
#define AES_SET_WCS 4
};
struct ae_acl {
struct ae_acl *next;
int type; /* E.g., access or default */
int tag; /* E.g., user/group/other/mask */
int permset; /* r/w/x bits */
int id; /* uid/gid for user/group */
struct aes name; /* uname/gname */
};
struct ae_xattr { struct ae_xattr {
struct ae_xattr *next; struct ae_xattr *next;
@ -70,6 +43,13 @@ struct ae_xattr {
size_t size; size_t size;
}; };
struct ae_sparse {
struct ae_sparse *next;
int64_t offset;
int64_t length;
};
/* /*
* Description of an archive entry. * Description of an archive entry.
* *
@ -91,6 +71,8 @@ struct ae_xattr {
* TODO: Design a good API for handling sparse files. * TODO: Design a good API for handling sparse files.
*/ */
struct archive_entry { struct archive_entry {
struct archive *archive;
/* /*
* Note that ae_stat.st_mode & AE_IFMT can be 0! * Note that ae_stat.st_mode & AE_IFMT can be 0!
* *
@ -101,10 +83,15 @@ struct archive_entry {
*/ */
/* /*
* Read archive_entry_copy_stat.c for an explanation of why I * We have a "struct aest" for holding file metadata rather than just
* don't just use "struct stat" instead of "struct aest" here * a "struct stat" because on some platforms the "struct stat" has
* and why I have this odd pointer to a separately-allocated * fields which are too narrow to hold the range of possible values;
* struct stat. * we don't want to lose information if we read an archive and write
* out another (e.g., in "tar -cf new.tar @old.tar").
*
* The "stat" pointer points to some form of platform-specific struct
* stat; it is declared as a void * rather than a struct stat * as
* some platforms have multiple varieties of stat structures.
*/ */
void *stat; void *stat;
int stat_valid; /* Set to 0 whenever a field in aest changes. */ int stat_valid; /* Set to 0 whenever a field in aest changes. */
@ -118,12 +105,11 @@ struct archive_entry {
uint32_t aest_mtime_nsec; uint32_t aest_mtime_nsec;
int64_t aest_birthtime; int64_t aest_birthtime;
uint32_t aest_birthtime_nsec; uint32_t aest_birthtime_nsec;
gid_t aest_gid; int64_t aest_gid;
int64_t aest_ino; int64_t aest_ino;
mode_t aest_mode;
uint32_t aest_nlink; uint32_t aest_nlink;
uint64_t aest_size; uint64_t aest_size;
uid_t aest_uid; int64_t aest_uid;
/* /*
* Because converting between device codes and * Because converting between device codes and
* major/minor values is platform-specific and * major/minor values is platform-specific and
@ -150,35 +136,41 @@ struct archive_entry {
#define AE_SET_MTIME 16 #define AE_SET_MTIME 16
#define AE_SET_BIRTHTIME 32 #define AE_SET_BIRTHTIME 32
#define AE_SET_SIZE 64 #define AE_SET_SIZE 64
#define AE_SET_INO 128
#define AE_SET_DEV 256
/* /*
* Use aes here so that we get transparent mbs<->wcs conversions. * Use aes here so that we get transparent mbs<->wcs conversions.
*/ */
struct aes ae_fflags_text; /* Text fflags per fflagstostr(3) */ struct archive_mstring ae_fflags_text; /* Text fflags per fflagstostr(3) */
unsigned long ae_fflags_set; /* Bitmap fflags */ unsigned long ae_fflags_set; /* Bitmap fflags */
unsigned long ae_fflags_clear; unsigned long ae_fflags_clear;
struct aes ae_gname; /* Name of owning group */ struct archive_mstring ae_gname; /* Name of owning group */
struct aes ae_hardlink; /* Name of target for hardlink */ struct archive_mstring ae_hardlink; /* Name of target for hardlink */
struct aes ae_pathname; /* Name of entry */ struct archive_mstring ae_pathname; /* Name of entry */
struct aes ae_symlink; /* symlink contents */ struct archive_mstring ae_symlink; /* symlink contents */
struct aes ae_uname; /* Name of owner */ struct archive_mstring ae_uname; /* Name of owner */
/* Not used within libarchive; useful for some clients. */ /* Not used within libarchive; useful for some clients. */
struct aes ae_sourcepath; /* Path this entry is sourced from. */ struct archive_mstring ae_sourcepath; /* Path this entry is sourced from. */
void *mac_metadata;
size_t mac_metadata_size;
/* ACL support. */ /* ACL support. */
struct ae_acl *acl_head; struct archive_acl acl;
struct ae_acl *acl_p;
int acl_state; /* See acl_next for details. */
wchar_t *acl_text_w;
/* extattr support. */ /* extattr support. */
struct ae_xattr *xattr_head; struct ae_xattr *xattr_head;
struct ae_xattr *xattr_p; struct ae_xattr *xattr_p;
/* sparse support. */
struct ae_sparse *sparse_head;
struct ae_sparse *sparse_tail;
struct ae_sparse *sparse_p;
/* Miscellaneous. */ /* Miscellaneous. */
char strmode[12]; char strmode[12];
}; };
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ #endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */

View File

@ -0,0 +1,156 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2010-2011 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 "archive_platform.h"
__FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_entry_private.h"
/*
* sparse handling
*/
void
archive_entry_sparse_clear(struct archive_entry *entry)
{
struct ae_sparse *sp;
while (entry->sparse_head != NULL) {
sp = entry->sparse_head->next;
free(entry->sparse_head);
entry->sparse_head = sp;
}
entry->sparse_tail = NULL;
}
void
archive_entry_sparse_add_entry(struct archive_entry *entry,
int64_t offset, int64_t length)
{
struct ae_sparse *sp;
if (offset < 0 || length < 0)
/* Invalid value */
return;
if (offset + length < 0 ||
offset + length > archive_entry_size(entry))
/* A value of "length" parameter is too large. */
return;
if ((sp = entry->sparse_tail) != NULL) {
if (sp->offset + sp->length > offset)
/* Invalid value. */
return;
if (sp->offset + sp->length == offset) {
if (sp->offset + sp->length + length < 0)
/* A value of "length" parameter is
* too large. */
return;
/* Expand existing sparse block size. */
sp->length += length;
return;
}
}
if ((sp = (struct ae_sparse *)malloc(sizeof(*sp))) == NULL)
/* XXX Error XXX */
return;
sp->offset = offset;
sp->length = length;
sp->next = NULL;
if (entry->sparse_head == NULL)
entry->sparse_head = entry->sparse_tail = sp;
else {
/* Add a new sparse block to the tail of list. */
if (entry->sparse_tail != NULL)
entry->sparse_tail->next = sp;
entry->sparse_tail = sp;
}
}
/*
* returns number of the sparse entries
*/
int
archive_entry_sparse_count(struct archive_entry *entry)
{
struct ae_sparse *sp;
int count = 0;
for (sp = entry->sparse_head; sp != NULL; sp = sp->next)
count++;
/*
* Sanity check if this entry is exactly sparse.
* If amount of sparse blocks is just one and it indicates the whole
* file data, we should remove it and return zero.
*/
if (count == 1) {
sp = entry->sparse_head;
if (sp->offset == 0 &&
sp->length >= archive_entry_size(entry)) {
count = 0;
archive_entry_sparse_clear(entry);
}
}
return (count);
}
int
archive_entry_sparse_reset(struct archive_entry * entry)
{
entry->sparse_p = entry->sparse_head;
return archive_entry_sparse_count(entry);
}
int
archive_entry_sparse_next(struct archive_entry * entry,
int64_t *offset, int64_t *length)
{
if (entry->sparse_p) {
*offset = entry->sparse_p->offset;
*length = entry->sparse_p->length;
entry->sparse_p = entry->sparse_p->next;
return (ARCHIVE_OK);
} else {
*offset = 0;
*length = 0;
return (ARCHIVE_WARN);
}
}
/*
* end of sparse handling
*/

View File

@ -0,0 +1,272 @@
.\" Copyright (c) 2010 Joerg Sonnenberger
.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
.\"
.Dd May 12, 2008
.Dt ARCHIVE_ENTRY 3
.Os
.Sh NAME
.Nm archive_entry_stat ,
.Nm archive_entry_copy_stat ,
.Nm archive_entry_filetype ,
.Nm archive_entry_set_filetype ,
.Nm archive_entry_mode ,
.Nm archive_entry_set_mode ,
.Nm archive_entry_size ,
.Nm archive_entry_size_is_set ,
.Nm archive_entry_set_size ,
.Nm archive_entry_unset_size ,
.Nm archive_entry_dev ,
.Nm archive_entry_set_dev ,
.Nm archive_entry_dev_is_set ,
.Nm archive_entry_devmajor ,
.Nm archive_entry_set_devmajor ,
.Nm archive_entry_devminor ,
.Nm archive_entry_set_devminor ,
.Nm archive_entry_ino ,
.Nm archive_entry_set_ino ,
.Nm archive_entry_ino_is_set ,
.Nm archive_entry_ino64 ,
.Nm archive_entry_set_ino64 ,
.Nm archive_entry_nlink ,
.Nm archive_entry_rdev ,
.Nm archive_entry_set_rdev ,
.Nm archive_entry_rdevmajor ,
.Nm archive_entry_set_rdevmajor ,
.Nm archive_entry_rdevminor ,
.Nm archive_entry_set_rdevminor ,
.Nd accessor functions for manipulating archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft const struct stat *
.Fn archive_entry_stat "struct archive_entry *a"
.Ft void
.Fn archive_entry_copy_stat "struct archive_entry *a" "const struct stat *sb"
.Ft mode_t
.Fn archive_entry_filetype "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_filetype "struct archive_entry *a" "unsigned int type"
.Ft mode_t
.Fn archive_entry_mode "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_mode "struct archive_entry *a" "mode_t mode"
.Ft int64_t
.Fn archive_entry_size "struct archive_entry *a"
.Ft int
.Fn archive_entry_size_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_size "struct archive_entry *a" "int64_t size"
.Ft void
.Fn archive_entry_unset_size "struct archive_entry *a"
.Ft dev_t
.Fn archive_entry_dev "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_dev "struct archive_entry *a" "dev_t dev"
.Ft int
.Fn archive_entry_dev_is_set "struct archive_entry *a"
.Ft dev_t
.Fn archive_entry_devmajor "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_devmajor "struct archive_entry *a" "dev_t major"
.Ft dev_t
.Fn archive_entry_devminor "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_devminor "struct archive_entry *a" "dev_t minor"
.Ft ino_t
.Fn archive_entry_ino "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_ino "struct archive_entry *a" "unsigned long ino"
.Ft int
.Fn archive_entry_ino_is_set "struct archive_entry *a"
.Ft int64_t
.Fn archive_entry_ino64 "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_ino64 "struct archive_entry *a" "int64_t ino"
.Ft unsigned int
.Fn archive_entry_nlink "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_nlink "struct archive_entry *a" "unsigned int count"
.Ft dev_t
.Fn archive_entry_rdev "struct archive_entry *a"
.Ft dev_t
.Fn archive_entry_rdevmajor "struct archive_entry *a"
.Ft dev_t
.Fn archive_entry_rdevminor "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_rdev "struct archive_entry *a" "dev_t dev"
.Ft void
.Fn archive_entry_set_rdevmajor "struct archive_entry *a" "dev_t major"
.Ft void
.Fn archive_entry_set_rdevminor "struct archive_entry *a" "dev_t minor"
.Sh DESCRIPTION
.Ss Copying to and from Vt struct stat
The function
.Fn archive_entry_stat
converts the various fields stored in the archive entry to the format
used by
.Xr stat 2 .
The return value remains valid until either
.Fn archive_entry_clear
or
.Fn archive_entry_free
is called.
It is not affected by calls to the set accessor functions.
It currently sets the following values in
.Vt struct stat :
.Vt st_atime ,
.Vt st_ctime ,
.Vt st_dev ,
.Vt st_gid ,
.Vt st_ino ,
.Vt st_mode ,
.Vt st_mtime ,
.Vt st_nlink ,
.Vt st_rdev ,
.Vt st_size ,
.Vt st_uid .
In addition,
.Vt st_birthtime
and high-precision information for time-related fields
will be included on platforms that support it.
.Pp
The function
.Fn archive_entry_copy_stat
copies fields from the platform's
.Vt struct stat .
Fields not provided by
.Vt struct stat
are unchanged.
.Ss General accessor functions
The functions
.Fn archive_entry_filetype
and
.Fn archive_entry_set_filetype
get respectively set the filetype.
The file type is one of the following constants:
.Bl -tag -width "AE_IFSOCK" -compact -offset indent
.It AE_IFREG
Regular file
.It AE_IFLNK
Symbolic link
.It AE_IFSOCK
Socket
.It AE_IFCHR
Character device
.It AE_IFBLK
Block device
.It AE_IFDIR
Directory
.It AE_IFIFO
Named pipe (fifo)
.El
Not all file types are supported by all platforms.
The constants used by
.Xr stat 2
may have different numeric values from the
corresponding constants above.
.Pp
The functions
.Fn archive_entry_mode
and
.Fn archive_entry_set_mode
get/set a combination of file type and permissions and provide the
equivalent of
.Va st_mode .
Use of
.Fn archive_entry_filetype
and
.Fn archive_entry_perm
for getting and
.Fn archive_entry_set_filetype
and
.Fn archive_entry_set_perm
for setting is recommended.
.Pp
The function
.Fn archive_entry_size
returns the file size, if it has been set, and 0 otherwise.
.Fn archive_entry_size
can be used to query that status.
.Fn archive_entry_set_size
and
.Fn archive_entry_unset_size
set and unset the size, respectively.
.Pp
The number of references (hardlinks) can be obtained by calling
.Fn archive_entry_nlinks
and set with
.Fn archive_entry_set_nlinks .
.Ss Identifying unique files
The functions
.Fn archive_entry_dev
and
.Fn archive_entry_ino64
are used by
.Xr archive_entry_linkify 3
to find hardlinks.
The pair of device and inode is suppossed to identify hardlinked files.
.Pp
The device major and minor number can be obtained independently using
.Fn archive_entry_devmajor
and
.Fn archive_entry_devminor .
The device can be set either via
.Fn archive_entry_set_dev
or by the combination of major and minor number using
.Fn archive_entry_set_devmajor
and
.Fn archive_entry_set_devminor .
.Pp
The inode number can be obtained using
.Fn archive_entry_ino .
This is a legacy interface that uses the platform
.Vt ino_t ,
which may be very small.
To set the inode number,
.Fn archive_entry_set_ino64
is the preferred interface.
.Ss Accessor functions for block and character devices
Block and character devices are characterised either using a device number
or a pair of major and minor number.
The combined device number can be obtained with
.Fn archive_device_rdev
and set with
.Fn archive_device_set_rdev .
The major and minor numbers are accessed by
.Fn archive_device_rdevmajor ,
.Fn archive_device_rdevminor
.Fn archive_device_set_rdevmajor
and
.Fn archive_device_set_rdevminor .
.Pp
The process of splitting the combined device number into major and
minor number and the reverse process of combing them differs between
platforms.
Some archive formats use the combined form, while other formats use
the split form.
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_entry_perms 3 ,
.Xr archive_entry_time 3 ,
.Xr stat 2

View File

@ -41,7 +41,7 @@ archive_entry_stat(struct archive_entry *entry)
{ {
struct stat *st; struct stat *st;
if (entry->stat == NULL) { if (entry->stat == NULL) {
entry->stat = malloc(sizeof(*st)); entry->stat = calloc(1, sizeof(*st));
if (entry->stat == NULL) if (entry->stat == NULL)
return (NULL); return (NULL);
entry->stat_valid = 0; entry->stat_valid = 0;
@ -110,7 +110,7 @@ archive_entry_stat(struct archive_entry *entry)
/* /*
* TODO: On Linux, store 32 or 64 here depending on whether * TODO: On Linux, store 32 or 64 here depending on whether
* the cached stat structure is a stat32 or a stat64. This * the cached stat structure is a stat32 or a stat64. This
* will allow us to support both variants interchangably. * will allow us to support both variants interchangeably.
*/ */
entry->stat_valid = 1; entry->stat_valid = 1;

View File

@ -0,0 +1,127 @@
.\" Copyright (c) 2003-2007 Tim Kientzle
.\" Copyright (c) 2010 Joerg Sonnenberger
.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $
.\"
.Dd February 21, 2010
.Dt ARCHIVE_ENTRY_TIME 3
.Os
.Sh NAME
.Nm archive_entry_atime ,
.Nm archive_entry_atime_nsec ,
.Nm archive_entry_atime_is_set ,
.Nm archive_entry_set_atime ,
.Nm archive_entry_unset_atime ,
.Nm archive_entry_birthtime ,
.Nm archive_entry_birthtime_nsec ,
.Nm archive_entry_birthtime_is_set ,
.Nm archive_entry_set_birthtime ,
.Nm archive_entry_unset_birthtime ,
.Nm archive_entry_ctime ,
.Nm archive_entry_ctime_nsec ,
.Nm archive_entry_ctime_is_set ,
.Nm archive_entry_set_ctime ,
.Nm archive_entry_unset_ctime ,
.Nm archive_entry_mtime ,
.Nm archive_entry_mtime_nsec ,
.Nm archive_entry_mtime_is_set ,
.Nm archive_entry_set_mtime ,
.Nm archive_entry_unset_mtime ,
.Nd functions for manipulating times in archive entry descriptions
.Sh SYNOPSIS
.In archive_entry.h
.Ft time_t
.Fn archive_entry_atime "struct archive_entry *a"
.Ft long
.Fn archive_entry_atime_nsec "struct archive_entry *a"
.Ft int
.Fn archive_entry_atime_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_atime "struct archive_entry *a" "time_t sec" "long nanosec"
.Ft void
.Fn archive_entry_unset_atime "struct archive_entry *a"
.Ft time_t
.Fn archive_entry_birthtime "struct archive_entry *a"
.Ft long
.Fn archive_entry_birthtime_nsec "struct archive_entry *a"
.Ft int
.Fn archive_entry_birthtime_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_birthtime "struct archive_entry *a" "time_t sec" "long nanosec"
.Ft void
.Fn archive_entry_unset_birthtime "struct archive_entry *a"
.Ft time_t
.Fn archive_entry_ctime "struct archive_entry *a"
.Ft long
.Fn archive_entry_ctime_nsec "struct archive_entry *a"
.Ft int
.Fn archive_entry_ctime_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_ctime "struct archive_entry *a" "time_t sec" "long nanosec"
.Ft void
.Fn archive_entry_unset_ctime "struct archive_entry *a"
.Ft time_t
.Fn archive_entry_mtime "struct archive_entry *a"
.Ft long
.Fn archive_entry_mtime_nsec "struct archive_entry *a"
.Ft int
.Fn archive_entry_mtime_is_set "struct archive_entry *a"
.Ft void
.Fn archive_entry_set_mtime "struct archive_entry *a" "time_t sec" "long nanosec"
.Ft void
.Fn archive_entry_unset_mtime "struct archive_entry *a"
.Sh DESCRIPTION
These functions create and manipulate the time fields in an
.Vt archive_entry .
Supported time fields are atime (access time), birthtime (creation time),
ctime (last time an inode property was changed) and mtime (modification time).
.Pp
.Xr libarchive 3
provides a high-resolution interface.
The timestamps are truncated automatically depending on the archive format
(for archiving) or the filesystem capabilities (for restoring).
.Pp
All timestamp fields are optional.
The
.Fn XXX_unset
functions can be used to mark the corresponding field as missing.
The current state can be queried using
.Fn XXX_is_set .
Unset time fields have a second and nanosecond field of 0.
.Sh SEE ALSO
.Xr archive 3 ,
.Xr archive_entry 3
.Sh HISTORY
The
.Nm libarchive
library first appeared in
.Fx 5.3 .
.Sh AUTHORS
.An -nosplit
The
.Nm libarchive
library was written by
.An Tim Kientzle Aq kientzle@acm.org .
.\" .Sh BUGS

View File

@ -1,309 +0,0 @@
/*-
* Copyright (c) 2009 Joerg Sonnenberger
* 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$
*/
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
/*
* Hash function support in various Operating Systems:
*
* NetBSD:
* - MD5 and SHA1 in libc: without _ after algorithm name
* - SHA2 in libc: with _ after algorithm name
*
* OpenBSD:
* - MD5, SHA1 and SHA2 in libc: without _ after algorithm name
* - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name
*
* DragonFly and FreeBSD (XXX not used yet):
* - MD5 and SHA1 in libmd: without _ after algorithm name
* - SHA256: with _ after algorithm name
*
* Mac OS X (10.4 and later):
* - MD5, SHA1 and SHA2 in libSystem: with CC_ prefix and _ after algorithm name
*
* OpenSSL:
* - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name
*
* Windows:
* - MD5, SHA1 and SHA2 in archive_windows.c: without algorithm name
* and with __la_ prefix.
*/
#if defined(ARCHIVE_HASH_MD5_WIN) ||\
defined(ARCHIVE_HASH_SHA1_WIN) || defined(ARCHIVE_HASH_SHA256_WIN) ||\
defined(ARCHIVE_HASH_SHA384_WIN) || defined(ARCHIVE_HASH_SHA512_WIN)
#include <wincrypt.h>
typedef struct {
int valid;
HCRYPTPROV cryptProv;
HCRYPTHASH hash;
} Digest_CTX;
extern void __la_hash_Init(Digest_CTX *, ALG_ID);
extern void __la_hash_Final(unsigned char *, size_t, Digest_CTX *);
extern void __la_hash_Update(Digest_CTX *, const unsigned char *, size_t);
#endif
#if defined(ARCHIVE_HASH_MD5_LIBC)
# include <md5.h>
# define ARCHIVE_HAS_MD5
typedef MD5_CTX archive_md5_ctx;
# define archive_md5_init(ctx) MD5Init(ctx)
# define archive_md5_final(ctx, buf) MD5Final(buf, ctx)
# define archive_md5_update(ctx, buf, n) MD5Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_MD5_LIBMD)
# include <md5.h>
# define ARCHIVE_HAS_MD5
typedef MD5_CTX archive_md5_ctx;
# define archive_md5_init(ctx) MD5Init(ctx)
# define archive_md5_final(ctx, buf) MD5Final(buf, ctx)
# define archive_md5_update(ctx, buf, n) MD5Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_MD5_LIBSYSTEM)
# include <CommonCrypto/CommonDigest.h>
# define ARCHIVE_HAS_MD5
typedef CC_MD5_CTX archive_md5_ctx;
# define archive_md5_init(ctx) CC_MD5_Init(ctx)
# define archive_md5_final(ctx, buf) CC_MD5_Final(buf, ctx)
# define archive_md5_update(ctx, buf, n) CC_MD5_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_MD5_OPENSSL)
# include <openssl/md5.h>
# define ARCHIVE_HAS_MD5
typedef MD5_CTX archive_md5_ctx;
# define archive_md5_init(ctx) MD5_Init(ctx)
# define archive_md5_final(ctx, buf) MD5_Final(buf, ctx)
# define archive_md5_update(ctx, buf, n) MD5_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_MD5_WIN)
# define ARCHIVE_HAS_MD5
# define MD5_DIGEST_LENGTH 16
typedef Digest_CTX archive_md5_ctx;
# define archive_md5_init(ctx) __la_hash_Init(ctx, CALG_MD5)
# define archive_md5_final(ctx, buf) __la_hash_Final(buf, MD5_DIGEST_LENGTH, ctx)
# define archive_md5_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
#endif
#if defined(ARCHIVE_HASH_RMD160_LIBC)
# include <rmd160.h>
# define ARCHIVE_HAS_RMD160
typedef RMD160_CTX archive_rmd160_ctx;
# define archive_rmd160_init(ctx) RMD160Init(ctx)
# define archive_rmd160_final(ctx, buf) RMD160Final(buf, ctx)
# define archive_rmd160_update(ctx, buf, n) RMD160Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_RMD160_OPENSSL)
# include <openssl/ripemd.h>
# define ARCHIVE_HAS_RMD160
typedef RIPEMD160_CTX archive_rmd160_ctx;
# define archive_rmd160_init(ctx) RIPEMD160_Init(ctx)
# define archive_rmd160_final(ctx, buf) RIPEMD160_Final(buf, ctx)
# define archive_rmd160_update(ctx, buf, n) RIPEMD160_Update(ctx, buf, n)
#endif
#if defined(ARCHIVE_HASH_SHA1_LIBC)
# include <sha1.h>
# define ARCHIVE_HAS_SHA1
typedef SHA1_CTX archive_sha1_ctx;
# define archive_sha1_init(ctx) SHA1Init(ctx)
# define archive_sha1_final(ctx, buf) SHA1Final(buf, ctx)
# define archive_sha1_update(ctx, buf, n) SHA1Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA1_LIBMD)
# include <sha.h>
# define ARCHIVE_HAS_SHA1
typedef SHA1_CTX archive_sha1_ctx;
# define archive_sha1_init(ctx) SHA1_Init(ctx)
# define archive_sha1_final(ctx, buf) SHA1_Final(buf, ctx)
# define archive_sha1_update(ctx, buf, n) SHA1_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA1_LIBSYSTEM)
# include <CommonCrypto/CommonDigest.h>
# define ARCHIVE_HAS_SHA1
typedef CC_SHA1_CTX archive_sha1_ctx;
# define archive_sha1_init(ctx) CC_SHA1_Init(ctx)
# define archive_sha1_final(ctx, buf) CC_SHA1_Final(buf, ctx)
# define archive_sha1_update(ctx, buf, n) CC_SHA1_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA1_OPENSSL)
# include <openssl/sha.h>
# define ARCHIVE_HAS_SHA1
typedef SHA_CTX archive_sha1_ctx;
# define archive_sha1_init(ctx) SHA1_Init(ctx)
# define archive_sha1_final(ctx, buf) SHA1_Final(buf, ctx)
# define archive_sha1_update(ctx, buf, n) SHA1_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA1_WIN)
# define ARCHIVE_HAS_SHA1
# define SHA1_DIGEST_LENGTH 20
typedef Digest_CTX archive_sha1_ctx;
# define archive_sha1_init(ctx) __la_hash_Init(ctx, CALG_SHA1)
# define archive_sha1_final(ctx, buf) __la_hash_Final(buf, SHA1_DIGEST_LENGTH, ctx)
# define archive_sha1_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
#endif
#if defined(ARCHIVE_HASH_SHA256_LIBC)
# include <sha2.h>
# define ARCHIVE_HAS_SHA256
typedef SHA256_CTX archive_sha256_ctx;
# define archive_sha256_init(ctx) SHA256_Init(ctx)
# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA256_LIBC2)
# include <sha2.h>
# define ARCHIVE_HAS_SHA256
typedef SHA256_CTX archive_sha256_ctx;
# define archive_sha256_init(ctx) SHA256Init(ctx)
# define archive_sha256_final(ctx, buf) SHA256Final(buf, ctx)
# define archive_sha256_update(ctx, buf, n) SHA256Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA256_LIBC3)
# include <sha2.h>
# define ARCHIVE_HAS_SHA256
typedef SHA2_CTX archive_sha256_ctx;
# define archive_sha256_init(ctx) SHA256Init(ctx)
# define archive_sha256_final(ctx, buf) SHA256Final(buf, ctx)
# define archive_sha256_update(ctx, buf, n) SHA256Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA256_LIBMD)
# include <sha256.h>
# define ARCHIVE_HAS_SHA256
typedef SHA256_CTX archive_sha256_ctx;
# define archive_sha256_init(ctx) SHA256_Init(ctx)
# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA256_LIBSYSTEM)
# include <CommonCrypto/CommonDigest.h>
# define ARCHIVE_HAS_SHA256
typedef CC_SHA256_CTX archive_shs256_ctx;
# define archive_shs256_init(ctx) CC_SHA256_Init(ctx)
# define archive_shs256_final(ctx, buf) CC_SHA256_Final(buf, ctx)
# define archive_shs256_update(ctx, buf, n) CC_SHA256_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA256_OPENSSL)
# include <openssl/sha.h>
# define ARCHIVE_HAS_SHA256
typedef SHA256_CTX archive_sha256_ctx;
# define archive_sha256_init(ctx) SHA256_Init(ctx)
# define archive_sha256_final(ctx, buf) SHA256_Final(buf, ctx)
# define archive_sha256_update(ctx, buf, n) SHA256_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA256_WIN)
# define ARCHIVE_HAS_SHA256
# define SHA256_DIGEST_LENGTH 32
typedef Digest_CTX archive_sha256_ctx;
# define archive_sha256_init(ctx) __la_hash_Init(ctx, CALG_SHA_256)
# define archive_sha256_final(ctx, buf) __la_hash_Final(buf, SHA256_DIGEST_LENGTH, ctx)
# define archive_sha256_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
#endif
#if defined(ARCHIVE_HASH_SHA384_LIBC)
# include <sha2.h>
# define ARCHIVE_HAS_SHA384
typedef SHA384_CTX archive_sha384_ctx;
# define archive_sha384_init(ctx) SHA384_Init(ctx)
# define archive_sha384_final(ctx, buf) SHA384_Final(buf, ctx)
# define archive_sha384_update(ctx, buf, n) SHA384_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA384_LIBC2)
# include <sha2.h>
# define ARCHIVE_HAS_SHA384
typedef SHA384_CTX archive_sha384_ctx;
# define archive_sha384_init(ctx) SHA384Init(ctx)
# define archive_sha384_final(ctx, buf) SHA384Final(buf, ctx)
# define archive_sha384_update(ctx, buf, n) SHA384Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA384_LIBC3)
# include <sha2.h>
# define ARCHIVE_HAS_SHA384
typedef SHA2_CTX archive_sha384_ctx;
# define archive_sha384_init(ctx) SHA384Init(ctx)
# define archive_sha384_final(ctx, buf) SHA384Final(buf, ctx)
# define archive_sha384_update(ctx, buf, n) SHA384Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA384_LIBSYSTEM)
# include <CommonCrypto/CommonDigest.h>
# define ARCHIVE_HAS_SHA384
typedef CC_SHA512_CTX archive_shs384_ctx;
# define archive_shs384_init(ctx) CC_SHA384_Init(ctx)
# define archive_shs384_final(ctx, buf) CC_SHA384_Final(buf, ctx)
# define archive_shs384_update(ctx, buf, n) CC_SHA384_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA384_OPENSSL)
# include <openssl/sha.h>
# define ARCHIVE_HAS_SHA384
typedef SHA512_CTX archive_sha384_ctx;
# define archive_sha384_init(ctx) SHA384_Init(ctx)
# define archive_sha384_final(ctx, buf) SHA384_Final(buf, ctx)
# define archive_sha384_update(ctx, buf, n) SHA384_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA384_WIN)
# define ARCHIVE_HAS_SHA384
# define SHA384_DIGEST_LENGTH 48
typedef Digest_CTX archive_sha384_ctx;
# define archive_sha384_init(ctx) __la_hash_Init(ctx, CALG_SHA_384)
# define archive_sha384_final(ctx, buf) __la_hash_Final(buf, SHA384_DIGEST_LENGTH, ctx)
# define archive_sha384_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
#endif
#if defined(ARCHIVE_HASH_SHA512_LIBC)
# include <sha2.h>
# define ARCHIVE_HAS_SHA512
typedef SHA512_CTX archive_sha512_ctx;
# define archive_sha512_init(ctx) SHA512_Init(ctx)
# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA512_LIBC2)
# include <sha2.h>
# define ARCHIVE_HAS_SHA512
typedef SHA512_CTX archive_sha512_ctx;
# define archive_sha512_init(ctx) SHA512Init(ctx)
# define archive_sha512_final(ctx, buf) SHA512Final(buf, ctx)
# define archive_sha512_update(ctx, buf, n) SHA512Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA512_LIBC3)
# include <sha2.h>
# define ARCHIVE_HAS_SHA512
typedef SHA2_CTX archive_sha512_ctx;
# define archive_sha512_init(ctx) SHA512Init(ctx)
# define archive_sha512_final(ctx, buf) SHA512Final(buf, ctx)
# define archive_sha512_update(ctx, buf, n) SHA512Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA512_LIBMD)
# include <sha512.h>
# define ARCHIVE_HAS_SHA512
typedef SHA512_CTX archive_sha512_ctx;
# define archive_sha512_init(ctx) SHA512_Init(ctx)
# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA512_LIBSYSTEM)
# include <CommonCrypto/CommonDigest.h>
# define ARCHIVE_HAS_SHA512
typedef CC_SHA512_CTX archive_shs512_ctx;
# define archive_shs512_init(ctx) CC_SHA512_Init(ctx)
# define archive_shs512_final(ctx, buf) CC_SHA512_Final(buf, ctx)
# define archive_shs512_update(ctx, buf, n) CC_SHA512_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA512_OPENSSL)
# include <openssl/sha.h>
# define ARCHIVE_HAS_SHA512
typedef SHA512_CTX archive_sha512_ctx;
# define archive_sha512_init(ctx) SHA512_Init(ctx)
# define archive_sha512_final(ctx, buf) SHA512_Final(buf, ctx)
# define archive_sha512_update(ctx, buf, n) SHA512_Update(ctx, buf, n)
#elif defined(ARCHIVE_HASH_SHA512_WIN)
# define ARCHIVE_HAS_SHA512
# define SHA512_DIGEST_LENGTH 64
typedef Digest_CTX archive_sha512_ctx;
# define archive_sha512_init(ctx) __la_hash_Init(ctx, CALG_SHA_512)
# define archive_sha512_final(ctx, buf) __la_hash_Final(buf, SHA512_DIGEST_LENGTH, ctx)
# define archive_sha512_update(ctx, buf, n) __la_hash_Update(ctx, buf, n)
#endif

View File

@ -0,0 +1,198 @@
/*-
* Copyright (c) 2011 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 "archive_platform.h"
__FBSDID("$FreeBSD$");
#include "archive_options_private.h"
static const char *
parse_option(const char **str,
const char **mod, const char **opt, const char **val);
int
_archive_set_option(struct archive *a,
const char *m, const char *o, const char *v,
int magic, const char *fn, option_handler use_option)
{
const char *mp, *op, *vp;
int r;
archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
mp = m != NULL && m[0] == '\0' ? NULL : m;
op = o != NULL && o[0] == '\0' ? NULL : o;
vp = v != NULL && v[0] == '\0' ? NULL : v;
if (op == NULL && vp == NULL)
return (ARCHIVE_OK);
if (op == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
return (ARCHIVE_FAILED);
}
r = use_option(a, mp, op, vp);
if (r == ARCHIVE_WARN - 1) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Unknown module name: `%s'", mp);
return (ARCHIVE_FAILED);
}
if (r == ARCHIVE_WARN) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Undefined option: `%s%s%s%s%s%s'",
vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");
return (ARCHIVE_FAILED);
}
return (r);
}
int
_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v,
option_handler use_format_option, option_handler use_filter_option)
{
int r1, r2;
if (o == NULL && v == NULL)
return (ARCHIVE_OK);
if (o == NULL)
return (ARCHIVE_FAILED);
r1 = use_format_option(a, m, o, v);
if (r1 == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
r2 = use_filter_option(a, m, o, v);
if (r2 == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
return r1 > r2 ? r1 : r2;
}
int
_archive_set_options(struct archive *a, const char *options,
int magic, const char *fn, option_handler use_option)
{
int allok = 1, anyok = 0, r;
char *data;
const char *s, *mod, *opt, *val;
archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
if (options == NULL || options[0] == '\0')
return ARCHIVE_OK;
data = (char *)malloc(strlen(options) + 1);
strcpy(data, options);
s = (const char *)data;
do {
mod = opt = val = NULL;
parse_option(&s, &mod, &opt, &val);
r = use_option(a, mod, opt, val);
if (r == ARCHIVE_FATAL) {
free(data);
return (ARCHIVE_FATAL);
}
if (r == ARCHIVE_FAILED && mod != NULL) {
free(data);
return (ARCHIVE_FAILED);
}
if (r == ARCHIVE_WARN - 1) {
/* The module name is wrong. */
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Unknown module name: `%s'", mod);
free(data);
return (ARCHIVE_FAILED);
}
if (r == ARCHIVE_WARN) {
/* The option name is wrong. No-one used this. */
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Undefined option: `%s%s%s'",
mod?mod:"", mod?":":"", opt);
free(data);
return (ARCHIVE_FAILED);
}
if (r == ARCHIVE_OK)
anyok = 1;
else
allok = 0;
} while (s != NULL);
free(data);
return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
}
static const char *
parse_option(const char **s, const char **m, const char **o, const char **v)
{
const char *end, *mod, *opt, *val;
char *p;
end = NULL;
mod = NULL;
opt = *s;
val = "1";
p = strchr(opt, ',');
if (p != NULL) {
*p = '\0';
end = ((const char *)p) + 1;
}
if (0 == strlen(opt)) {
*s = end;
*m = NULL;
*o = NULL;
*v = NULL;
return end;
}
p = strchr(opt, ':');
if (p != NULL) {
*p = '\0';
mod = opt;
opt = ++p;
}
p = strchr(opt, '=');
if (p != NULL) {
*p = '\0';
val = ++p;
} else if (opt[0] == '!') {
++opt;
val = NULL;
}
*s = end;
*m = mod;
*o = opt;
*v = val;
return end;
}

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2011 Tim Kientzle
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -21,37 +21,27 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * (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 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/ */
/* A hand-tooled configuration for FreeBSD. */ #include "archive_platform.h"
__FBSDID("$FreeBSD$");
#include <sys/param.h> /* __FreeBSD_version */ #include "archive_private.h"
#define HAVE_DIRENT_H 1 typedef int (*option_handler)(struct archive *a,
#define HAVE_ERRNO_H 1 const char *mod, const char *opt, const char *val);
#define HAVE_FCNTL_H 1
#define HAVE_FUTIMES 1 int
#define HAVE_GRP_H 1 _archive_set_option(struct archive *a,
#define HAVE_LIBARCHIVE 1 const char *mod, const char *opt, const char *val,
#define HAVE_LINK 1 int magic, const char *fn, option_handler use_option);
#define HAVE_LSTAT 1
#define HAVE_LUTIMES 1 int
#define HAVE_PWD_H 1 _archive_set_options(struct archive *a, const char *options,
#define HAVE_READLINK 1 int magic, const char *fn, option_handler use_option);
#define HAVE_STDARG_H 1
#define HAVE_STDLIB_H 1 int
#define HAVE_STRING_H 1 _archive_set_either_option(struct archive *a,
#define HAVE_SYMLINK 1 const char *m, const char *o, const char *v,
#define HAVE_SYS_CDEFS_H 1 option_handler use_format_option, option_handler use_filter_option);
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TIME_H 1
#define HAVE_TIME_H 1
#define HAVE_UINTMAX_T 1
#define HAVE_UNISTD_H 1
#define HAVE_UNSIGNED_LONG_LONG 1
#define HAVE_UTIME_H 1
#define HAVE_UTIMES 1
#define HAVE_WCSCMP 1

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
/* Ppmd7.h -- PPMdH compression codec
2010-03-12 : Igor Pavlov : Public domain
This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
/* This code supports virtual RangeDecoder and includes the implementation
of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.
If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_PPMD7_PRIVATE_H_INCLUDED
#define ARCHIVE_PPMD7_PRIVATE_H_INCLUDED
#include "archive_ppmd_private.h"
#define PPMD7_MIN_ORDER 2
#define PPMD7_MAX_ORDER 64
#define PPMD7_MIN_MEM_SIZE (1 << 11)
#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
struct CPpmd7_Context_;
typedef
#ifdef PPMD_32BIT
struct CPpmd7_Context_ *
#else
UInt32
#endif
CPpmd7_Context_Ref;
typedef struct CPpmd7_Context_
{
UInt16 NumStats;
UInt16 SummFreq;
CPpmd_State_Ref Stats;
CPpmd7_Context_Ref Suffix;
} CPpmd7_Context;
#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
typedef struct
{
CPpmd7_Context *MinContext, *MaxContext;
CPpmd_State *FoundState;
unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
Int32 RunLength, InitRL; /* must be 32-bit at least */
UInt32 Size;
UInt32 GlueCount;
Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
UInt32 AlignOffset;
Byte Indx2Units[PPMD_NUM_INDEXES];
Byte Units2Indx[128];
CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
CPpmd_See DummySee, See[25][16];
UInt16 BinSumm[128][64];
} CPpmd7;
/* ---------- Decode ---------- */
typedef struct
{
UInt32 (*GetThreshold)(void *p, UInt32 total);
void (*Decode)(void *p, UInt32 start, UInt32 size);
UInt32 (*DecodeBit)(void *p, UInt32 size0);
} IPpmd7_RangeDec;
typedef struct
{
IPpmd7_RangeDec p;
UInt32 Range;
UInt32 Code;
UInt32 Low;
UInt32 Bottom;
IByteIn *Stream;
} CPpmd7z_RangeDec;
/* ---------- Encode ---------- */
typedef struct
{
UInt64 Low;
UInt32 Range;
Byte Cache;
UInt64 CacheSize;
IByteOut *Stream;
} CPpmd7z_RangeEnc;
typedef struct
{
/* Base Functions */
void (*Ppmd7_Construct)(CPpmd7 *p);
Bool (*Ppmd7_Alloc)(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
void (*Ppmd7_Free)(CPpmd7 *p, ISzAlloc *alloc);
void (*Ppmd7_Init)(CPpmd7 *p, unsigned maxOrder);
#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
/* Decode Functions */
void (*Ppmd7z_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p);
void (*PpmdRAR_RangeDec_CreateVTable)(CPpmd7z_RangeDec *p);
Bool (*Ppmd7z_RangeDec_Init)(CPpmd7z_RangeDec *p);
Bool (*PpmdRAR_RangeDec_Init)(CPpmd7z_RangeDec *p);
#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
int (*Ppmd7_DecodeSymbol)(CPpmd7 *p, IPpmd7_RangeDec *rc);
/* Encode Functions */
void (*Ppmd7z_RangeEnc_Init)(CPpmd7z_RangeEnc *p);
void (*Ppmd7z_RangeEnc_FlushData)(CPpmd7z_RangeEnc *p);
void (*Ppmd7_EncodeSymbol)(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);
} IPpmd7;
extern const IPpmd7 __archive_ppmd7_functions;
#endif

View File

@ -0,0 +1,158 @@
/* Ppmd.h -- PPMD codec common code
2010-03-12 : Igor Pavlov : Public domain
This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
#ifndef __LIBARCHIVE_BUILD
#error This header is only to be used internally to libarchive.
#endif
#ifndef ARCHIVE_PPMD_PRIVATE_H_INCLUDED
#define ARCHIVE_PPMD_PRIVATE_H_INCLUDED
#include <stddef.h>
#include "archive_read_private.h"
/*** Begin defined in Types.h ***/
#if !defined(ZCONF_H)
typedef unsigned char Byte;
#endif
typedef short Int16;
typedef unsigned short UInt16;
#ifdef _LZMA_UINT32_IS_ULONG
typedef long Int32;
typedef unsigned long UInt32;
#else
typedef int Int32;
typedef unsigned int UInt32;
#endif
#ifdef _SZ_NO_INT_64
/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
NOTES: Some code will work incorrectly in that case! */
typedef long Int64;
typedef unsigned long UInt64;
#else
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 Int64;
typedef unsigned __int64 UInt64;
#define UINT64_CONST(n) n
#else
typedef long long int Int64;
typedef unsigned long long int UInt64;
#define UINT64_CONST(n) n ## ULL
#endif
#endif
typedef int Bool;
#define True 1
#define False 0
/* The following interfaces use first parameter as pointer to structure */
typedef struct
{
struct archive_read *a;
Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
} IByteIn;
typedef struct
{
struct archive_write *a;
void (*Write)(void *p, Byte b);
} IByteOut;
typedef struct
{
void *(*Alloc)(void *p, size_t size);
void (*Free)(void *p, void *address); /* address can be 0 */
} ISzAlloc;
/*** End defined in Types.h ***/
/*** Begin defined in CpuArch.h ***/
#if defined(_M_IX86) || defined(__i386__)
#define MY_CPU_X86
#endif
#if defined(MY_CPU_X86) || defined(_M_ARM)
#define MY_CPU_32BIT
#endif
#ifdef MY_CPU_32BIT
#define PPMD_32BIT
#endif
/*** End defined in CpuArch.h ***/
#define PPMD_INT_BITS 7
#define PPMD_PERIOD_BITS 7
#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
#define PPMD_N1 4
#define PPMD_N2 4
#define PPMD_N3 4
#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
/* SEE-contexts for PPM-contexts with masked symbols */
typedef struct
{
UInt16 Summ; /* Freq */
Byte Shift; /* Speed of Freq change; low Shift is for fast change */
Byte Count; /* Count to next change of Shift */
} CPpmd_See;
#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
{ (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
typedef struct
{
Byte Symbol;
Byte Freq;
UInt16 SuccessorLow;
UInt16 SuccessorHigh;
} CPpmd_State;
typedef
#ifdef PPMD_32BIT
CPpmd_State *
#else
UInt32
#endif
CPpmd_State_Ref;
typedef
#ifdef PPMD_32BIT
void *
#else
UInt32
#endif
CPpmd_Void_Ref;
typedef
#ifdef PPMD_32BIT
Byte *
#else
UInt32
#endif
CPpmd_Byte_Ref;
#define PPMD_SetAllBitsIn256Bytes(p) \
{ unsigned j; for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \
p[j+7] = p[j+6] = p[j+5] = p[j+4] = p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; }}
#endif

View File

@ -32,6 +32,10 @@
#ifndef ARCHIVE_PRIVATE_H_INCLUDED #ifndef ARCHIVE_PRIVATE_H_INCLUDED
#define ARCHIVE_PRIVATE_H_INCLUDED #define ARCHIVE_PRIVATE_H_INCLUDED
#if HAVE_ICONV_H
#include <iconv.h>
#endif
#include "archive.h" #include "archive.h"
#include "archive_string.h" #include "archive_string.h"
@ -47,14 +51,13 @@
#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U) #define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U) #define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
#define ARCHIVE_STATE_ANY 0xFFFFU
#define ARCHIVE_STATE_NEW 1U #define ARCHIVE_STATE_NEW 1U
#define ARCHIVE_STATE_HEADER 2U #define ARCHIVE_STATE_HEADER 2U
#define ARCHIVE_STATE_DATA 4U #define ARCHIVE_STATE_DATA 4U
#define ARCHIVE_STATE_DATA_END 8U
#define ARCHIVE_STATE_EOF 0x10U #define ARCHIVE_STATE_EOF 0x10U
#define ARCHIVE_STATE_CLOSED 0x20U #define ARCHIVE_STATE_CLOSED 0x20U
#define ARCHIVE_STATE_FATAL 0x8000U #define ARCHIVE_STATE_FATAL 0x8000U
#define ARCHIVE_STATE_ANY (0xFFFFU & ~ARCHIVE_STATE_FATAL)
struct archive_vtable { struct archive_vtable {
int (*archive_close)(struct archive *); int (*archive_close)(struct archive *);
@ -65,9 +68,23 @@ struct archive_vtable {
ssize_t (*archive_write_data)(struct archive *, ssize_t (*archive_write_data)(struct archive *,
const void *, size_t); const void *, size_t);
ssize_t (*archive_write_data_block)(struct archive *, ssize_t (*archive_write_data_block)(struct archive *,
const void *, size_t, off_t); const void *, size_t, int64_t);
int (*archive_read_next_header)(struct archive *,
struct archive_entry **);
int (*archive_read_next_header2)(struct archive *,
struct archive_entry *);
int (*archive_read_data_block)(struct archive *,
const void **, size_t *, int64_t *);
int (*archive_filter_count)(struct archive *);
int64_t (*archive_filter_bytes)(struct archive *, int);
int (*archive_filter_code)(struct archive *, int);
const char * (*archive_filter_name)(struct archive *, int);
}; };
struct archive_string_conv;
struct archive { struct archive {
/* /*
* The magic/state values are used to sanity-check the * The magic/state values are used to sanity-check the
@ -90,26 +107,35 @@ struct archive {
int compression_code; /* Currently active compression. */ int compression_code; /* Currently active compression. */
const char *compression_name; const char *compression_name;
/* Position in UNCOMPRESSED data stream. */
int64_t file_position;
/* Position in COMPRESSED data stream. */
int64_t raw_position;
/* Number of file entries processed. */ /* Number of file entries processed. */
int file_count; int file_count;
int archive_error_number; int archive_error_number;
const char *error; const char *error;
struct archive_string error_string; struct archive_string error_string;
char *current_code;
unsigned current_codepage; /* Current ACP(ANSI CodePage). */
unsigned current_oemcp; /* Current OEMCP(OEM CodePage). */
struct archive_string_conv *sconv;
}; };
/* Check magic value and state; exit if it isn't valid. */ /* Check magic value and state; return(ARCHIVE_FATAL) if it isn't valid. */
void __archive_check_magic(struct archive *, unsigned int magic, int __archive_check_magic(struct archive *, unsigned int magic,
unsigned int state, const char *func); unsigned int state, const char *func);
#define archive_check_magic(a, expected_magic, allowed_states, function_name) \
do { \
int magic_test = __archive_check_magic((a), (expected_magic), \
(allowed_states), (function_name)); \
if (magic_test == ARCHIVE_FATAL) \
return ARCHIVE_FATAL; \
} while (0)
void __archive_errx(int retvalue, const char *msg) __LA_DEAD; void __archive_errx(int retvalue, const char *msg) __LA_DEAD;
int __archive_parse_options(const char *p, const char *fn, int __archive_mktemp(const char *tmpdir);
int keysize, char *key, int valsize, char *val);
int __archive_clean(struct archive *);
#define err_combine(a,b) ((a) < (b) ? (a) : (b)) #define err_combine(a,b) ((a) < (b) ? (a) : (b))

View File

@ -0,0 +1,701 @@
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Thomas <matt@3am-software.com>.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*
* Based on: NetBSD: rb.c,v 1.6 2010/04/30 13:58:09 joerg Exp
*/
#include "archive_platform.h"
#include <stddef.h>
#include "archive_rb.h"
/* Keep in sync with archive_rb.h */
#define RB_DIR_LEFT 0
#define RB_DIR_RIGHT 1
#define RB_DIR_OTHER 1
#define rb_left rb_nodes[RB_DIR_LEFT]
#define rb_right rb_nodes[RB_DIR_RIGHT]
#define RB_FLAG_POSITION 0x2
#define RB_FLAG_RED 0x1
#define RB_FLAG_MASK (RB_FLAG_POSITION|RB_FLAG_RED)
#define RB_FATHER(rb) \
((struct archive_rb_node *)((rb)->rb_info & ~RB_FLAG_MASK))
#define RB_SET_FATHER(rb, father) \
((void)((rb)->rb_info = (uintptr_t)(father)|((rb)->rb_info & RB_FLAG_MASK)))
#define RB_SENTINEL_P(rb) ((rb) == NULL)
#define RB_LEFT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_left)
#define RB_RIGHT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_right)
#define RB_FATHER_SENTINEL_P(rb) RB_SENTINEL_P(RB_FATHER((rb)))
#define RB_CHILDLESS_P(rb) \
(RB_SENTINEL_P(rb) || (RB_LEFT_SENTINEL_P(rb) && RB_RIGHT_SENTINEL_P(rb)))
#define RB_TWOCHILDREN_P(rb) \
(!RB_SENTINEL_P(rb) && !RB_LEFT_SENTINEL_P(rb) && !RB_RIGHT_SENTINEL_P(rb))
#define RB_POSITION(rb) \
(((rb)->rb_info & RB_FLAG_POSITION) ? RB_DIR_RIGHT : RB_DIR_LEFT)
#define RB_RIGHT_P(rb) (RB_POSITION(rb) == RB_DIR_RIGHT)
#define RB_LEFT_P(rb) (RB_POSITION(rb) == RB_DIR_LEFT)
#define RB_RED_P(rb) (!RB_SENTINEL_P(rb) && ((rb)->rb_info & RB_FLAG_RED) != 0)
#define RB_BLACK_P(rb) (RB_SENTINEL_P(rb) || ((rb)->rb_info & RB_FLAG_RED) == 0)
#define RB_MARK_RED(rb) ((void)((rb)->rb_info |= RB_FLAG_RED))
#define RB_MARK_BLACK(rb) ((void)((rb)->rb_info &= ~RB_FLAG_RED))
#define RB_INVERT_COLOR(rb) ((void)((rb)->rb_info ^= RB_FLAG_RED))
#define RB_ROOT_P(rbt, rb) ((rbt)->rbt_root == (rb))
#define RB_SET_POSITION(rb, position) \
((void)((position) ? ((rb)->rb_info |= RB_FLAG_POSITION) : \
((rb)->rb_info &= ~RB_FLAG_POSITION)))
#define RB_ZERO_PROPERTIES(rb) ((void)((rb)->rb_info &= ~RB_FLAG_MASK))
#define RB_COPY_PROPERTIES(dst, src) \
((void)((dst)->rb_info ^= ((dst)->rb_info ^ (src)->rb_info) & RB_FLAG_MASK))
#define RB_SWAP_PROPERTIES(a, b) do { \
uintptr_t xorinfo = ((a)->rb_info ^ (b)->rb_info) & RB_FLAG_MASK; \
(a)->rb_info ^= xorinfo; \
(b)->rb_info ^= xorinfo; \
} while (/*CONSTCOND*/ 0)
static void __archive_rb_tree_insert_rebalance(struct archive_rb_tree *,
struct archive_rb_node *);
static void __archive_rb_tree_removal_rebalance(struct archive_rb_tree *,
struct archive_rb_node *, unsigned int);
#define RB_SENTINEL_NODE NULL
#define T 1
#define F 0
void
__archive_rb_tree_init(struct archive_rb_tree *rbt,
const struct archive_rb_tree_ops *ops)
{
rbt->rbt_ops = ops;
*((struct archive_rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE;
}
struct archive_rb_node *
__archive_rb_tree_find_node(struct archive_rb_tree *rbt, const void *key)
{
archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
struct archive_rb_node *parent = rbt->rbt_root;
while (!RB_SENTINEL_P(parent)) {
const signed int diff = (*compare_key)(parent, key);
if (diff == 0)
return parent;
parent = parent->rb_nodes[diff > 0];
}
return NULL;
}
struct archive_rb_node *
__archive_rb_tree_find_node_geq(struct archive_rb_tree *rbt, const void *key)
{
archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
struct archive_rb_node *parent = rbt->rbt_root;
struct archive_rb_node *last = NULL;
while (!RB_SENTINEL_P(parent)) {
const signed int diff = (*compare_key)(parent, key);
if (diff == 0)
return parent;
if (diff < 0)
last = parent;
parent = parent->rb_nodes[diff > 0];
}
return last;
}
struct archive_rb_node *
__archive_rb_tree_find_node_leq(struct archive_rb_tree *rbt, const void *key)
{
archive_rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
struct archive_rb_node *parent = rbt->rbt_root;
struct archive_rb_node *last = NULL;
while (!RB_SENTINEL_P(parent)) {
const signed int diff = (*compare_key)(parent, key);
if (diff == 0)
return parent;
if (diff > 0)
last = parent;
parent = parent->rb_nodes[diff > 0];
}
return last;
}
int
__archive_rb_tree_insert_node(struct archive_rb_tree *rbt,
struct archive_rb_node *self)
{
archive_rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes;
struct archive_rb_node *parent, *tmp;
unsigned int position;
int rebalance;
tmp = rbt->rbt_root;
/*
* This is a hack. Because rbt->rbt_root is just a
* struct archive_rb_node *, just like rb_node->rb_nodes[RB_DIR_LEFT],
* we can use this fact to avoid a lot of tests for root and know
* that even at root, updating
* RB_FATHER(rb_node)->rb_nodes[RB_POSITION(rb_node)] will
* update rbt->rbt_root.
*/
parent = (struct archive_rb_node *)(void *)&rbt->rbt_root;
position = RB_DIR_LEFT;
/*
* Find out where to place this new leaf.
*/
while (!RB_SENTINEL_P(tmp)) {
const signed int diff = (*compare_nodes)(tmp, self);
if (diff == 0) {
/*
* Node already exists; don't insert.
*/
return F;
}
parent = tmp;
position = (diff > 0);
tmp = parent->rb_nodes[position];
}
/*
* Initialize the node and insert as a leaf into the tree.
*/
RB_SET_FATHER(self, parent);
RB_SET_POSITION(self, position);
if (parent == (struct archive_rb_node *)(void *)&rbt->rbt_root) {
RB_MARK_BLACK(self); /* root is always black */
rebalance = F;
} else {
/*
* All new nodes are colored red. We only need to rebalance
* if our parent is also red.
*/
RB_MARK_RED(self);
rebalance = RB_RED_P(parent);
}
self->rb_left = parent->rb_nodes[position];
self->rb_right = parent->rb_nodes[position];
parent->rb_nodes[position] = self;
/*
* Rebalance tree after insertion
*/
if (rebalance)
__archive_rb_tree_insert_rebalance(rbt, self);
return T;
}
/*
* Swap the location and colors of 'self' and its child @ which. The child
* can not be a sentinel node. This is our rotation function. However,
* since it preserves coloring, it great simplifies both insertion and
* removal since rotation almost always involves the exchanging of colors
* as a separate step.
*/
/*ARGSUSED*/
static void
__archive_rb_tree_reparent_nodes(
struct archive_rb_node *old_father, const unsigned int which)
{
const unsigned int other = which ^ RB_DIR_OTHER;
struct archive_rb_node * const grandpa = RB_FATHER(old_father);
struct archive_rb_node * const old_child = old_father->rb_nodes[which];
struct archive_rb_node * const new_father = old_child;
struct archive_rb_node * const new_child = old_father;
/*
* Exchange descendant linkages.
*/
grandpa->rb_nodes[RB_POSITION(old_father)] = new_father;
new_child->rb_nodes[which] = old_child->rb_nodes[other];
new_father->rb_nodes[other] = new_child;
/*
* Update ancestor linkages
*/
RB_SET_FATHER(new_father, grandpa);
RB_SET_FATHER(new_child, new_father);
/*
* Exchange properties between new_father and new_child. The only
* change is that new_child's position is now on the other side.
*/
RB_SWAP_PROPERTIES(new_father, new_child);
RB_SET_POSITION(new_child, other);
/*
* Make sure to reparent the new child to ourself.
*/
if (!RB_SENTINEL_P(new_child->rb_nodes[which])) {
RB_SET_FATHER(new_child->rb_nodes[which], new_child);
RB_SET_POSITION(new_child->rb_nodes[which], which);
}
}
static void
__archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt,
struct archive_rb_node *self)
{
struct archive_rb_node * father = RB_FATHER(self);
struct archive_rb_node * grandpa;
struct archive_rb_node * uncle;
unsigned int which;
unsigned int other;
for (;;) {
/*
* We are red and our parent is red, therefore we must have a
* grandfather and he must be black.
*/
grandpa = RB_FATHER(father);
which = (father == grandpa->rb_right);
other = which ^ RB_DIR_OTHER;
uncle = grandpa->rb_nodes[other];
if (RB_BLACK_P(uncle))
break;
/*
* Case 1: our uncle is red
* Simply invert the colors of our parent and
* uncle and make our grandparent red. And
* then solve the problem up at his level.
*/
RB_MARK_BLACK(uncle);
RB_MARK_BLACK(father);
if (RB_ROOT_P(rbt, grandpa)) {
/*
* If our grandpa is root, don't bother
* setting him to red, just return.
*/
return;
}
RB_MARK_RED(grandpa);
self = grandpa;
father = RB_FATHER(self);
if (RB_BLACK_P(father)) {
/*
* If our greatgrandpa is black, we're done.
*/
return;
}
}
/*
* Case 2&3: our uncle is black.
*/
if (self == father->rb_nodes[other]) {
/*
* Case 2: we are on the same side as our uncle
* Swap ourselves with our parent so this case
* becomes case 3. Basically our parent becomes our
* child.
*/
__archive_rb_tree_reparent_nodes(father, other);
}
/*
* Case 3: we are opposite a child of a black uncle.
* Swap our parent and grandparent. Since our grandfather
* is black, our father will become black and our new sibling
* (former grandparent) will become red.
*/
__archive_rb_tree_reparent_nodes(grandpa, which);
/*
* Final step: Set the root to black.
*/
RB_MARK_BLACK(rbt->rbt_root);
}
static void
__archive_rb_tree_prune_node(struct archive_rb_tree *rbt,
struct archive_rb_node *self, int rebalance)
{
const unsigned int which = RB_POSITION(self);
struct archive_rb_node *father = RB_FATHER(self);
/*
* Since we are childless, we know that self->rb_left is pointing
* to the sentinel node.
*/
father->rb_nodes[which] = self->rb_left;
/*
* Rebalance if requested.
*/
if (rebalance)
__archive_rb_tree_removal_rebalance(rbt, father, which);
}
/*
* When deleting an interior node
*/
static void
__archive_rb_tree_swap_prune_and_rebalance(struct archive_rb_tree *rbt,
struct archive_rb_node *self, struct archive_rb_node *standin)
{
const unsigned int standin_which = RB_POSITION(standin);
unsigned int standin_other = standin_which ^ RB_DIR_OTHER;
struct archive_rb_node *standin_son;
struct archive_rb_node *standin_father = RB_FATHER(standin);
int rebalance = RB_BLACK_P(standin);
if (standin_father == self) {
/*
* As a child of self, any children would be opposite of
* our parent.
*/
standin_son = standin->rb_nodes[standin_which];
} else {
/*
* Since we aren't a child of self, any children would be
* on the same side as our parent.
*/
standin_son = standin->rb_nodes[standin_other];
}
if (RB_RED_P(standin_son)) {
/*
* We know we have a red child so if we flip it to black
* we don't have to rebalance.
*/
RB_MARK_BLACK(standin_son);
rebalance = F;
if (standin_father != self) {
/*
* Change the son's parentage to point to his grandpa.
*/
RB_SET_FATHER(standin_son, standin_father);
RB_SET_POSITION(standin_son, standin_which);
}
}
if (standin_father == self) {
/*
* If we are about to delete the standin's father, then when
* we call rebalance, we need to use ourselves as our father.
* Otherwise remember our original father. Also, since we are
* our standin's father we only need to reparent the standin's
* brother.
*
* | R --> S |
* | Q S --> Q T |
* | t --> |
*
* Have our son/standin adopt his brother as his new son.
*/
standin_father = standin;
} else {
/*
* | R --> S . |
* | / \ | T --> / \ | / |
* | ..... | S --> ..... | T |
*
* Sever standin's connection to his father.
*/
standin_father->rb_nodes[standin_which] = standin_son;
/*
* Adopt the far son.
*/
standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];
RB_SET_FATHER(standin->rb_nodes[standin_other], standin);
/*
* Use standin_other because we need to preserve standin_which
* for the removal_rebalance.
*/
standin_other = standin_which;
}
/*
* Move the only remaining son to our standin. If our standin is our
* son, this will be the only son needed to be moved.
*/
standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];
RB_SET_FATHER(standin->rb_nodes[standin_other], standin);
/*
* Now copy the result of self to standin and then replace
* self with standin in the tree.
*/
RB_COPY_PROPERTIES(standin, self);
RB_SET_FATHER(standin, RB_FATHER(self));
RB_FATHER(standin)->rb_nodes[RB_POSITION(standin)] = standin;
if (rebalance)
__archive_rb_tree_removal_rebalance(rbt, standin_father, standin_which);
}
/*
* We could do this by doing
* __archive_rb_tree_node_swap(rbt, self, which);
* __archive_rb_tree_prune_node(rbt, self, F);
*
* But it's more efficient to just evaluate and recolor the child.
*/
static void
__archive_rb_tree_prune_blackred_branch(
struct archive_rb_node *self, unsigned int which)
{
struct archive_rb_node *father = RB_FATHER(self);
struct archive_rb_node *son = self->rb_nodes[which];
/*
* Remove ourselves from the tree and give our former child our
* properties (position, color, root).
*/
RB_COPY_PROPERTIES(son, self);
father->rb_nodes[RB_POSITION(son)] = son;
RB_SET_FATHER(son, father);
}
/*
*
*/
void
__archive_rb_tree_remove_node(struct archive_rb_tree *rbt,
struct archive_rb_node *self)
{
struct archive_rb_node *standin;
unsigned int which;
/*
* In the following diagrams, we (the node to be removed) are S. Red
* nodes are lowercase. T could be either red or black.
*
* Remember the major axiom of the red-black tree: the number of
* black nodes from the root to each leaf is constant across all
* leaves, only the number of red nodes varies.
*
* Thus removing a red leaf doesn't require any other changes to a
* red-black tree. So if we must remove a node, attempt to rearrange
* the tree so we can remove a red node.
*
* The simplest case is a childless red node or a childless root node:
*
* | T --> T | or | R --> * |
* | s --> * |
*/
if (RB_CHILDLESS_P(self)) {
const int rebalance = RB_BLACK_P(self) && !RB_ROOT_P(rbt, self);
__archive_rb_tree_prune_node(rbt, self, rebalance);
return;
}
if (!RB_TWOCHILDREN_P(self)) {
/*
* The next simplest case is the node we are deleting is
* black and has one red child.
*
* | T --> T --> T |
* | S --> R --> R |
* | r --> s --> * |
*/
which = RB_LEFT_SENTINEL_P(self) ? RB_DIR_RIGHT : RB_DIR_LEFT;
__archive_rb_tree_prune_blackred_branch(self, which);
return;
}
/*
* We invert these because we prefer to remove from the inside of
* the tree.
*/
which = RB_POSITION(self) ^ RB_DIR_OTHER;
/*
* Let's find the node closes to us opposite of our parent
* Now swap it with ourself, "prune" it, and rebalance, if needed.
*/
standin = __archive_rb_tree_iterate(rbt, self, which);
__archive_rb_tree_swap_prune_and_rebalance(rbt, self, standin);
}
static void
__archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
struct archive_rb_node *parent, unsigned int which)
{
while (RB_BLACK_P(parent->rb_nodes[which])) {
unsigned int other = which ^ RB_DIR_OTHER;
struct archive_rb_node *brother = parent->rb_nodes[other];
/*
* For cases 1, 2a, and 2b, our brother's children must
* be black and our father must be black
*/
if (RB_BLACK_P(parent)
&& RB_BLACK_P(brother->rb_left)
&& RB_BLACK_P(brother->rb_right)) {
if (RB_RED_P(brother)) {
/*
* Case 1: Our brother is red, swap its
* position (and colors) with our parent.
* This should now be case 2b (unless C or E
* has a red child which is case 3; thus no
* explicit branch to case 2b).
*
* B -> D
* A d -> b E
* C E -> A C
*/
__archive_rb_tree_reparent_nodes(parent, other);
brother = parent->rb_nodes[other];
} else {
/*
* Both our parent and brother are black.
* Change our brother to red, advance up rank
* and go through the loop again.
*
* B -> *B
* *A D -> A d
* C E -> C E
*/
RB_MARK_RED(brother);
if (RB_ROOT_P(rbt, parent))
return; /* root == parent == black */
which = RB_POSITION(parent);
parent = RB_FATHER(parent);
continue;
}
}
/*
* Avoid an else here so that case 2a above can hit either
* case 2b, 3, or 4.
*/
if (RB_RED_P(parent)
&& RB_BLACK_P(brother)
&& RB_BLACK_P(brother->rb_left)
&& RB_BLACK_P(brother->rb_right)) {
/*
* We are black, our father is red, our brother and
* both nephews are black. Simply invert/exchange the
* colors of our father and brother (to black and red
* respectively).
*
* | f --> F |
* | * B --> * b |
* | N N --> N N |
*/
RB_MARK_BLACK(parent);
RB_MARK_RED(brother);
break; /* We're done! */
} else {
/*
* Our brother must be black and have at least one
* red child (it may have two).
*/
if (RB_BLACK_P(brother->rb_nodes[other])) {
/*
* Case 3: our brother is black, our near
* nephew is red, and our far nephew is black.
* Swap our brother with our near nephew.
* This result in a tree that matches case 4.
* (Our father could be red or black).
*
* | F --> F |
* | x B --> x B |
* | n --> n |
*/
__archive_rb_tree_reparent_nodes(brother, which);
brother = parent->rb_nodes[other];
}
/*
* Case 4: our brother is black and our far nephew
* is red. Swap our father and brother locations and
* change our far nephew to black. (these can be
* done in either order so we change the color first).
* The result is a valid red-black tree and is a
* terminal case. (again we don't care about the
* father's color)
*
* If the father is red, we will get a red-black-black
* tree:
* | f -> f --> b |
* | B -> B --> F N |
* | n -> N --> |
*
* If the father is black, we will get an all black
* tree:
* | F -> F --> B |
* | B -> B --> F N |
* | n -> N --> |
*
* If we had two red nephews, then after the swap,
* our former father would have a red grandson.
*/
RB_MARK_BLACK(brother->rb_nodes[other]);
__archive_rb_tree_reparent_nodes(parent, other);
break; /* We're done! */
}
}
}
struct archive_rb_node *
__archive_rb_tree_iterate(struct archive_rb_tree *rbt,
struct archive_rb_node *self, const unsigned int direction)
{
const unsigned int other = direction ^ RB_DIR_OTHER;
if (self == NULL) {
self = rbt->rbt_root;
if (RB_SENTINEL_P(self))
return NULL;
while (!RB_SENTINEL_P(self->rb_nodes[direction]))
self = self->rb_nodes[direction];
return self;
}
/*
* We can't go any further in this direction. We proceed up in the
* opposite direction until our parent is in direction we want to go.
*/
if (RB_SENTINEL_P(self->rb_nodes[direction])) {
while (!RB_ROOT_P(rbt, self)) {
if (other == (unsigned int)RB_POSITION(self))
return RB_FATHER(self);
self = RB_FATHER(self);
}
return NULL;
}
/*
* Advance down one in current direction and go down as far as possible
* in the opposite direction.
*/
self = self->rb_nodes[direction];
while (!RB_SENTINEL_P(self->rb_nodes[other]))
self = self->rb_nodes[other];
return self;
}

View File

@ -0,0 +1,100 @@
/*-
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Thomas <matt@3am-software.com>.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*
* Based on NetBSD: rb.h,v 1.13 2009/08/16 10:57:01 yamt Exp
*/
#ifndef ARCHIVE_RB_H_
#define ARCHIVE_RB_H_
struct archive_rb_node {
struct archive_rb_node *rb_nodes[2];
/*
* rb_info contains the two flags and the parent back pointer.
* We put the two flags in the low two bits since we know that
* rb_node will have an alignment of 4 or 8 bytes.
*/
uintptr_t rb_info;
};
#define ARCHIVE_RB_DIR_LEFT 0
#define ARCHIVE_RB_DIR_RIGHT 1
#define ARCHIVE_RB_TREE_MIN(T) \
__archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_LEFT)
#define ARCHIVE_RB_TREE_MAX(T) \
__archive_rb_tree_iterate((T), NULL, ARCHIVE_RB_DIR_RIGHT)
#define ARCHIVE_RB_TREE_FOREACH(N, T) \
for ((N) = ARCHIVE_RB_TREE_MIN(T); (N); \
(N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_RIGHT))
#define ARCHIVE_RB_TREE_FOREACH_REVERSE(N, T) \
for ((N) = ARCHIVE_RB_TREE_MAX(T); (N); \
(N) = __archive_rb_tree_iterate((T), (N), ARCHIVE_RB_DIR_LEFT))
/*
* archive_rbto_compare_nodes_fn:
* return a positive value if the first node < the second node.
* return a negative value if the first node > the second node.
* return 0 if they are considered same.
*
* archive_rbto_compare_key_fn:
* return a positive value if the node < the key.
* return a negative value if the node > the key.
* return 0 if they are considered same.
*/
typedef signed int (*const archive_rbto_compare_nodes_fn)(const struct archive_rb_node *,
const struct archive_rb_node *);
typedef signed int (*const archive_rbto_compare_key_fn)(const struct archive_rb_node *,
const void *);
struct archive_rb_tree_ops {
archive_rbto_compare_nodes_fn rbto_compare_nodes;
archive_rbto_compare_key_fn rbto_compare_key;
};
struct archive_rb_tree {
struct archive_rb_node *rbt_root;
const struct archive_rb_tree_ops *rbt_ops;
};
void __archive_rb_tree_init(struct archive_rb_tree *,
const struct archive_rb_tree_ops *);
int __archive_rb_tree_insert_node(struct archive_rb_tree *,
struct archive_rb_node *);
struct archive_rb_node *
__archive_rb_tree_find_node(struct archive_rb_tree *, const void *);
struct archive_rb_node *
__archive_rb_tree_find_node_geq(struct archive_rb_tree *, const void *);
struct archive_rb_node *
__archive_rb_tree_find_node_leq(struct archive_rb_tree *, const void *);
void __archive_rb_tree_remove_node(struct archive_rb_tree *, struct archive_rb_node *);
struct archive_rb_node *
__archive_rb_tree_iterate(struct archive_rb_tree *,
struct archive_rb_node *, const unsigned int);
#endif /* ARCHIVE_RB_H_*/

View File

@ -24,179 +24,14 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd April 13, 2009 .Dd March 23, 2011
.Dt ARCHIVE_READ 3 .Dt ARCHIVE_READ 3
.Os .Os
.Sh NAME .Sh NAME
.Nm archive_read_new , .Nm archive_read
.Nm archive_read_set_filter_options ,
.Nm archive_read_set_format_options ,
.Nm archive_read_set_options ,
.Nm archive_read_support_compression_all ,
.Nm archive_read_support_compression_bzip2 ,
.Nm archive_read_support_compression_compress ,
.Nm archive_read_support_compression_gzip ,
.Nm archive_read_support_compression_lzma ,
.Nm archive_read_support_compression_none ,
.Nm archive_read_support_compression_xz ,
.Nm archive_read_support_compression_program ,
.Nm archive_read_support_compression_program_signature ,
.Nm archive_read_support_format_all ,
.Nm archive_read_support_format_ar ,
.Nm archive_read_support_format_cpio ,
.Nm archive_read_support_format_empty ,
.Nm archive_read_support_format_iso9660 ,
.Nm archive_read_support_format_mtree,
.Nm archive_read_support_format_raw,
.Nm archive_read_support_format_tar ,
.Nm archive_read_support_format_zip ,
.Nm archive_read_open ,
.Nm archive_read_open2 ,
.Nm archive_read_open_fd ,
.Nm archive_read_open_FILE ,
.Nm archive_read_open_filename ,
.Nm archive_read_open_memory ,
.Nm archive_read_next_header ,
.Nm archive_read_next_header2 ,
.Nm archive_read_data ,
.Nm archive_read_data_block ,
.Nm archive_read_data_skip ,
.\" #if ARCHIVE_API_VERSION < 3
.Nm archive_read_data_into_buffer ,
.\" #endif
.Nm archive_read_data_into_fd ,
.Nm archive_read_extract ,
.Nm archive_read_extract2 ,
.Nm archive_read_extract_set_progress_callback ,
.Nm archive_read_close ,
.Nm archive_read_free
.Nd functions for reading streaming archives .Nd functions for reading streaming archives
.Sh SYNOPSIS .Sh SYNOPSIS
.In archive.h .In archive.h
.Ft struct archive *
.Fn archive_read_new "void"
.Ft int
.Fn archive_read_support_compression_all "struct archive *"
.Ft int
.Fn archive_read_support_compression_bzip2 "struct archive *"
.Ft int
.Fn archive_read_support_compression_compress "struct archive *"
.Ft int
.Fn archive_read_support_compression_gzip "struct archive *"
.Ft int
.Fn archive_read_support_compression_lzma "struct archive *"
.Ft int
.Fn archive_read_support_compression_none "struct archive *"
.Ft int
.Fn archive_read_support_compression_xz "struct archive *"
.Ft int
.Fo archive_read_support_compression_program
.Fa "struct archive *"
.Fa "const char *cmd"
.Fc
.Ft int
.Fo archive_read_support_compression_program_signature
.Fa "struct archive *"
.Fa "const char *cmd"
.Fa "const void *signature"
.Fa "size_t signature_length"
.Fc
.Ft int
.Fn archive_read_support_format_all "struct archive *"
.Ft int
.Fn archive_read_support_format_ar "struct archive *"
.Ft int
.Fn archive_read_support_format_cpio "struct archive *"
.Ft int
.Fn archive_read_support_format_empty "struct archive *"
.Ft int
.Fn archive_read_support_format_iso9660 "struct archive *"
.Ft int
.Fn archive_read_support_format_mtree "struct archive *"
.Ft int
.Fn archive_read_support_format_raw "struct archive *"
.Ft int
.Fn archive_read_support_format_tar "struct archive *"
.Ft int
.Fn archive_read_support_format_zip "struct archive *"
.Ft int
.Fn archive_read_set_filter_options "struct archive *" "const char *"
.Ft int
.Fn archive_read_set_format_options "struct archive *" "const char *"
.Ft int
.Fn archive_read_set_options "struct archive *" "const char *"
.Ft int
.Fo archive_read_open
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "archive_open_callback *"
.Fa "archive_read_callback *"
.Fa "archive_close_callback *"
.Fc
.Ft int
.Fo archive_read_open2
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "archive_open_callback *"
.Fa "archive_read_callback *"
.Fa "archive_skip_callback *"
.Fa "archive_close_callback *"
.Fc
.Ft int
.Fn archive_read_open_FILE "struct archive *" "FILE *file"
.Ft int
.Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size"
.Ft int
.Fo archive_read_open_filename
.Fa "struct archive *"
.Fa "const char *filename"
.Fa "size_t block_size"
.Fc
.Ft int
.Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size"
.Ft int
.Fn archive_read_next_header "struct archive *" "struct archive_entry **"
.Ft int
.Fn archive_read_next_header2 "struct archive *" "struct archive_entry *"
.Ft ssize_t
.Fn archive_read_data "struct archive *" "void *buff" "size_t len"
.Ft int
.Fo archive_read_data_block
.Fa "struct archive *"
.Fa "const void **buff"
.Fa "size_t *len"
.Fa "off_t *offset"
.Fc
.Ft int
.Fn archive_read_data_skip "struct archive *"
.\" #if ARCHIVE_API_VERSION < 3
.Ft int
.Fn archive_read_data_into_buffer "struct archive *" "void *" "ssize_t len"
.\" #endif
.Ft int
.Fn archive_read_data_into_fd "struct archive *" "int fd"
.Ft int
.Fo archive_read_extract
.Fa "struct archive *"
.Fa "struct archive_entry *"
.Fa "int flags"
.Fc
.Ft int
.Fo archive_read_extract2
.Fa "struct archive *src"
.Fa "struct archive_entry *"
.Fa "struct archive *dest"
.Fc
.Ft void
.Fo archive_read_extract_set_progress_callback
.Fa "struct archive *"
.Fa "void (*func)(void *)"
.Fa "void *user_data"
.Fc
.Ft int
.Fn archive_read_close "struct archive *"
.Ft int
.Fn archive_read_free "struct archive *"
.Sh DESCRIPTION .Sh DESCRIPTION
These functions provide a complete API for reading streaming archives. These functions provide a complete API for reading streaming archives.
The general process is to first create the The general process is to first create the
@ -204,375 +39,120 @@ The general process is to first create the
object, set options, initialize the reader, iterate over the archive object, set options, initialize the reader, iterate over the archive
headers and associated data, then close the archive and release all headers and associated data, then close the archive and release all
resources. resources.
The following summary describes the functions in approximately the .\"
order they would be used: .Ss Create archive object
.Bl -tag -compact -width indent See
.It Fn archive_read_new .Xr archive_read_new 3 .
Allocates and initializes a
.Tn struct archive
object suitable for reading from an archive.
.It Xo
.Fn archive_read_support_compression_bzip2 ,
.Fn archive_read_support_compression_compress ,
.Fn archive_read_support_compression_gzip ,
.Fn archive_read_support_compression_lzma ,
.Fn archive_read_support_compression_none ,
.Fn archive_read_support_compression_xz
.Xc
Enables auto-detection code and decompression support for the
specified compression.
Returns
.Cm ARCHIVE_OK
if the compression is fully supported, or
.Cm ARCHIVE_WARN
if the compression is supported only through an external program.
Note that decompression using an external program is usually slower than
decompression through built-in libraries.
Note that
.Dq none
is always enabled by default.
.It Fn archive_read_support_compression_all
Enables all available decompression filters.
.It Fn archive_read_support_compression_program
Data is fed through the specified external program before being dearchived.
Note that this disables automatic detection of the compression format,
so it makes no sense to specify this in conjunction with any other
decompression option.
.It Fn archive_read_support_compression_program_signature
This feeds data through the specified external program
but only if the initial bytes of the data match the specified
signature value.
.It Xo
.Fn archive_read_support_format_all ,
.Fn archive_read_support_format_ar ,
.Fn archive_read_support_format_cpio ,
.Fn archive_read_support_format_empty ,
.Fn archive_read_support_format_iso9660 ,
.Fn archive_read_support_format_mtree ,
.Fn archive_read_support_format_tar ,
.Fn archive_read_support_format_zip
.Xc
Enables support---including auto-detection code---for the
specified archive format.
For example,
.Fn archive_read_support_format_tar
enables support for a variety of standard tar formats, old-style tar,
ustar, pax interchange format, and many common variants.
For convenience,
.Fn archive_read_support_format_all
enables support for all available formats.
Only empty archives are supported by default.
.It Fn archive_read_support_format_raw
The
.Dq raw
format handler allows libarchive to be used to read arbitrary data.
It treats any data stream as an archive with a single entry.
The pathname of this entry is
.Dq data ;
all other entry fields are unset.
This is not enabled by
.Fn archive_read_support_format_all
in order to avoid erroneous handling of damaged archives.
.It Xo
.Fn archive_read_set_filter_options ,
.Fn archive_read_set_format_options ,
.Fn archive_read_set_options
.Xc
Specifies options that will be passed to currently-registered
filters (including decompression filters) and/or format readers.
The argument is a comma-separated list of individual options.
Individual options have one of the following forms:
.Bl -tag -compact -width indent
.It Ar option=value
The option/value pair will be provided to every module.
Modules that do not accept an option with this name will ignore it.
.It Ar option
The option will be provided to every module with a value of
.Dq 1 .
.It Ar !option
The option will be provided to every module with a NULL value.
.It Ar module:option=value , Ar module:option , Ar module:!option
As above, but the corresponding option and value will be provided
only to modules whose name matches
.Ar module .
.El
The return value will be
.Cm ARCHIVE_OK
if any module accepts the option, or
.Cm ARCHIVE_WARN
if no module accepted the option, or
.Cm ARCHIVE_FATAL
if there was a fatal error while attempting to process the option.
.Pp .Pp
The currently supported options are: To read an archive, you must first obtain an initialized
.Bl -tag -compact -width indent .Tn struct archive
.It Format iso9660 object from
.Bl -tag -compact -width indent .Fn archive_read_new .
.It Cm joliet .\"
Support Joliet extensions. .Ss Enable filters and formats
Defaults to enabled, use See
.Cm !joliet .Xr archive_read_filter 3
to disable. and
.El .Xr archive_read_format 3 .
.El .Pp
.It Fn archive_read_open You can then modify this object for the desired operations with the
The same as various
.Fn archive_read_open2 , .Fn archive_read_set_XXX
except that the skip callback is assumed to be and
.Dv NULL . .Fn archive_read_support_XXX
.It Fn archive_read_open2 functions.
Freeze the settings, open the archive, and prepare for reading entries. In particular, you will need to invoke appropriate
This is the most generic version of this call, which accepts .Fn archive_read_support_XXX
four callback functions. functions to enable the corresponding compression and format
Most clients will want to use support.
.Fn archive_read_open_filename , Note that these latter functions perform two distinct operations:
.Fn archive_read_open_FILE , they cause the corresponding support code to be linked into your
.Fn archive_read_open_fd , program, and they enable the corresponding auto-detect code.
or Unless you have specific constraints, you will generally want
.Fn archive_read_open_memory to invoke
instead. .Fn archive_read_support_filter_all
The library invokes the client-provided functions to obtain and
raw bytes from the archive. .Fn archive_read_support_format_all
.It Fn archive_read_open_FILE to enable auto-detect for all formats and compression types
Like currently supported by the library.
.Fn archive_read_open , .\"
except that it accepts a .Ss Set options
See
.Xr archive_read_set_options 3 .
.\"
.Ss Open archive
See
.Xr archive_read_open 3 .
.Pp
Once you have prepared the
.Tn struct archive
object, you call
.Fn archive_read_open
to actually open the archive and prepare it for reading.
There are several variants of this function;
the most basic expects you to provide pointers to several
functions that can provide blocks of bytes from the archive.
There are convenience forms that allow you to
specify a filename, file descriptor,
.Ft "FILE *" .Ft "FILE *"
pointer. object, or a block of memory from which to read the archive data.
This function should not be used with tape drives or other devices Note that the core library makes no assumptions about the
that require strict I/O blocking. size of the blocks read;
.It Fn archive_read_open_fd callback functions are free to read whatever block size is
Like most appropriate for the medium.
.Fn archive_read_open , .\"
except that it accepts a file descriptor and block size rather than .Ss Consume archive
a set of function pointers. See
Note that the file descriptor will not be automatically closed at .Xr archive_read_header 3 ,
end-of-archive. .Xr archive_read_data 3
This function is safe for use with tape drives or other blocked devices. and
.It Fn archive_read_open_file .Xr archive_read_extract 3 .
This is a deprecated synonym for .Pp
.Fn archive_read_open_filename . Each archive entry consists of a header followed by a certain
.It Fn archive_read_open_filename amount of data.
Like You can obtain the next header with
.Fn archive_read_open , .Fn archive_read_next_header ,
except that it accepts a simple filename and a block size. which returns a pointer to an
A NULL filename represents standard input.
This function is safe for use with tape drives or other blocked devices.
.It Fn archive_read_open_memory
Like
.Fn archive_read_open ,
except that it accepts a pointer and size of a block of
memory containing the archive data.
.It Fn archive_read_next_header
Read the header for the next entry and return a pointer to
a
.Tn struct archive_entry .
This is a convenience wrapper around
.Fn archive_read_next_header2
that reuses an internal
.Tn struct archive_entry .Tn struct archive_entry
object for each request. structure with information about the current archive element.
.It Fn archive_read_next_header2 If the entry is a regular file, then the header will be followed
Read the header for the next entry and populate the provided by the file data.
.Tn struct archive_entry . You can use
.It Fn archive_read_data
Read data associated with the header just read.
Internally, this is a convenience function that calls
.Fn archive_read_data_block
and fills any gaps with nulls so that callers see a single
continuous stream of data.
.It Fn archive_read_data_block
Return the next available block of data for this entry.
Unlike
.Fn archive_read_data ,
the
.Fn archive_read_data_block
function avoids copying data and allows you to correctly handle
sparse files, as supported by some archive formats.
The library guarantees that offsets will increase and that blocks
will not overlap.
Note that the blocks returned from this function can be much larger
than the block size read from disk, due to compression
and internal buffer optimizations.
.It Fn archive_read_data_skip
A convenience function that repeatedly calls
.Fn archive_read_data_block
to skip all of the data for this archive entry.
.\" #if ARCHIVE_API_VERSION < 3
.It Fn archive_read_data_into_buffer
This function is deprecated and will be removed.
Use
.Fn archive_read_data .Fn archive_read_data
instead. (which works much like the
.\" #endif .Xr read 2
.It Fn archive_read_data_into_fd system call)
A convenience function that repeatedly calls to read this data from the archive, or
.Fn archive_read_data_block .Fn archive_read_data_block
to copy the entire entry to the provided file descriptor. which provides a slightly more efficient interface.
.It Fn archive_read_extract , Fn archive_read_extract_set_skip_file You may prefer to use the higher-level
A convenience function that wraps the corresponding .Fn archive_read_data_skip ,
.Xr archive_write_disk 3 which reads and discards the data for this entry,
interfaces. .Fn archive_read_data_to_file ,
The first call to which copies the data to the provided file descriptor, or
.Fn archive_read_extract ,
which recreates the specified entry on disk and copies data
from the archive.
In particular, note that
.Fn archive_read_extract .Fn archive_read_extract
creates a restore object using uses the
.Xr archive_write_disk_new 3
and
.Xr archive_write_disk_set_standard_lookup 3 ,
then transparently invokes
.Xr archive_write_disk_set_options 3 ,
.Xr archive_write_header 3 ,
.Xr archive_write_data 3 ,
and
.Xr archive_write_finish_entry 3
to create the entry on disk and copy data into it.
The
.Va flags
argument is passed unmodified to
.Xr archive_write_disk_set_options 3 .
.It Fn archive_read_extract2
This is another version of
.Fn archive_read_extract
that allows you to provide your own restore object.
In particular, this allows you to override the standard lookup functions
using
.Xr archive_write_disk_set_group_lookup 3 ,
and
.Xr archive_write_disk_set_user_lookup 3 .
Note that
.Fn archive_read_extract2
does not accept a
.Va flags
argument; you should use
.Fn archive_write_disk_set_options
to set the restore options yourself.
.It Fn archive_read_extract_set_progress_callback
Sets a pointer to a user-defined callback that can be used
for updating progress displays during extraction.
The progress function will be invoked during the extraction of large
regular files.
The progress function will be invoked with the pointer provided to this call.
Generally, the data pointed to should include a reference to the archive
object and the archive_entry object so that various statistics
can be retrieved for the progress display.
.It Fn archive_read_close
Complete the archive and invoke the close callback.
.It Fn archive_read_free
Invokes
.Fn archive_read_close
if it was not invoked manually, then release all resources.
Note: In libarchive 1.x, this function was declared to return
.Ft void ,
which made it impossible to detect certain errors when
.Fn archive_read_close
was invoked implicitly from this function.
The declaration is corrected beginning with libarchive 2.0.
.El
.Pp
Note that the library determines most of the relevant information about
the archive by inspection.
In particular, it automatically detects
.Xr gzip 1
or
.Xr bzip2 1
compression and transparently performs the appropriate decompression.
It also automatically detects the archive format.
.Pp
A complete description of the
.Tn struct archive
and
.Tn struct archive_entry .Tn struct archive_entry
objects can be found in the overview manual page for structure that you provide it, which may differ from the
.Xr libarchive 3 . entry just read from the archive.
.Sh CLIENT CALLBACKS In particular, many applications will want to override the
The callback functions must match the following prototypes: pathname, file permissions, or ownership.
.Bl -item -offset indent .\"
.It .Ss Release resources
.Ft typedef ssize_t See
.Fo archive_read_callback .Xr archive_read_free 3 .
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "const void **buffer"
.Fc
.It
.\" #if ARCHIVE_API_VERSION < 2
.Ft typedef int
.Fo archive_skip_callback
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "size_t request"
.Fc
.\" #else
.\" .Ft typedef off_t
.\" .Fo archive_skip_callback
.\" .Fa "struct archive *"
.\" .Fa "void *client_data"
.\" .Fa "off_t request"
.\" .Fc
.\" #endif
.It
.Ft typedef int
.Fn archive_open_callback "struct archive *" "void *client_data"
.It
.Ft typedef int
.Fn archive_close_callback "struct archive *" "void *client_data"
.El
.Pp .Pp
The open callback is invoked by Once you have finished reading data from the archive, you
.Fn archive_open . should call
It should return .Fn archive_read_close
.Cm ARCHIVE_OK to close the archive, then call
if the underlying file or data source is successfully .Fn archive_read_free
opened. to release all resources, including all memory allocated by the library.
If the open fails, it should call .\"
.Fn archive_set_error
to register an error code and message and return
.Cm ARCHIVE_FATAL .
.Pp
The read callback is invoked whenever the library
requires raw bytes from the archive.
The read callback should read data into a buffer,
set the
.Li const void **buffer
argument to point to the available data, and
return a count of the number of bytes available.
The library will invoke the read callback again
only after it has consumed this data.
The library imposes no constraints on the size
of the data blocks returned.
On end-of-file, the read callback should
return zero.
On error, the read callback should invoke
.Fn archive_set_error
to register an error code and message and
return -1.
.Pp
The skip callback is invoked when the
library wants to ignore a block of data.
The return value is the number of bytes actually
skipped, which may differ from the request.
If the callback cannot skip data, it should return
zero.
If the skip callback is not provided (the
function pointer is
.Dv NULL ),
the library will invoke the read function
instead and simply discard the result.
A skip callback can provide significant
performance gains when reading uncompressed
archives from slow disk drives or other media
that can skip quickly.
.Pp
The close callback is invoked by archive_close when
the archive processing is complete.
The callback should return
.Cm ARCHIVE_OK
on success.
On failure, the callback should invoke
.Fn archive_set_error
to register an error code and message and
return
.Cm ARCHIVE_FATAL.
.Sh EXAMPLE .Sh EXAMPLE
The following illustrates basic usage of the library. The following illustrates basic usage of the library.
In this example, In this example,
@ -593,7 +173,7 @@ list_archive(const char *name)
mydata = malloc(sizeof(struct mydata)); mydata = malloc(sizeof(struct mydata));
a = archive_read_new(); a = archive_read_new();
mydata->name = name; mydata->name = name;
archive_read_support_compression_all(a); archive_read_support_filter_all(a);
archive_read_support_format_all(a); archive_read_support_format_all(a);
archive_read_open(a, mydata, myopen, myread, myclose); archive_read_open(a, mydata, myopen, myread, myclose);
while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { while (archive_read_next_header(a, &entry) == ARCHIVE_OK) {
@ -632,62 +212,18 @@ myclose(struct archive *a, void *client_data)
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
.Ed .Ed
.Sh RETURN VALUES
Most functions return zero on success, non-zero on error.
The possible return codes include:
.Cm ARCHIVE_OK
(the operation succeeded),
.Cm ARCHIVE_WARN
(the operation succeeded but a non-critical error was encountered),
.Cm ARCHIVE_EOF
(end-of-archive was encountered),
.Cm ARCHIVE_RETRY
(the operation failed but can be retried),
and
.Cm ARCHIVE_FATAL
(there was a fatal error; the archive should be closed immediately).
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.Pp
.Fn archive_read_new
returns a pointer to a freshly allocated
.Tn struct archive
object.
It returns
.Dv NULL
on error.
.Pp
.Fn archive_read_data
returns a count of bytes actually read or zero at the end of the entry.
On error, a value of
.Cm ARCHIVE_FATAL ,
.Cm ARCHIVE_WARN ,
or
.Cm ARCHIVE_RETRY
is returned and an error code and textual description can be retrieved from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.Pp
The library expects the client callbacks to behave similarly.
If there is an error, you can use
.Fn archive_set_error
to set an appropriate error code and description,
then return one of the non-zero values above.
(Note that the value eventually returned to the client may
not be the same; many errors that are not critical at the level
of basic I/O can prevent the archive from being properly read,
thus most I/O errors eventually cause
.Cm ARCHIVE_FATAL
to be returned.)
.\" .Sh ERRORS .\" .Sh ERRORS
.Sh SEE ALSO .Sh SEE ALSO
.Xr tar 1 , .Xr tar 1 ,
.Xr archive 3 , .Xr libarchive 3 ,
.Xr archive_read_new 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_extract 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_header 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 , .Xr archive_util 3 ,
.Xr tar 5 .Xr tar 5
.Sh HISTORY .Sh HISTORY

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,128 @@
.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
.\"
.Dd March 22, 2011
.Dt ARCHIVE_READ_DATA 3
.Os
.Sh NAME
.Nm archive_read_data
.Nm archive_read_data_block ,
.Nm archive_read_data_skip ,
.Nm archive_read_data_into_fd
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft ssize_t
.Fn archive_read_data "struct archive *" "void *buff" "size_t len"
.Ft int
.Fo archive_read_data_block
.Fa "struct archive *"
.Fa "const void **buff"
.Fa "size_t *len"
.Fa "off_t *offset"
.Fc
.Ft int
.Fn archive_read_data_skip "struct archive *"
.Ft int
.Fn archive_read_data_into_fd "struct archive *" "int fd"
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_data
Read data associated with the header just read.
Internally, this is a convenience function that calls
.Fn archive_read_data_block
and fills any gaps with nulls so that callers see a single
continuous stream of data.
.It Fn archive_read_data_block
Return the next available block of data for this entry.
Unlike
.Fn archive_read_data ,
the
.Fn archive_read_data_block
function avoids copying data and allows you to correctly handle
sparse files, as supported by some archive formats.
The library guarantees that offsets will increase and that blocks
will not overlap.
Note that the blocks returned from this function can be much larger
than the block size read from disk, due to compression
and internal buffer optimizations.
.It Fn archive_read_data_skip
A convenience function that repeatedly calls
.Fn archive_read_data_block
to skip all of the data for this archive entry.
Note that this function is invoked automatically by
.Fn archive_read_next_header2
if the previous entry was not completely consumed.
.It Fn archive_read_data_into_fd
A convenience function that repeatedly calls
.Fn archive_read_data_block
to copy the entire entry to the provided file descriptor.
.El
.\"
.Sh RETURN VALUES
Most functions return zero on success, non-zero on error.
The possible return codes include:
.Cm ARCHIVE_OK
(the operation succeeded),
.Cm ARCHIVE_WARN
(the operation succeeded but a non-critical error was encountered),
.Cm ARCHIVE_EOF
(end-of-archive was encountered),
.Cm ARCHIVE_RETRY
(the operation failed but can be retried),
and
.Cm ARCHIVE_FATAL
(there was a fatal error; the archive should be closed immediately).
.Pp
.Fn archive_read_data
returns a count of bytes actually read or zero at the end of the entry.
On error, a value of
.Cm ARCHIVE_FATAL ,
.Cm ARCHIVE_WARN ,
or
.Cm ARCHIVE_RETRY
is returned.
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_extract 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_header 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -45,31 +45,68 @@ __FBSDID("$FreeBSD$");
/* /*
* This implementation minimizes copying of data and is sparse-file aware. * This implementation minimizes copying of data and is sparse-file aware.
*/ */
static int
pad_to(struct archive *a, int fd, int can_lseek,
size_t nulls_size, const char *nulls,
int64_t target_offset, int64_t actual_offset)
{
size_t to_write;
ssize_t bytes_written;
if (can_lseek) {
actual_offset = lseek(fd,
target_offset - actual_offset, SEEK_CUR);
if (actual_offset != target_offset) {
archive_set_error(a, errno, "Seek error");
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
}
while (target_offset > actual_offset) {
to_write = nulls_size;
if (target_offset < actual_offset + (int64_t)nulls_size)
to_write = (size_t)(target_offset - actual_offset);
bytes_written = write(fd, nulls, to_write);
if (bytes_written < 0) {
archive_set_error(a, errno, "Write error");
return (ARCHIVE_FATAL);
}
actual_offset += bytes_written;
}
return (ARCHIVE_OK);
}
int int
archive_read_data_into_fd(struct archive *a, int fd) archive_read_data_into_fd(struct archive *a, int fd)
{ {
int r; struct stat st;
int r, r2;
const void *buff; const void *buff;
size_t size, bytes_to_write; size_t size, bytes_to_write;
ssize_t bytes_written, total_written; ssize_t bytes_written;
off_t offset; int64_t target_offset;
off_t output_offset; int64_t actual_offset = 0;
int can_lseek;
char *nulls = NULL;
size_t nulls_size = 16384;
__archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_into_fd"); archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
"archive_read_data_into_fd");
total_written = 0; can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode);
output_offset = 0; if (!can_lseek)
nulls = calloc(1, nulls_size);
while ((r = archive_read_data_block(a, &buff, &size, &offset)) == while ((r = archive_read_data_block(a, &buff, &size, &target_offset)) ==
ARCHIVE_OK) { ARCHIVE_OK) {
const char *p = buff; const char *p = buff;
if (offset > output_offset) { if (target_offset > actual_offset) {
output_offset = lseek(fd, r = pad_to(a, fd, can_lseek, nulls_size, nulls,
offset - output_offset, SEEK_CUR); target_offset, actual_offset);
if (output_offset != offset) { if (r != ARCHIVE_OK)
archive_set_error(a, errno, "Seek error"); break;
return (ARCHIVE_FATAL); actual_offset = target_offset;
}
} }
while (size > 0) { while (size > 0) {
bytes_to_write = size; bytes_to_write = size;
@ -78,15 +115,24 @@ archive_read_data_into_fd(struct archive *a, int fd)
bytes_written = write(fd, p, bytes_to_write); bytes_written = write(fd, p, bytes_to_write);
if (bytes_written < 0) { if (bytes_written < 0) {
archive_set_error(a, errno, "Write error"); archive_set_error(a, errno, "Write error");
return (ARCHIVE_FATAL); r = ARCHIVE_FATAL;
goto cleanup;
} }
output_offset += bytes_written; actual_offset += bytes_written;
total_written += bytes_written;
p += bytes_written; p += bytes_written;
size -= bytes_written; size -= bytes_written;
} }
} }
if (r == ARCHIVE_EOF && target_offset > actual_offset) {
r2 = pad_to(a, fd, can_lseek, nulls_size, nulls,
target_offset, actual_offset);
if (r2 != ARCHIVE_OK)
r = r2;
}
cleanup:
free(nulls);
if (r != ARCHIVE_EOF) if (r != ARCHIVE_EOF)
return (r); return (r);
return (ARCHIVE_OK); return (ARCHIVE_OK);

View File

@ -39,6 +39,7 @@
.Nm archive_read_disk_set_gname_lookup , .Nm archive_read_disk_set_gname_lookup ,
.Nm archive_read_disk_set_standard_lookup , .Nm archive_read_disk_set_standard_lookup ,
.Nm archive_read_close , .Nm archive_read_close ,
.Nm archive_read_finish ,
.Nm archive_read_free .Nm archive_read_free
.Nd functions for reading objects from disk .Nd functions for reading objects from disk
.Sh SYNOPSIS .Sh SYNOPSIS
@ -81,6 +82,8 @@
.Ft int .Ft int
.Fn archive_read_close "struct archive *" .Fn archive_read_close "struct archive *"
.Ft int .Ft int
.Fn archive_read_finish "struct archive *"
.Ft int
.Fn archive_read_free "struct archive *" .Fn archive_read_free "struct archive *"
.Sh DESCRIPTION .Sh DESCRIPTION
These functions provide an API for reading information about These functions provide an API for reading information about
@ -177,7 +180,12 @@ This affects the file ownership fields and ACL values in the
.Tn struct archive_entry .Tn struct archive_entry
object. object.
.It Fn archive_read_close .It Fn archive_read_close
This currently does nothing. Does nothing for
.Tn archive_read_disk
handles.
.It Fn archive_read_finish
This is a deprecated synonym for
.Fn archive_read_free .
.It Fn archive_read_free .It Fn archive_read_free
Invokes Invokes
.Fn archive_read_close .Fn archive_read_close
@ -207,7 +215,7 @@ file_to_archive(struct archive *a, const char *name)
fd = open(name, O_RDONLY); fd = open(name, O_RDONLY);
if (fd < 0) if (fd < 0)
return; return;
archive_entry_copy_sourcepath(entry, name); archive_entry_copy_pathname(entry, name);
archive_read_disk_entry_from_file(ard, entry, fd, NULL); archive_read_disk_entry_from_file(ard, entry, fd, NULL);
archive_write_header(a, entry); archive_write_header(a, entry);
while ((bytes_read = read(fd, buff, sizeof(buff))) > 0) while ((bytes_read = read(fd, buff, sizeof(buff))) > 0)
@ -229,15 +237,6 @@ for operations that might succeed if retried,
for unusual conditions that do not prevent further operations, and for unusual conditions that do not prevent further operations, and
.Cm ARCHIVE_FATAL .Cm ARCHIVE_FATAL
for serious errors that make remaining operations impossible. for serious errors that make remaining operations impossible.
The
.Xr archive_errno 3
and
.Xr archive_error_string 3
functions can be used to retrieve an appropriate error code and a
textual error message.
(See
.Xr archive_util 3
for details.)
.Pp .Pp
.Fn archive_read_disk_new .Fn archive_read_disk_new
returns a pointer to a newly-allocated returns a pointer to a newly-allocated
@ -253,9 +252,17 @@ pointers to the textual name or NULL if the lookup failed for any reason.
The returned pointer points to internal storage that The returned pointer points to internal storage that
may be reused on the next call to either of these functions; may be reused on the next call to either of these functions;
callers should copy the string if they need to continue accessing it. callers should copy the string if they need to continue accessing it.
.Pp .\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO .Sh SEE ALSO
.Xr archive_read 3 , .Xr archive_read 3 ,
.Xr archive_util 3 ,
.Xr archive_write 3 , .Xr archive_write 3 ,
.Xr archive_write_disk 3 , .Xr archive_write_disk 3 ,
.Xr tar 1 , .Xr tar 1 ,

View File

@ -1,198 +0,0 @@
/*-
* Copyright (c) 2003-2009 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
* in this position and unchanged.
* 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 "archive_platform.h"
__FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_string.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_disk_private.h"
static int _archive_read_free(struct archive *);
static int _archive_read_close(struct archive *);
static const char *trivial_lookup_gname(void *, gid_t gid);
static const char *trivial_lookup_uname(void *, uid_t uid);
static struct archive_vtable *
archive_read_disk_vtable(void)
{
static struct archive_vtable av;
static int inited = 0;
if (!inited) {
av.archive_free = _archive_read_free;
av.archive_close = _archive_read_close;
}
return (&av);
}
const char *
archive_read_disk_gname(struct archive *_a, gid_t gid)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (a->lookup_gname != NULL)
return ((*a->lookup_gname)(a->lookup_gname_data, gid));
return (NULL);
}
const char *
archive_read_disk_uname(struct archive *_a, uid_t uid)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (a->lookup_uname != NULL)
return ((*a->lookup_uname)(a->lookup_uname_data, uid));
return (NULL);
}
int
archive_read_disk_set_gname_lookup(struct archive *_a,
void *private_data,
const char * (*lookup_gname)(void *private, gid_t gid),
void (*cleanup_gname)(void *private))
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
__archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_set_gname_lookup");
if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
(a->cleanup_gname)(a->lookup_gname_data);
a->lookup_gname = lookup_gname;
a->cleanup_gname = cleanup_gname;
a->lookup_gname_data = private_data;
return (ARCHIVE_OK);
}
int
archive_read_disk_set_uname_lookup(struct archive *_a,
void *private_data,
const char * (*lookup_uname)(void *private, uid_t uid),
void (*cleanup_uname)(void *private))
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
__archive_check_magic(&a->archive, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_set_uname_lookup");
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
(a->cleanup_uname)(a->lookup_uname_data);
a->lookup_uname = lookup_uname;
a->cleanup_uname = cleanup_uname;
a->lookup_uname_data = private_data;
return (ARCHIVE_OK);
}
/*
* Create a new archive_read_disk object and initialize it with global state.
*/
struct archive *
archive_read_disk_new(void)
{
struct archive_read_disk *a;
a = (struct archive_read_disk *)malloc(sizeof(*a));
if (a == NULL)
return (NULL);
memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
/* We're ready to write a header immediately. */
a->archive.state = ARCHIVE_STATE_HEADER;
a->archive.vtable = archive_read_disk_vtable();
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
return (&a->archive);
}
static int
_archive_read_free(struct archive *_a)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (a->cleanup_gname != NULL && a->lookup_gname_data != NULL)
(a->cleanup_gname)(a->lookup_gname_data);
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
(a->cleanup_uname)(a->lookup_uname_data);
archive_string_free(&a->archive.error_string);
free(a);
return (ARCHIVE_OK);
}
static int
_archive_read_close(struct archive *_a)
{
(void)_a; /* UNUSED */
return (ARCHIVE_OK);
}
int
archive_read_disk_set_symlink_logical(struct archive *_a)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
a->symlink_mode = 'L';
a->follow_symlinks = 1;
return (ARCHIVE_OK);
}
int
archive_read_disk_set_symlink_physical(struct archive *_a)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
a->symlink_mode = 'P';
a->follow_symlinks = 0;
return (ARCHIVE_OK);
}
int
archive_read_disk_set_symlink_hybrid(struct archive *_a)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
a->symlink_mode = 'H';
a->follow_symlinks = 1; /* Follow symlinks initially. */
return (ARCHIVE_OK);
}
/*
* Trivial implementations of gname/uname lookup functions.
* These are normally overridden by the client, but these stub
* versions ensure that we always have something that works.
*/
static const char *
trivial_lookup_gname(void *private_data, gid_t gid)
{
(void)private_data; /* UNUSED */
(void)gid; /* UNUSED */
return (NULL);
}
static const char *
trivial_lookup_uname(void *private_data, uid_t uid)
{
(void)private_data; /* UNUSED */
(void)uid; /* UNUSED */
return (NULL);
}

View File

@ -1,5 +1,6 @@
/*- /*-
* Copyright (c) 2003-2009 Tim Kientzle * Copyright (c) 2003-2009 Tim Kientzle
* Copyright (c) 2010 Michihiro NAKAJIMA
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -26,6 +27,9 @@
#include "archive_platform.h" #include "archive_platform.h"
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
/* This is the tree-walking code for POSIX systems. */
#if !defined(_WIN32) || defined(__CYGWIN__)
#ifdef HAVE_SYS_TYPES_H #ifdef HAVE_SYS_TYPES_H
/* Mac OSX requires sys/types.h before sys/acl.h. */ /* Mac OSX requires sys/types.h before sys/acl.h. */
#include <sys/types.h> #include <sys/types.h>
@ -36,6 +40,9 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_EXTATTR_H #ifdef HAVE_SYS_EXTATTR_H
#include <sys/extattr.h> #include <sys/extattr.h>
#endif #endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_PARAM_H #ifdef HAVE_SYS_PARAM_H
#include <sys/param.h> #include <sys/param.h>
#endif #endif
@ -45,20 +52,48 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_XATTR_H #ifdef HAVE_SYS_XATTR_H
#include <sys/xattr.h> #include <sys/xattr.h>
#endif #endif
#ifdef HAVE_SYS_EA_H
#include <sys/ea.h>
#endif
#ifdef HAVE_ACL_LIBACL_H #ifdef HAVE_ACL_LIBACL_H
#include <acl/libacl.h> #include <acl/libacl.h>
#endif #endif
#ifdef HAVE_ATTR_XATTR_H #ifdef HAVE_ATTR_XATTR_H
#include <attr/xattr.h> #include <attr/xattr.h>
#endif #endif
#ifdef HAVE_COPYFILE_H
#include <copyfile.h>
#endif
#ifdef HAVE_ERRNO_H #ifdef HAVE_ERRNO_H
#include <errno.h> #include <errno.h>
#endif #endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_LIMITS_H #ifdef HAVE_LIMITS_H
#include <limits.h> #include <limits.h>
#endif #endif
#ifdef HAVE_WINDOWS_H #ifdef HAVE_LINUX_FIEMAP_H
#include <windows.h> #include <linux/fiemap.h>
#endif
#ifdef HAVE_LINUX_FS_H
#include <linux/fs.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
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif #endif
#include "archive.h" #include "archive.h"
@ -78,13 +113,18 @@ __FBSDID("$FreeBSD$");
static int setup_acls_posix1e(struct archive_read_disk *, static int setup_acls_posix1e(struct archive_read_disk *,
struct archive_entry *, int fd); struct archive_entry *, int fd);
static int setup_mac_metadata(struct archive_read_disk *,
struct archive_entry *, int fd);
static int setup_xattrs(struct archive_read_disk *, static int setup_xattrs(struct archive_read_disk *,
struct archive_entry *, int fd); struct archive_entry *, int fd);
static int setup_sparse(struct archive_read_disk *,
struct archive_entry *, int fd);
int int
archive_read_disk_entry_from_file(struct archive *_a, archive_read_disk_entry_from_file(struct archive *_a,
struct archive_entry *entry, struct archive_entry *entry,
int fd, const struct stat *st) int fd,
const struct stat *st)
{ {
struct archive_read_disk *a = (struct archive_read_disk *)_a; struct archive_read_disk *a = (struct archive_read_disk *)_a;
const char *path, *name; const char *path, *name;
@ -97,54 +137,35 @@ archive_read_disk_entry_from_file(struct archive *_a,
if (path == NULL) if (path == NULL)
path = archive_entry_pathname(entry); path = archive_entry_pathname(entry);
#ifdef EXT2_IOC_GETFLAGS if (a->tree == NULL) {
/* Linux requires an extra ioctl to pull the flags. Although if (st == NULL) {
* this is an extra step, it has a nice side-effect: We get an
* open file descriptor which we can use in the subsequent lookups. */
if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
if (fd < 0)
fd = open(pathname, O_RDONLY | O_NONBLOCK | O_BINARY);
if (fd >= 0) {
unsigned long stflags;
int r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
if (r == 0 && stflags != 0)
archive_entry_set_fflags(entry, stflags, 0);
}
}
#endif
if (st == NULL) {
/* TODO: On Windows, use GetFileInfoByHandle() here.
* Using Windows stat() call is badly broken, but
* even the stat() wrapper has problems because
* 'struct stat' is broken on Windows.
*/
#if HAVE_FSTAT #if HAVE_FSTAT
if (fd >= 0) { if (fd >= 0) {
if (fstat(fd, &s) != 0) { if (fstat(fd, &s) != 0) {
archive_set_error(&a->archive, errno, archive_set_error(&a->archive, errno,
"Can't fstat"); "Can't fstat");
return (ARCHIVE_FAILED); return (ARCHIVE_FAILED);
} }
} else } else
#endif #endif
#if HAVE_LSTAT #if HAVE_LSTAT
if (!a->follow_symlinks) { if (!a->follow_symlinks) {
if (lstat(path, &s) != 0) { if (lstat(path, &s) != 0) {
archive_set_error(&a->archive, errno,
"Can't lstat %s", path);
return (ARCHIVE_FAILED);
}
} else
#endif
if (stat(path, &s) != 0) {
archive_set_error(&a->archive, errno, archive_set_error(&a->archive, errno,
"Can't lstat %s", path); "Can't stat %s", path);
return (ARCHIVE_FAILED); return (ARCHIVE_FAILED);
} }
} else st = &s;
#endif
if (stat(path, &s) != 0) {
archive_set_error(&a->archive, errno,
"Can't lstat %s", path);
return (ARCHIVE_FAILED);
} }
st = &s; archive_entry_copy_stat(entry, st);
} }
archive_entry_copy_stat(entry, st);
/* Lookup uname/gname */ /* Lookup uname/gname */
name = archive_read_disk_uname(_a, archive_entry_uid(entry)); name = archive_read_disk_uname(_a, archive_entry_uid(entry));
@ -161,30 +182,185 @@ archive_read_disk_entry_from_file(struct archive *_a,
archive_entry_set_fflags(entry, st->st_flags, 0); archive_entry_set_fflags(entry, st->st_flags, 0);
#endif #endif
#ifdef HAVE_READLINK #if defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
/* Linux requires an extra ioctl to pull the flags. Although
* this is an extra step, it has a nice side-effect: We get an
* open file descriptor which we can use in the subsequent lookups. */
if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
if (fd < 0)
fd = open(path, O_RDONLY | O_NONBLOCK);
if (fd >= 0) {
unsigned long stflags;
r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
if (r == 0 && stflags != 0)
archive_entry_set_fflags(entry, stflags, 0);
}
}
#endif
#if defined(HAVE_READLINK) || defined(HAVE_READLINKAT)
if (S_ISLNK(st->st_mode)) { if (S_ISLNK(st->st_mode)) {
char linkbuffer[PATH_MAX + 1]; size_t linkbuffer_len = st->st_size + 1;
int lnklen = readlink(path, linkbuffer, PATH_MAX); char *linkbuffer;
int lnklen;
linkbuffer = malloc(linkbuffer_len);
if (linkbuffer == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Couldn't read link data");
return (ARCHIVE_FAILED);
}
#ifdef HAVE_READLINKAT
if (a->entry_wd_fd >= 0)
lnklen = readlinkat(a->entry_wd_fd, path,
linkbuffer, linkbuffer_len);
else
#endif /* HAVE_READLINKAT */
lnklen = readlink(path, linkbuffer, linkbuffer_len);
if (lnklen < 0) { if (lnklen < 0) {
archive_set_error(&a->archive, errno, archive_set_error(&a->archive, errno,
"Couldn't read link data"); "Couldn't read link data");
free(linkbuffer);
return (ARCHIVE_FAILED); return (ARCHIVE_FAILED);
} }
linkbuffer[lnklen] = 0; linkbuffer[lnklen] = 0;
archive_entry_set_symlink(entry, linkbuffer); archive_entry_set_symlink(entry, linkbuffer);
free(linkbuffer);
} }
#endif #endif /* HAVE_READLINK || HAVE_READLINKAT */
r = setup_acls_posix1e(a, entry, fd); r = setup_acls_posix1e(a, entry, fd);
r1 = setup_xattrs(a, entry, fd); r1 = setup_xattrs(a, entry, fd);
if (r1 < r) if (r1 < r)
r = r1; r = r1;
r1 = setup_mac_metadata(a, entry, fd);
if (r1 < r)
r = r1;
r1 = setup_sparse(a, entry, fd);
if (r1 < r)
r = r1;
/* If we opened the file earlier in this function, close it. */ /* If we opened the file earlier in this function, close it. */
if (initial_fd != fd) if (initial_fd != fd)
close(fd); close(fd);
return (r); return (r);
} }
#if defined(__APPLE__) && defined(HAVE_COPYFILE_H)
/*
* The Mac OS "copyfile()" API copies the extended metadata for a
* file into a separate file in AppleDouble format (see RFC 1740).
*
* Mac OS tar and cpio implementations store this extended
* metadata as a separate entry just before the regular entry
* with a "._" prefix added to the filename.
*
* Note that this is currently done unconditionally; the tar program has
* an option to discard this information before the archive is written.
*
* TODO: If there's a failure, report it and return ARCHIVE_WARN.
*/
static int
setup_mac_metadata(struct archive_read_disk *a,
struct archive_entry *entry, int fd)
{
int tempfd = -1;
int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
struct stat copyfile_stat;
int ret = ARCHIVE_OK;
void *buff;
int have_attrs;
const char *name, *tempdir, *tempfile = NULL;
name = archive_entry_sourcepath(entry);
if (name == NULL)
name = archive_entry_pathname(entry);
if (name == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Can't open file to read extended attributes: No name");
return (ARCHIVE_WARN);
}
/* Short-circuit if there's nothing to do. */
have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
if (have_attrs == -1) {
archive_set_error(&a->archive, errno,
"Could not check extended attributes");
return (ARCHIVE_WARN);
}
if (have_attrs == 0)
return (ARCHIVE_OK);
tempdir = NULL;
if (issetugid() == 0)
tempdir = getenv("TMPDIR");
if (tempdir == NULL)
tempdir = _PATH_TMP;
tempfile = tempnam(tempdir, "tar.md.");
/* XXX I wish copyfile() could pack directly to a memory
* buffer; that would avoid the temp file here. For that
* matter, it would be nice if fcopyfile() actually worked,
* that would reduce the many open/close races here. */
if (copyfile(name, tempfile, 0, copyfile_flags | COPYFILE_PACK)) {
archive_set_error(&a->archive, errno,
"Could not pack extended attributes");
ret = ARCHIVE_WARN;
goto cleanup;
}
tempfd = open(tempfile, O_RDONLY);
if (tempfd < 0) {
archive_set_error(&a->archive, errno,
"Could not open extended attribute file");
ret = ARCHIVE_WARN;
goto cleanup;
}
if (fstat(tempfd, &copyfile_stat)) {
archive_set_error(&a->archive, errno,
"Could not check size of extended attributes");
ret = ARCHIVE_WARN;
goto cleanup;
}
buff = malloc(copyfile_stat.st_size);
if (buff == NULL) {
archive_set_error(&a->archive, errno,
"Could not allocate memory for extended attributes");
ret = ARCHIVE_WARN;
goto cleanup;
}
if (copyfile_stat.st_size != read(tempfd, buff, copyfile_stat.st_size)) {
archive_set_error(&a->archive, errno,
"Could not read extended attributes into memory");
ret = ARCHIVE_WARN;
goto cleanup;
}
archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
cleanup:
if (tempfd >= 0)
close(tempfd);
if (tempfile != NULL)
unlink(tempfile);
return (ret);
}
#else
/*
* Stub implementation for non-Mac systems.
*/
static int
setup_mac_metadata(struct archive_read_disk *a,
struct archive_entry *entry, int fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
(void)fd; /* UNUSED */
return (ARCHIVE_OK);
}
#endif
#ifdef HAVE_POSIX_ACL #ifdef HAVE_POSIX_ACL
static void setup_acl_posix1e(struct archive_read_disk *a, static void setup_acl_posix1e(struct archive_read_disk *a,
struct archive_entry *entry, acl_t acl, int archive_entry_acl_type); struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
@ -307,10 +483,12 @@ setup_acls_posix1e(struct archive_read_disk *a,
} }
#endif #endif
#if HAVE_LISTXATTR && HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
(HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
/* /*
* Linux extended attribute support. * Linux and AIX extended attribute support.
* *
* TODO: By using a stack-allocated buffer for the first * TODO: By using a stack-allocated buffer for the first
* call to getxattr(), we might be able to avoid the second * call to getxattr(), we might be able to avoid the second
@ -329,16 +507,25 @@ setup_xattr(struct archive_read_disk *a,
void *value = NULL; void *value = NULL;
const char *accpath; const char *accpath;
(void)fd; /* UNUSED */
accpath = archive_entry_sourcepath(entry); accpath = archive_entry_sourcepath(entry);
if (accpath == NULL) if (accpath == NULL)
accpath = archive_entry_pathname(entry); accpath = archive_entry_pathname(entry);
if (!a->follow_symlinks) #if HAVE_FGETXATTR
if (fd >= 0)
size = fgetxattr(fd, name, NULL, 0);
else if (!a->follow_symlinks)
size = lgetxattr(accpath, name, NULL, 0); size = lgetxattr(accpath, name, NULL, 0);
else else
size = getxattr(accpath, name, NULL, 0); size = getxattr(accpath, name, NULL, 0);
#elif HAVE_FGETEA
if (fd >= 0)
size = fgetea(fd, name, NULL, 0);
else if (!a->follow_symlinks)
size = lgetea(accpath, name, NULL, 0);
else
size = getea(accpath, name, NULL, 0);
#endif
if (size == -1) { if (size == -1) {
archive_set_error(&a->archive, errno, archive_set_error(&a->archive, errno,
@ -351,10 +538,21 @@ setup_xattr(struct archive_read_disk *a,
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
if (!a->follow_symlinks) #if HAVE_FGETXATTR
if (fd >= 0)
size = fgetxattr(fd, name, value, size);
else if (!a->follow_symlinks)
size = lgetxattr(accpath, name, value, size); size = lgetxattr(accpath, name, value, size);
else else
size = getxattr(accpath, name, value, size); size = getxattr(accpath, name, value, size);
#elif HAVE_FGETEA
if (fd >= 0)
size = fgetea(fd, name, value, size);
else if (!a->follow_symlinks)
size = lgetea(accpath, name, value, size);
else
size = getea(accpath, name, value, size);
#endif
if (size == -1) { if (size == -1) {
archive_set_error(&a->archive, errno, archive_set_error(&a->archive, errno,
@ -376,18 +574,28 @@ setup_xattrs(struct archive_read_disk *a,
const char *path; const char *path;
ssize_t list_size; ssize_t list_size;
path = archive_entry_sourcepath(entry); path = archive_entry_sourcepath(entry);
if (path == NULL) if (path == NULL)
path = archive_entry_pathname(entry); path = archive_entry_pathname(entry);
if (!a->follow_symlinks) #if HAVE_FLISTXATTR
if (fd >= 0)
list_size = flistxattr(fd, NULL, 0);
else if (!a->follow_symlinks)
list_size = llistxattr(path, NULL, 0); list_size = llistxattr(path, NULL, 0);
else else
list_size = listxattr(path, NULL, 0); list_size = listxattr(path, NULL, 0);
#elif HAVE_FLISTEA
if (fd >= 0)
list_size = flistea(fd, NULL, 0);
else if (!a->follow_symlinks)
list_size = llistea(path, NULL, 0);
else
list_size = listea(path, NULL, 0);
#endif
if (list_size == -1) { if (list_size == -1) {
if (errno == ENOTSUP) if (errno == ENOTSUP || errno == ENOSYS)
return (ARCHIVE_OK); return (ARCHIVE_OK);
archive_set_error(&a->archive, errno, archive_set_error(&a->archive, errno,
"Couldn't list extended attributes"); "Couldn't list extended attributes");
@ -402,10 +610,21 @@ setup_xattrs(struct archive_read_disk *a,
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
if (!a->follow_symlinks) #if HAVE_FLISTXATTR
if (fd >= 0)
list_size = flistxattr(fd, list, list_size);
else if (!a->follow_symlinks)
list_size = llistxattr(path, list, list_size); list_size = llistxattr(path, list, list_size);
else else
list_size = listxattr(path, list, list_size); list_size = listxattr(path, list, list_size);
#elif HAVE_FLISTEA
if (fd >= 0)
list_size = flistea(fd, list, list_size);
else if (!a->follow_symlinks)
list_size = llistea(path, list, list_size);
else
list_size = listea(path, list, list_size);
#endif
if (list_size == -1) { if (list_size == -1) {
archive_set_error(&a->archive, errno, archive_set_error(&a->archive, errno,
@ -449,13 +668,13 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
void *value = NULL; void *value = NULL;
const char *accpath; const char *accpath;
(void)fd; /* UNUSED */
accpath = archive_entry_sourcepath(entry); accpath = archive_entry_sourcepath(entry);
if (accpath == NULL) if (accpath == NULL)
accpath = archive_entry_pathname(entry); accpath = archive_entry_pathname(entry);
if (!a->follow_symlinks) if (fd >= 0)
size = extattr_get_fd(fd, namespace, name, NULL, 0);
else if (!a->follow_symlinks)
size = extattr_get_link(accpath, namespace, name, NULL, 0); size = extattr_get_link(accpath, namespace, name, NULL, 0);
else else
size = extattr_get_file(accpath, namespace, name, NULL, 0); size = extattr_get_file(accpath, namespace, name, NULL, 0);
@ -471,7 +690,9 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
if (!a->follow_symlinks) if (fd >= 0)
size = extattr_get_fd(fd, namespace, name, value, size);
else if (!a->follow_symlinks)
size = extattr_get_link(accpath, namespace, name, value, size); size = extattr_get_link(accpath, namespace, name, value, size);
else else
size = extattr_get_file(accpath, namespace, name, value, size); size = extattr_get_file(accpath, namespace, name, value, size);
@ -502,7 +723,9 @@ setup_xattrs(struct archive_read_disk *a,
if (path == NULL) if (path == NULL)
path = archive_entry_pathname(entry); path = archive_entry_pathname(entry);
if (!a->follow_symlinks) if (fd >= 0)
list_size = extattr_list_fd(fd, namespace, NULL, 0);
else if (!a->follow_symlinks)
list_size = extattr_list_link(path, namespace, NULL, 0); list_size = extattr_list_link(path, namespace, NULL, 0);
else else
list_size = extattr_list_file(path, namespace, NULL, 0); list_size = extattr_list_file(path, namespace, NULL, 0);
@ -523,7 +746,9 @@ setup_xattrs(struct archive_read_disk *a,
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
if (!a->follow_symlinks) if (fd >= 0)
list_size = extattr_list_fd(fd, namespace, list, list_size);
else if (!a->follow_symlinks)
list_size = extattr_list_link(path, namespace, list, list_size); list_size = extattr_list_link(path, namespace, list, list_size);
else else
list_size = extattr_list_file(path, namespace, list, list_size); list_size = extattr_list_file(path, namespace, list, list_size);
@ -568,3 +793,213 @@ setup_xattrs(struct archive_read_disk *a,
} }
#endif #endif
#if defined(HAVE_LINUX_FIEMAP_H)
/*
* Linux sparse interface.
*
* The FIEMAP ioctl returns an "extent" for each physical allocation
* on disk. We need to process those to generate a more compact list
* of logical file blocks. We also need to be very careful to use
* FIEMAP_FLAG_SYNC here, since there are reports that Linux sometimes
* does not report allocations for newly-written data that hasn't
* been synced to disk.
*
* It's important to return a minimal sparse file list because we want
* to not trigger sparse file extensions if we don't have to, since
* not all readers support them.
*/
static int
setup_sparse(struct archive_read_disk *a,
struct archive_entry *entry, int fd)
{
char buff[4096];
struct fiemap *fm;
struct fiemap_extent *fe;
int64_t size;
int count, do_fiemap;
int initial_fd = fd;
int exit_sts = ARCHIVE_OK;
if (archive_entry_filetype(entry) != AE_IFREG
|| archive_entry_size(entry) <= 0
|| archive_entry_hardlink(entry) != NULL)
return (ARCHIVE_OK);
if (fd < 0) {
const char *path;
path = archive_entry_sourcepath(entry);
if (path == NULL)
path = archive_entry_pathname(entry);
fd = open(path, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
archive_set_error(&a->archive, errno,
"Can't open `%s'", path);
return (ARCHIVE_FAILED);
}
}
count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
fm = (struct fiemap *)buff;
fm->fm_start = 0;
fm->fm_length = ~0ULL;;
fm->fm_flags = FIEMAP_FLAG_SYNC;
fm->fm_extent_count = count;
do_fiemap = 1;
size = archive_entry_size(entry);
for (;;) {
int i, r;
r = ioctl(fd, FS_IOC_FIEMAP, fm);
if (r < 0) {
/* When errno is ENOTTY, it is better we should
* return ARCHIVE_OK because an earlier version
*(<2.6.28) cannot perfom FS_IOC_FIEMAP.
* We should also check if errno is EOPNOTSUPP,
* it means "Operation not supported". */
if (errno != ENOTTY && errno != EOPNOTSUPP) {
archive_set_error(&a->archive, errno,
"FIEMAP failed");
exit_sts = ARCHIVE_FAILED;
}
goto exit_setup_sparse;
}
if (fm->fm_mapped_extents == 0)
break;
fe = fm->fm_extents;
for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
/* The fe_length of the last block does not
* adjust itself to its size files. */
int64_t length = fe->fe_length;
if (fe->fe_logical + length > (uint64_t)size)
length -= fe->fe_logical + length - size;
if (fe->fe_logical == 0 && length == size) {
/* This is not sparse. */
do_fiemap = 0;
break;
}
if (length > 0)
archive_entry_sparse_add_entry(entry,
fe->fe_logical, length);
}
if (fe->fe_flags & FIEMAP_EXTENT_LAST)
do_fiemap = 0;
}
if (do_fiemap) {
fe = fm->fm_extents + fm->fm_mapped_extents -1;
fm->fm_start = fe->fe_logical + fe->fe_length;
} else
break;
}
exit_setup_sparse:
if (initial_fd != fd)
close(fd);
return (exit_sts);
}
#elif defined(SEEK_HOLE) && defined(SEEK_DATA) && defined(_PC_MIN_HOLE_SIZE)
/*
* FreeBSD and Solaris sparse interface.
*/
static int
setup_sparse(struct archive_read_disk *a,
struct archive_entry *entry, int fd)
{
int64_t size;
int initial_fd = fd;
off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */
off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */
int exit_sts = ARCHIVE_OK;
if (archive_entry_filetype(entry) != AE_IFREG
|| archive_entry_size(entry) <= 0
|| archive_entry_hardlink(entry) != NULL)
return (ARCHIVE_OK);
/* Does filesystem support the reporting of hole ? */
if (fd >= 0) {
if (fpathconf(fd, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
initial_off = lseek(fd, 0, SEEK_CUR);
if (initial_off != 0)
lseek(fd, 0, SEEK_SET);
} else {
const char *path;
path = archive_entry_sourcepath(entry);
if (path == NULL)
path = archive_entry_pathname(entry);
if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
fd = open(path, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
archive_set_error(&a->archive, errno,
"Can't open `%s'", path);
return (ARCHIVE_FAILED);
}
initial_off = 0;
}
off_s = 0;
size = archive_entry_size(entry);
while (off_s < size) {
off_s = lseek(fd, off_s, SEEK_DATA);
if (off_s == (off_t)-1) {
if (errno == ENXIO)
break;/* no more hole */
archive_set_error(&a->archive, errno,
"lseek(SEEK_HOLE) failed");
exit_sts = ARCHIVE_FAILED;
goto exit_setup_sparse;
}
off_e = lseek(fd, off_s, SEEK_HOLE);
if (off_s == (off_t)-1) {
if (errno == ENXIO) {
off_e = lseek(fd, 0, SEEK_END);
if (off_e != (off_t)-1)
break;/* no more data */
}
archive_set_error(&a->archive, errno,
"lseek(SEEK_DATA) failed");
exit_sts = ARCHIVE_FAILED;
goto exit_setup_sparse;
}
if (off_s == 0 && off_e == size)
break;/* This is not spase. */
archive_entry_sparse_add_entry(entry, off_s,
off_e - off_s);
off_s = off_e;
}
exit_setup_sparse:
if (initial_fd != fd)
close(fd);
else
lseek(fd, initial_off, SEEK_SET);
return (exit_sts);
}
#else
/*
* Generic (stub) sparse support.
*/
static int
setup_sparse(struct archive_read_disk *a,
struct archive_entry *entry, int fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
(void)fd; /* UNUSED */
return (ARCHIVE_OK);
}
#endif
#endif /* !defined(_WIN32) || defined(__CYGWIN__) */

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,8 @@
#ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED #ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED #define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
struct tree;
struct archive_read_disk { struct archive_read_disk {
struct archive archive; struct archive archive;
@ -51,10 +53,17 @@ struct archive_read_disk {
*/ */
char follow_symlinks; /* Either 'L' or 'P'. */ char follow_symlinks; /* Either 'L' or 'P'. */
const char * (*lookup_gname)(void *private, gid_t gid); /* Directory traversals. */
struct tree *tree;
/* Set 1 if users request to restore atime . */
int restore_time;
int entry_wd_fd;
const char * (*lookup_gname)(void *private, int64_t gid);
void (*cleanup_gname)(void *private); void (*cleanup_gname)(void *private);
void *lookup_gname_data; void *lookup_gname_data;
const char * (*lookup_uname)(void *private, gid_t gid); const char * (*lookup_uname)(void *private, int64_t uid);
void (*cleanup_uname)(void *private); void (*cleanup_uname)(void *private);
void *lookup_uname_data; void *lookup_uname_data;
}; };

View File

@ -72,8 +72,8 @@ struct name_cache {
} cache[name_cache_size]; } cache[name_cache_size];
}; };
static const char * lookup_gname(void *, gid_t); static const char * lookup_gname(void *, int64_t);
static const char * lookup_uname(void *, uid_t); static const char * lookup_uname(void *, int64_t);
static void cleanup(void *); static void cleanup(void *);
static const char * lookup_gname_helper(struct name_cache *, id_t gid); static const char * lookup_gname_helper(struct name_cache *, id_t gid);
static const char * lookup_uname_helper(struct name_cache *, id_t uid); static const char * lookup_uname_helper(struct name_cache *, id_t uid);
@ -175,7 +175,7 @@ lookup_name(struct name_cache *cache,
} }
static const char * static const char *
lookup_uname(void *data, uid_t uid) lookup_uname(void *data, int64_t uid)
{ {
struct name_cache *uname_cache = (struct name_cache *)data; struct name_cache *uname_cache = (struct name_cache *)data;
return (lookup_name(uname_cache, return (lookup_name(uname_cache,
@ -187,6 +187,8 @@ static const char *
lookup_uname_helper(struct name_cache *cache, id_t id) lookup_uname_helper(struct name_cache *cache, id_t id)
{ {
struct passwd pwent, *result; struct passwd pwent, *result;
char * nbuff;
size_t nbuff_size;
int r; int r;
if (cache->buff_size == 0) { if (cache->buff_size == 0) {
@ -208,10 +210,12 @@ lookup_uname_helper(struct name_cache *cache, id_t id)
* we just double it and try again. Because the buffer * we just double it and try again. Because the buffer
* is kept around in the cache object, we shouldn't * is kept around in the cache object, we shouldn't
* have to do this very often. */ * have to do this very often. */
cache->buff_size *= 2; nbuff_size = cache->buff_size * 2;
cache->buff = realloc(cache->buff, cache->buff_size); nbuff = realloc(cache->buff, nbuff_size);
if (cache->buff == NULL) if (nbuff == NULL)
break; break;
cache->buff = nbuff;
cache->buff_size = nbuff_size;
} }
if (r != 0) { if (r != 0) {
archive_set_error(cache->archive, errno, archive_set_error(cache->archive, errno,
@ -239,7 +243,7 @@ lookup_uname_helper(struct name_cache *cache, id_t id)
#endif #endif
static const char * static const char *
lookup_gname(void *data, gid_t gid) lookup_gname(void *data, int64_t gid)
{ {
struct name_cache *gname_cache = (struct name_cache *)data; struct name_cache *gname_cache = (struct name_cache *)data;
return (lookup_name(gname_cache, return (lookup_name(gname_cache,
@ -251,6 +255,8 @@ static const char *
lookup_gname_helper(struct name_cache *cache, id_t id) lookup_gname_helper(struct name_cache *cache, id_t id)
{ {
struct group grent, *result; struct group grent, *result;
char * nbuff;
size_t nbuff_size;
int r; int r;
if (cache->buff_size == 0) { if (cache->buff_size == 0) {
@ -270,10 +276,12 @@ lookup_gname_helper(struct name_cache *cache, id_t id)
/* ERANGE means our buffer was too small, but POSIX /* ERANGE means our buffer was too small, but POSIX
* doesn't tell us how big the buffer should be, so * doesn't tell us how big the buffer should be, so
* we just double it and try again. */ * we just double it and try again. */
cache->buff_size *= 2; nbuff_size = cache->buff_size * 2;
cache->buff = realloc(cache->buff, cache->buff_size); nbuff = realloc(cache->buff, nbuff_size);
if (cache->buff == NULL) if (nbuff == NULL)
break; break;
cache->buff = nbuff;
cache->buff_size = nbuff_size;
} }
if (r != 0) { if (r != 0) {
archive_set_error(cache->archive, errno, archive_set_error(cache->archive, errno,

View File

@ -0,0 +1,135 @@
.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
.\"
.Dd March 22, 2011
.Dt ARCHIVE_READ_EXTRACT 3
.Os
.Sh NAME
.Nm archive_read_extract ,
.Nm archive_read_extract2 ,
.Nm archive_read_extract_set_progress_callback
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fo archive_read_extract
.Fa "struct archive *"
.Fa "struct archive_entry *"
.Fa "int flags"
.Fc
.Ft int
.Fo archive_read_extract2
.Fa "struct archive *src"
.Fa "struct archive_entry *"
.Fa "struct archive *dest"
.Fc
.Ft void
.Fo archive_read_extract_set_progress_callback
.Fa "struct archive *"
.Fa "void (*func)(void *)"
.Fa "void *user_data"
.Fc
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_extract , Fn archive_read_extract_set_skip_file
A convenience function that wraps the corresponding
.Xr archive_write_disk 3
interfaces.
The first call to
.Fn archive_read_extract
creates a restore object using
.Xr archive_write_disk_new 3
and
.Xr archive_write_disk_set_standard_lookup 3 ,
then transparently invokes
.Xr archive_write_disk_set_options 3 ,
.Xr archive_write_header 3 ,
.Xr archive_write_data 3 ,
and
.Xr archive_write_finish_entry 3
to create the entry on disk and copy data into it.
The
.Va flags
argument is passed unmodified to
.Xr archive_write_disk_set_options 3 .
.It Fn archive_read_extract2
This is another version of
.Fn archive_read_extract
that allows you to provide your own restore object.
In particular, this allows you to override the standard lookup functions
using
.Xr archive_write_disk_set_group_lookup 3 ,
and
.Xr archive_write_disk_set_user_lookup 3 .
Note that
.Fn archive_read_extract2
does not accept a
.Va flags
argument; you should use
.Fn archive_write_disk_set_options
to set the restore options yourself.
.It Fn archive_read_extract_set_progress_callback
Sets a pointer to a user-defined callback that can be used
for updating progress displays during extraction.
The progress function will be invoked during the extraction of large
regular files.
The progress function will be invoked with the pointer provided to this call.
Generally, the data pointed to should include a reference to the archive
object and the archive_entry object so that various statistics
can be retrieved for the progress display.
.El
.\"
.Sh RETURN VALUES
Most functions return zero on success, non-zero on error.
The possible return codes include:
.Cm ARCHIVE_OK
(the operation succeeded),
.Cm ARCHIVE_WARN
(the operation succeeded but a non-critical error was encountered),
.Cm ARCHIVE_EOF
(end-of-archive was encountered),
.Cm ARCHIVE_RETRY
(the operation failed but can be retried),
and
.Cm ARCHIVE_FATAL
(there was a fatal error; the archive should be closed immediately).
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -100,8 +100,9 @@ archive_read_extract2(struct archive *_a, struct archive_entry *entry,
int r, r2; int r, r2;
/* Set up for this particular entry. */ /* Set up for this particular entry. */
archive_write_disk_set_skip_file(ad, if (a->skip_file_set)
a->skip_file_dev, a->skip_file_ino); archive_write_disk_set_skip_file(ad,
a->skip_file_dev, a->skip_file_ino);
r = archive_write_header(ad, entry); r = archive_write_header(ad, entry);
if (r < ARCHIVE_WARN) if (r < ARCHIVE_WARN)
r = ARCHIVE_WARN; r = ARCHIVE_WARN;
@ -116,7 +117,7 @@ archive_read_extract2(struct archive *_a, struct archive_entry *entry,
r2 = ARCHIVE_WARN; r2 = ARCHIVE_WARN;
/* Use the first message. */ /* Use the first message. */
if (r2 != ARCHIVE_OK && r == ARCHIVE_OK) if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)
archive_copy_error(&a->archive, ad); archive_copy_error(&a->archive, ad);
/* Use the worst error return. */ /* Use the worst error return. */
if (r2 < r) if (r2 < r)
r = r2; r = r2;
@ -138,13 +139,15 @@ archive_read_extract_set_progress_callback(struct archive *_a,
static int static int
copy_data(struct archive *ar, struct archive *aw) copy_data(struct archive *ar, struct archive *aw)
{ {
off_t offset; int64_t offset;
const void *buff; const void *buff;
struct extract *extract; struct extract *extract;
size_t size; size_t size;
int r; int r;
extract = get_extract((struct archive_read *)ar); extract = get_extract((struct archive_read *)ar);
if (extract == NULL)
return (ARCHIVE_FATAL);
for (;;) { for (;;) {
r = archive_read_data_block(ar, &buff, &size, &offset); r = archive_read_data_block(ar, &buff, &size, &offset);
if (r == ARCHIVE_EOF) if (r == ARCHIVE_EOF)

View File

@ -0,0 +1,127 @@
.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
.\"
.Dd March 19, 2011
.Dt ARCHIVE_READ_FILTER 3
.Os
.Sh NAME
.Nm archive_read_support_filter_all ,
.Nm archive_read_support_filter_bzip2 ,
.Nm archive_read_support_filter_compress ,
.Nm archive_read_support_filter_gzip ,
.Nm archive_read_support_filter_lzma ,
.Nm archive_read_support_filter_none ,
.Nm archive_read_support_filter_xz ,
.Nm archive_read_support_filter_program ,
.Nm archive_read_support_filter_program_signature
.Nd functions for reading streaming archives
.\"
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fn archive_read_support_filter_all "struct archive *"
.Ft int
.Fn archive_read_support_filter_bzip2 "struct archive *"
.Ft int
.Fn archive_read_support_filter_compress "struct archive *"
.Ft int
.Fn archive_read_support_filter_gzip "struct archive *"
.Ft int
.Fn archive_read_support_filter_lzma "struct archive *"
.Ft int
.Fn archive_read_support_filter_none "struct archive *"
.Ft int
.Fn archive_read_support_filter_xz "struct archive *"
.Ft int
.Fo archive_read_support_filter_program
.Fa "struct archive *"
.Fa "const char *cmd"
.Fc
.Ft int
.Fo archive_read_support_filter_program_signature
.Fa "struct archive *"
.Fa "const char *cmd"
.Fa "const void *signature"
.Fa "size_t signature_length"
.Fc
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Xo
.Fn archive_read_support_filter_bzip2 ,
.Fn archive_read_support_filter_compress ,
.Fn archive_read_support_filter_gzip ,
.Fn archive_read_support_filter_lzma ,
.Fn archive_read_support_filter_none ,
.Fn archive_read_support_filter_xz
.Xc
Enables auto-detection code and decompression support for the
specified compression.
These functions may fall back on external programs if an appropriate
library was not available at build time.
Decompression using an external program is usually slower than
decompression through built-in libraries.
Note that
.Dq none
is always enabled by default.
.It Fn archive_read_support_filter_all
Enables all available decompression filters.
.It Fn archive_read_support_filter_program
Data is fed through the specified external program before being dearchived.
Note that this disables automatic detection of the compression format,
so it makes no sense to specify this in conjunction with any other
decompression option.
.It Fn archive_read_support_filter_program_signature
This feeds data through the specified external program
but only if the initial bytes of the data match the specified
signature value.
.El
.\"
.\". Sh EXAMPLE
.\"
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
if the compression is fully supported,
.Cm ARCHIVE_WARN
if the compression is supported only through an external program.
.Pp
.Fn archive_read_support_filter_none
always succeeds.
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_format 3

View File

@ -0,0 +1,175 @@
.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 19, 2011
.Dt ARCHIVE_READ_FORMAT 3
.Os
.Sh NAME
.Nm archive_read_support_format_7zip ,
.Nm archive_read_support_format_all ,
.Nm archive_read_support_format_ar ,
.Nm archive_read_support_format_by_code ,
.Nm archive_read_support_format_cab ,
.Nm archive_read_support_format_cpio ,
.Nm archive_read_support_format_empty ,
.Nm archive_read_support_format_iso9660 ,
.Nm archive_read_support_format_lha ,
.Nm archive_read_support_format_mtree,
.Nm archive_read_support_format_rar,
.Nm archive_read_support_format_raw,
.Nm archive_read_support_format_tar ,
.Nm archive_read_support_format_xar ,
.Nm archive_read_support_format_zip
.Nd functions for reading streaming archives
.\"
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fn archive_read_support_format_7zip "struct archive *"
.Ft int
.Fn archive_read_support_format_all "struct archive *"
.Ft int
.Fn archive_read_support_format_ar "struct archive *"
.Ft int
.Fn archive_read_support_format_by_code "struct archive *" "int"
.Ft int
.Fn archive_read_support_format_cab "struct archive *"
.Ft int
.Fn archive_read_support_format_cpio "struct archive *"
.Ft int
.Fn archive_read_support_format_empty "struct archive *"
.Ft int
.Fn archive_read_support_format_iso9660 "struct archive *"
.Ft int
.Fn archive_read_support_format_lha "struct archive *"
.Ft int
.Fn archive_read_support_format_mtree "struct archive *"
.Ft int
.Fn archive_read_support_format_rar "struct archive *"
.Ft int
.Fn archive_read_support_format_raw "struct archive *"
.Ft int
.Fn archive_read_support_format_tar "struct archive *"
.Ft int
.Fn archive_read_support_format_xar "struct archive *"
.Ft int
.Fn archive_read_support_format_zip "struct archive *"
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Xo
.Fn archive_read_support_format_7zip ,
.Fn archive_read_support_format_ar ,
.Fn archive_read_support_format_cab ,
.Fn archive_read_support_format_cpio ,
.Fn archive_read_support_format_iso9660 ,
.Fn archive_read_support_format_lha ,
.Fn archive_read_support_format_mtree ,
.Fn archive_read_support_format_rar ,
.Fn archive_read_support_format_raw ,
.Fn archive_read_support_format_tar ,
.Fn archive_read_support_format_xar ,
.Fn archive_read_support_format_zip
.Xc
Enables support---including auto-detection code---for the
specified archive format.
For example,
.Fn archive_read_support_format_tar
enables support for a variety of standard tar formats, old-style tar,
ustar, pax interchange format, and many common variants.
.It Fn archive_read_support_format_all
Enables support for all available formats except the
.Dq raw
format (see below).
.It Fn archive_read_support_format_by_code
Enables a single format specified by the format code.
This can be useful when reading a single archive twice;
use
.Fn archive_format
after reading the first time and pass the resulting code
to this function to selectively enable only the necessary
format support.
Note: In statically-linked executables, this will cause
your program to include support for every format.
If executable size is a concern, you may wish to avoid
using this function.
.It Fn archive_read_support_format_empty
Enables support for treating empty files as empty archives.
Because empty files are valid for several different formats,
it is not possible to accurately determine a format for
an empty file based purely on contents.
So empty files are treated by libarchive as a distinct
format.
.It Fn archive_read_support_format_raw
The
.Dq raw
format handler allows libarchive to be used to read arbitrary data.
It treats any data stream as an archive with a single entry.
The pathname of this entry is
.Dq data ;
all other entry fields are unset.
This is not enabled by
.Fn archive_read_support_format_all
in order to avoid erroneous handling of damaged archives.
.El
.\" .Sh EXAMPLE
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
on success, or
.Cm ARCHIVE_FATAL .
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5
.Sh BUGS
Many traditional archiver programs treat
empty files as valid empty archives.
For example, many implementations of
.Xr tar 1
allow you to append entries to an empty file.
Of course, it is impossible to determine the format of an empty file
by inspecting the contents, so this library treats empty files as
having a special
.Dq empty
format.
.Pp
Using the
.Dq raw
handler together with any other handler will often work
but can produce surprising results.

View File

@ -0,0 +1,91 @@
.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 20, 2011
.Dt ARCHIVE_READ_FREE 3
.Os
.Sh NAME
.Nm archive_read_close ,
.Nm archive_read_finish ,
.Nm archive_read_free
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fn archive_read_close "struct archive *"
.Ft int
.Fn archive_read_finish "struct archive *"
.Ft int
.Fn archive_read_free "struct archive *"
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_close
Complete the archive and invoke the close callback.
.It Fn archive_read_finish
This is a deprecated synonym for
.Fn archive_read_free .
The new name was introduced with libarchive 3.0.
Applications that need to compile with either libarchive 2
or libarchive 3 should continue to use the
.Fn archive_read_finish
name.
Both names will be supported until libarchive 4.0 is
released, which is not expected to occur earlier
than 2013.
.It Fn archive_read_free
Invokes
.Fn archive_read_close
if it was not invoked manually, then release all resources.
Note: In libarchive 1.x, this function was declared to return
.Ft void ,
which made it impossible to detect certain errors when
.Fn archive_read_close
was invoked implicitly from this function.
The declaration is corrected beginning with libarchive 2.0.
.El
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
on success, or
.Cm ARCHIVE_FATAL .
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr libarchive 3 ,
.Xr archive_read_new 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3

View File

@ -0,0 +1,89 @@
.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
.\"
.Dd March 22, 2011
.Dt ARCHIVE_READ_HEADER 3
.Os
.Sh NAME
.Nm archive_read_next_header ,
.Nm archive_read_next_header2
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fn archive_read_next_header "struct archive *" "struct archive_entry **"
.Ft int
.Fn archive_read_next_header2 "struct archive *" "struct archive_entry *"
.\"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_next_header
Read the header for the next entry and return a pointer to
a
.Tn struct archive_entry .
This is a convenience wrapper around
.Fn archive_read_next_header2
that reuses an internal
.Tn struct archive_entry
object for each request.
.It Fn archive_read_next_header2
Read the header for the next entry and populate the provided
.Tn struct archive_entry .
.El
.\"
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
(the operation succeeded),
.Cm ARCHIVE_WARN
(the operation succeeded but a non-critical error was encountered),
.Cm ARCHIVE_EOF
(end-of-archive was encountered),
.Cm ARCHIVE_RETRY
(the operation failed but can be retried),
and
.Cm ARCHIVE_FATAL
(there was a fatal error; the archive should be closed immediately).
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_extract 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_open 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -0,0 +1,57 @@
.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 20, 2011
.Dt ARCHIVE_READ_NEW 3
.Os
.Sh NAME
.Nm archive_read_new
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft struct archive *
.Fn archive_read_new "void"
.Sh DESCRIPTION
Allocates and initializes a
.Tn struct archive
object suitable for reading from an archive.
.Dv NULL
is returned on error.
.Pp
A complete description of the
.Tn struct archive
object can be found in the overview manual page for
.Xr libarchive 3 .
.\" .Sh ERRORS
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -0,0 +1,231 @@
.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
.\"
.Dd March 19, 2011
.Dt ARCHIVE_READ_OPEN 3
.Os
.Sh NAME
.Nm archive_read_open ,
.Nm archive_read_open2 ,
.Nm archive_read_open_fd ,
.Nm archive_read_open_FILE ,
.Nm archive_read_open_filename ,
.Nm archive_read_open_memory ,
.Nd functions for reading streaming archives
.Sh SYNOPSIS
.In archive.h
.Ft int
.Fo archive_read_open
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "archive_open_callback *"
.Fa "archive_read_callback *"
.Fa "archive_close_callback *"
.Fc
.Ft int
.Fo archive_read_open2
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "archive_open_callback *"
.Fa "archive_read_callback *"
.Fa "archive_skip_callback *"
.Fa "archive_close_callback *"
.Fc
.Ft int
.Fn archive_read_open_FILE "struct archive *" "FILE *file"
.Ft int
.Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size"
.Ft int
.Fo archive_read_open_filename
.Fa "struct archive *"
.Fa "const char *filename"
.Fa "size_t block_size"
.Fc
.Ft int
.Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size"
.Sh DESCRIPTION
.Bl -tag -compact -width indent
.It Fn archive_read_open
The same as
.Fn archive_read_open2 ,
except that the skip callback is assumed to be
.Dv NULL .
.It Fn archive_read_open2
Freeze the settings, open the archive, and prepare for reading entries.
This is the most generic version of this call, which accepts
four callback functions.
Most clients will want to use
.Fn archive_read_open_filename ,
.Fn archive_read_open_FILE ,
.Fn archive_read_open_fd ,
or
.Fn archive_read_open_memory
instead.
The library invokes the client-provided functions to obtain
raw bytes from the archive.
.It Fn archive_read_open_FILE
Like
.Fn archive_read_open ,
except that it accepts a
.Ft "FILE *"
pointer.
This function should not be used with tape drives or other devices
that require strict I/O blocking.
.It Fn archive_read_open_fd
Like
.Fn archive_read_open ,
except that it accepts a file descriptor and block size rather than
a set of function pointers.
Note that the file descriptor will not be automatically closed at
end-of-archive.
This function is safe for use with tape drives or other blocked devices.
.It Fn archive_read_open_file
This is a deprecated synonym for
.Fn archive_read_open_filename .
.It Fn archive_read_open_filename
Like
.Fn archive_read_open ,
except that it accepts a simple filename and a block size.
A NULL filename represents standard input.
This function is safe for use with tape drives or other blocked devices.
.It Fn archive_read_open_memory
Like
.Fn archive_read_open ,
except that it accepts a pointer and size of a block of
memory containing the archive data.
.El
.Pp
A complete description of the
.Tn struct archive
and
.Tn struct archive_entry
objects can be found in the overview manual page for
.Xr libarchive 3 .
.Sh CLIENT CALLBACKS
The callback functions must match the following prototypes:
.Bl -item -offset indent
.It
.Ft typedef ssize_t
.Fo archive_read_callback
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "const void **buffer"
.Fc
.It
.Ft typedef off_t
.Fo archive_skip_callback
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "off_t request"
.Fc
.It
.Ft typedef int
.Fn archive_open_callback "struct archive *" "void *client_data"
.It
.Ft typedef int
.Fn archive_close_callback "struct archive *" "void *client_data"
.El
.Pp
The open callback is invoked by
.Fn archive_open .
It should return
.Cm ARCHIVE_OK
if the underlying file or data source is successfully
opened.
If the open fails, it should call
.Fn archive_set_error
to register an error code and message and return
.Cm ARCHIVE_FATAL .
.Pp
The read callback is invoked whenever the library
requires raw bytes from the archive.
The read callback should read data into a buffer,
set the
.Li const void **buffer
argument to point to the available data, and
return a count of the number of bytes available.
The library will invoke the read callback again
only after it has consumed this data.
The library imposes no constraints on the size
of the data blocks returned.
On end-of-file, the read callback should
return zero.
On error, the read callback should invoke
.Fn archive_set_error
to register an error code and message and
return -1.
.Pp
The skip callback is invoked when the
library wants to ignore a block of data.
The return value is the number of bytes actually
skipped, which may differ from the request.
If the callback cannot skip data, it should return
zero.
If the skip callback is not provided (the
function pointer is
.Dv NULL ),
the library will invoke the read function
instead and simply discard the result.
A skip callback can provide significant
performance gains when reading uncompressed
archives from slow disk drives or other media
that can skip quickly.
.Pp
The close callback is invoked by archive_close when
the archive processing is complete.
The callback should return
.Cm ARCHIVE_OK
on success.
On failure, the callback should invoke
.Fn archive_set_error
to register an error code and message and
return
.Cm ARCHIVE_FATAL.
.\" .Sh EXAMPLE
.\"
.Sh RETURN VALUES
These functions return
.Cm ARCHIVE_OK
on success, or
.Cm ARCHIVE_FATAL .
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_read 3 ,
.Xr archive_read_data 3 ,
.Xr archive_read_filter 3 ,
.Xr archive_read_format 3 ,
.Xr archive_read_set_options 3 ,
.Xr archive_util 3 ,
.Xr tar 5

View File

@ -53,17 +53,13 @@ __FBSDID("$FreeBSD$");
struct read_fd_data { struct read_fd_data {
int fd; int fd;
size_t block_size; size_t block_size;
char can_skip; char use_lseek;
void *buffer; void *buffer;
}; };
static int file_close(struct archive *, void *); static int file_close(struct archive *, void *);
static ssize_t file_read(struct archive *, void *, const void **buff); static ssize_t file_read(struct archive *, void *, const void **buff);
#if ARCHIVE_API_VERSION < 2 static int64_t file_skip(struct archive *, void *, int64_t request);
static ssize_t file_skip(struct archive *, void *, size_t request);
#else
static off_t file_skip(struct archive *, void *, off_t request);
#endif
int int
archive_read_open_fd(struct archive *a, int fd, size_t block_size) archive_read_open_fd(struct archive *a, int fd, size_t block_size)
@ -78,7 +74,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
mine = (struct read_fd_data *)malloc(sizeof(*mine)); mine = (struct read_fd_data *)calloc(1, sizeof(*mine));
b = malloc(block_size); b = malloc(block_size);
if (mine == NULL || b == NULL) { if (mine == NULL || b == NULL) {
archive_set_error(a, ENOMEM, "No memory"); archive_set_error(a, ENOMEM, "No memory");
@ -98,15 +94,17 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
*/ */
if (S_ISREG(st.st_mode)) { if (S_ISREG(st.st_mode)) {
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
mine->can_skip = 1; mine->use_lseek = 1;
} else }
mine->can_skip = 0;
#if defined(__CYGWIN__) || defined(_WIN32) #if defined(__CYGWIN__) || defined(_WIN32)
setmode(mine->fd, O_BINARY); setmode(mine->fd, O_BINARY);
#endif #endif
return (archive_read_open2(a, mine, archive_read_set_read_callback(a, file_read);
NULL, file_read, file_skip, file_close)); archive_read_set_skip_callback(a, file_skip);
archive_read_set_close_callback(a, file_close);
archive_read_set_callback_data(a, mine);
return (archive_read_open1(a));
} }
static ssize_t static ssize_t
@ -127,55 +125,48 @@ file_read(struct archive *a, void *client_data, const void **buff)
} }
} }
#if ARCHIVE_API_VERSION < 2 static int64_t
static ssize_t file_skip(struct archive *a, void *client_data, int64_t request)
file_skip(struct archive *a, void *client_data, size_t request)
#else
static off_t
file_skip(struct archive *a, void *client_data, off_t request)
#endif
{ {
struct read_fd_data *mine = (struct read_fd_data *)client_data; struct read_fd_data *mine = (struct read_fd_data *)client_data;
off_t skip = (off_t)request;
off_t old_offset, new_offset; off_t old_offset, new_offset;
int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */
if (!mine->can_skip) if (!mine->use_lseek)
return (0); return (0);
/* Reduce a request that would overflow the 'skip' variable. */
if (sizeof(request) > sizeof(skip)) {
int64_t max_skip =
(((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
if (request > max_skip)
skip = max_skip;
}
/* Reduce request to the next smallest multiple of block_size */ /* Reduce request to the next smallest multiple of block_size */
request = (request / mine->block_size) * mine->block_size; request = (request / mine->block_size) * mine->block_size;
if (request == 0) if (request == 0)
return (0); return (0);
/* if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) &&
* Hurray for lazy evaluation: if the first lseek fails, the second ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0))
* one will not be executed. return (new_offset - old_offset);
*/
if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) ||
((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0))
{
/* If seek failed once, it will probably fail again. */
mine->can_skip = 0;
if (errno == ESPIPE) /* If seek failed once, it will probably fail again. */
{ mine->use_lseek = 0;
/*
* Failure to lseek() can be caused by the file /* Let libarchive recover with read+discard. */
* descriptor pointing to a pipe, socket or FIFO. if (errno == ESPIPE)
* Return 0 here, so the compression layer will use return (0);
* read()s instead to advance the file descriptor.
* It's slower of course, but works as well. /*
*/ * There's been an error other than ESPIPE. This is most
return (0); * likely caused by a programmer error (too large request)
} * or a corrupted archive file.
/* */
* There's been an error other than ESPIPE. This is most archive_set_error(a, errno, "Error seeking");
* likely caused by a programmer error (too large request) return (-1);
* or a corrupted archive file.
*/
archive_set_error(a, errno, "Error seeking");
return (-1);
}
return (new_offset - old_offset);
} }
static int static int

View File

@ -59,11 +59,7 @@ struct read_FILE_data {
static int file_close(struct archive *, void *); static int file_close(struct archive *, void *);
static ssize_t file_read(struct archive *, void *, const void **buff); static ssize_t file_read(struct archive *, void *, const void **buff);
#if ARCHIVE_API_VERSION < 2 static int64_t file_skip(struct archive *, void *, int64_t request);
static ssize_t file_skip(struct archive *, void *, size_t request);
#else
static off_t file_skip(struct archive *, void *, off_t request);
#endif
int int
archive_read_open_FILE(struct archive *a, FILE *f) archive_read_open_FILE(struct archive *a, FILE *f)
@ -101,8 +97,11 @@ archive_read_open_FILE(struct archive *a, FILE *f)
setmode(fileno(mine->f), O_BINARY); setmode(fileno(mine->f), O_BINARY);
#endif #endif
return (archive_read_open2(a, mine, NULL, file_read, archive_read_set_read_callback(a, file_read);
file_skip, file_close)); archive_read_set_skip_callback(a, file_skip);
archive_read_set_close_callback(a, file_close);
archive_read_set_callback_data(a, mine);
return (archive_read_open1(a));
} }
static ssize_t static ssize_t
@ -119,15 +118,18 @@ file_read(struct archive *a, void *client_data, const void **buff)
return (bytes_read); return (bytes_read);
} }
#if ARCHIVE_API_VERSION < 2 static int64_t
static ssize_t file_skip(struct archive *a, void *client_data, int64_t request)
file_skip(struct archive *a, void *client_data, size_t request)
#else
static off_t
file_skip(struct archive *a, void *client_data, off_t request)
#endif
{ {
struct read_FILE_data *mine = (struct read_FILE_data *)client_data; struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
#if HAVE_FSEEKO
off_t skip = (off_t)request;
#elif HAVE__FSEEKI64
int64_t skip = request;
#else
long skip = (long)request;
#endif
int skip_bits = sizeof(skip) * 8 - 1;
(void)a; /* UNUSED */ (void)a; /* UNUSED */
@ -140,10 +142,20 @@ file_skip(struct archive *a, void *client_data, off_t request)
if (request == 0) if (request == 0)
return (0); return (0);
/* If request is too big for a long or an off_t, reduce it. */
if (sizeof(request) > sizeof(skip)) {
int64_t max_skip =
(((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1;
if (request > max_skip)
skip = max_skip;
}
#if HAVE_FSEEKO #if HAVE_FSEEKO
if (fseeko(mine->f, request, SEEK_CUR) != 0) if (fseeko(mine->f, skip, SEEK_CUR) != 0)
#elif HAVE__FSEEKI64
if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)
#else #else
if (fseek(mine->f, request, SEEK_CUR) != 0) if (fseek(mine->f, skip, SEEK_CUR) != 0)
#endif #endif
{ {
mine->can_skip = 0; mine->can_skip = 0;

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2003-2010 Tim Kientzle
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -26,6 +26,9 @@
#include "archive_platform.h" #include "archive_platform.h"
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_STAT_H #ifdef HAVE_SYS_STAT_H
#include <sys/stat.h> #include <sys/stat.h>
#endif #endif
@ -47,8 +50,17 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
#include <unistd.h> #include <unistd.h>
#endif #endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#include <sys/disk.h>
#elif defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/disklabel.h>
#include <sys/dkio.h>
#elif defined(__DragonFly__)
#include <sys/diskslice.h>
#endif
#include "archive.h" #include "archive.h"
#include "archive_string.h"
#ifndef O_BINARY #ifndef O_BINARY
#define O_BINARY 0 #define O_BINARY 0
@ -59,17 +71,21 @@ struct read_file_data {
size_t block_size; size_t block_size;
void *buffer; void *buffer;
mode_t st_mode; /* Mode bits for opened file. */ mode_t st_mode; /* Mode bits for opened file. */
char can_skip; /* This file supports skipping. */ char use_lseek;
char filename[1]; /* Must be last! */ enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type;
union {
char m[1];/* MBS filename. */
wchar_t w[1];/* WCS filename. */
} filename; /* Must be last! */
}; };
static int file_close(struct archive *, void *); static int file_close(struct archive *, void *);
static int file_open_filename(struct archive *, enum fnt_e, const void *,
size_t);
static ssize_t file_read(struct archive *, void *, const void **buff); static ssize_t file_read(struct archive *, void *, const void **buff);
#if ARCHIVE_API_VERSION < 2 static int64_t file_seek(struct archive *, void *, int64_t request, int);
static ssize_t file_skip(struct archive *, void *, size_t request); static int64_t file_skip(struct archive *, void *, int64_t request);
#else static int64_t file_skip_lseek(struct archive *, void *, int64_t request);
static off_t file_skip(struct archive *, void *, off_t request);
#endif
int int
archive_read_open_file(struct archive *a, const char *filename, archive_read_open_file(struct archive *a, const char *filename,
@ -81,15 +97,76 @@ archive_read_open_file(struct archive *a, const char *filename,
int int
archive_read_open_filename(struct archive *a, const char *filename, archive_read_open_filename(struct archive *a, const char *filename,
size_t block_size) size_t block_size)
{
enum fnt_e filename_type;
if (filename == NULL || filename[0] == '\0') {
filename_type = FNT_STDIN;
} else
filename_type = FNT_MBS;
return (file_open_filename(a, filename_type, filename, block_size));
}
int
archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
size_t block_size)
{
enum fnt_e filename_type;
if (wfilename == NULL || wfilename[0] == L'\0') {
filename_type = FNT_STDIN;
} else {
#if defined(_WIN32) && !defined(__CYGWIN__)
filename_type = FNT_WCS;
#else
/*
* POSIX system does not support a wchar_t interface for
* open() system call, so we have to translate a whcar_t
* filename to multi-byte one and use it.
*/
struct archive_string fn;
int r;
archive_string_init(&fn);
if (archive_string_append_from_wcs(&fn, wfilename,
wcslen(wfilename)) != 0) {
archive_set_error(a, EINVAL,
"Failed to convert a wide-character filename to"
" a multi-byte filename");
archive_string_free(&fn);
return (ARCHIVE_FATAL);
}
r = file_open_filename(a, FNT_MBS, fn.s, block_size);
archive_string_free(&fn);
return (r);
#endif
}
return (file_open_filename(a, filename_type, wfilename, block_size));
}
static int
file_open_filename(struct archive *a, enum fnt_e filename_type,
const void *_filename, size_t block_size)
{ {
struct stat st; struct stat st;
struct read_file_data *mine; struct read_file_data *mine;
void *b; void *buffer;
const char *filename = NULL;
const wchar_t *wfilename = NULL;
int fd; int fd;
int is_disk_like = 0;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */
#elif defined(__NetBSD__) || defined(__OpenBSD__)
struct disklabel dl;
#elif defined(__DragonFly__)
struct partinfo pi;
#endif
archive_clear_error(a); archive_clear_error(a);
if (filename == NULL || filename[0] == '\0') { if (filename_type == FNT_STDIN) {
/* We used to invoke archive_read_open_fd(a,0,block_size) /* We used to delegate stdin support by
* directly calling archive_read_open_fd(a,0,block_size)
* here, but that doesn't (and shouldn't) handle the * here, but that doesn't (and shouldn't) handle the
* end-of-file flush when reading stdout from a pipe. * end-of-file flush when reading stdout from a pipe.
* Basically, read_open_fd() is intended for folks who * Basically, read_open_fd() is intended for folks who
@ -97,60 +174,152 @@ archive_read_open_filename(struct archive *a, const char *filename,
* API is intended to be a little smarter for folks who * API is intended to be a little smarter for folks who
* want easy handling of the common case. * want easy handling of the common case.
*/ */
filename = ""; /* Normalize NULL to "" */
fd = 0; fd = 0;
#if defined(__CYGWIN__) || defined(_WIN32) #if defined(__CYGWIN__) || defined(_WIN32)
setmode(0, O_BINARY); setmode(0, O_BINARY);
#endif #endif
} else { filename = "";
} else if (filename_type == FNT_MBS) {
filename = (const char *)_filename;
fd = open(filename, O_RDONLY | O_BINARY); fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0) { if (fd < 0) {
archive_set_error(a, errno, archive_set_error(a, errno,
"Failed to open '%s'", filename); "Failed to open '%s'", filename);
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
} else {
#if defined(_WIN32) && !defined(__CYGWIN__)
wfilename = (const wchar_t *)_filename;
fd = _wopen(wfilename, O_RDONLY | O_BINARY);
if (fd < 0 && errno == ENOENT) {
wchar_t *fullpath;
fullpath = __la_win_permissive_name_w(wfilename);
if (fullpath != NULL) {
fd = _wopen(fullpath, O_RDONLY | O_BINARY);
free(fullpath);
}
}
if (fd < 0) {
archive_set_error(a, errno,
"Failed to open '%S'", wfilename);
return (ARCHIVE_FATAL);
}
#else
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Unexpedted operation in archive_read_open_filename");
return (ARCHIVE_FATAL);
#endif
} }
if (fstat(fd, &st) != 0) { if (fstat(fd, &st) != 0) {
archive_set_error(a, errno, "Can't stat '%s'", filename); if (filename_type == FNT_WCS)
archive_set_error(a, errno, "Can't stat '%S'",
wfilename);
else
archive_set_error(a, errno, "Can't stat '%s'",
filename);
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
mine = (struct read_file_data *)calloc(1, /*
sizeof(*mine) + strlen(filename)); * Determine whether the input looks like a disk device or a
b = malloc(block_size); * tape device. The results are used below to select an I/O
if (mine == NULL || b == NULL) { * strategy:
* = "disk-like" devices support arbitrary lseek() and will
* support I/O requests of any size. So we get easy skipping
* and can cheat on block sizes to get better performance.
* = "tape-like" devices require strict blocking and use
* specialized ioctls for seeking.
* = "socket-like" devices cannot seek at all but can improve
* performance by using nonblocking I/O to read "whatever is
* available right now".
*
* Right now, we only specially recognize disk-like devices,
* but it should be straightforward to add probes and strategy
* here for tape-like and socket-like devices.
*/
if (S_ISREG(st.st_mode)) {
/* Safety: Tell the extractor not to overwrite the input. */
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
/* Regular files act like disks. */
is_disk_like = 1;
}
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
/* FreeBSD: if it supports DIOCGMEDIASIZE ioctl, it's disk-like. */
else if (S_ISCHR(st.st_mode) &&
ioctl(fd, DIOCGMEDIASIZE, &mediasize) == 0 &&
mediasize > 0) {
is_disk_like = 1;
}
#elif defined(__NetBSD__) || defined(__OpenBSD__)
/* Net/OpenBSD: if it supports DIOCGDINFO ioctl, it's disk-like. */
else if ((S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) &&
ioctl(fd, DIOCGDINFO, &dl) == 0 &&
dl.d_partitions[DISKPART(st.st_rdev)].p_size > 0) {
is_disk_like = 1;
}
#elif defined(__DragonFly__)
/* DragonFly BSD: if it supports DIOCGPART ioctl, it's disk-like. */
else if (S_ISCHR(st.st_mode) &&
ioctl(fd, DIOCGPART, &pi) == 0 &&
pi.media_size > 0) {
is_disk_like = 1;
}
#elif defined(__linux__)
/* Linux: All block devices are disk-like. */
else if (S_ISBLK(st.st_mode) &&
lseek(fd, 0, SEEK_CUR) == 0 &&
lseek(fd, 0, SEEK_SET) == 0 &&
lseek(fd, 0, SEEK_END) > 0 &&
lseek(fd, 0, SEEK_SET) == 0) {
is_disk_like = 1;
}
#endif
/* TODO: Add an "is_tape_like" variable and appropriate tests. */
if (filename_type == FNT_WCS)
mine = (struct read_file_data *)calloc(1,
sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));
else
mine = (struct read_file_data *)calloc(1,
sizeof(*mine) + strlen(filename));
/* Disk-like devices prefer power-of-two block sizes. */
/* Use provided block_size as a guide so users have some control. */
if (is_disk_like) {
size_t new_block_size = 64 * 1024;
while (new_block_size < block_size
&& new_block_size < 64 * 1024 * 1024)
new_block_size *= 2;
block_size = new_block_size;
}
buffer = malloc(block_size);
if (mine == NULL || buffer == NULL) {
archive_set_error(a, ENOMEM, "No memory"); archive_set_error(a, ENOMEM, "No memory");
free(mine); free(mine);
free(b); free(buffer);
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
strcpy(mine->filename, filename); if (filename_type == FNT_WCS)
wcscpy(mine->filename.w, wfilename);
else
strcpy(mine->filename.m, filename);
mine->filename_type = filename_type;
mine->block_size = block_size; mine->block_size = block_size;
mine->buffer = b; mine->buffer = buffer;
mine->fd = fd; mine->fd = fd;
/* Remember mode so close can decide whether to flush. */ /* Remember mode so close can decide whether to flush. */
mine->st_mode = st.st_mode; mine->st_mode = st.st_mode;
/* If we're reading a file from disk, ensure that we don't
overwrite it with an extracted file. */ /* Disk-like inputs can use lseek(). */
if (S_ISREG(st.st_mode)) { if (is_disk_like) {
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); archive_read_set_seek_callback(a, file_seek);
/* mine->use_lseek = 1;
* Enabling skip here is a performance optimization
* for anything that supports lseek(). On FreeBSD
* (and probably many other systems), only regular
* files and raw disk devices support lseek() (on
* other input types, lseek() returns success but
* doesn't actually change the file pointer, which
* just completely screws up the position-tracking
* logic). In addition, I've yet to find a portable
* way to determine if a device is a raw disk device.
* So I don't see a way to do much better than to only
* enable this optimization for regular files.
*/
mine->can_skip = 1;
} }
return (archive_read_open2(a, mine,
NULL, file_read, file_skip, file_close)); archive_read_set_read_callback(a, file_read);
archive_read_set_skip_callback(a, file_skip);
archive_read_set_close_callback(a, file_close);
archive_read_set_callback_data(a, mine);
return (archive_read_open1(a));
} }
static ssize_t static ssize_t
@ -159,79 +328,146 @@ file_read(struct archive *a, void *client_data, const void **buff)
struct read_file_data *mine = (struct read_file_data *)client_data; struct read_file_data *mine = (struct read_file_data *)client_data;
ssize_t bytes_read; ssize_t bytes_read;
/* TODO: If a recent lseek() operation has left us
* mis-aligned, read and return a short block to try to get
* us back in alignment. */
/* TODO: Someday, try mmap() here; if that succeeds, give
* the entire file to libarchive as a single block. That
* could be a lot faster than block-by-block manual I/O. */
/* TODO: We might be able to improve performance on pipes and
* sockets by setting non-blocking I/O and just accepting
* whatever we get here instead of waiting for a full block
* worth of data. */
*buff = mine->buffer; *buff = mine->buffer;
for (;;) { for (;;) {
bytes_read = read(mine->fd, mine->buffer, mine->block_size); bytes_read = read(mine->fd, mine->buffer, mine->block_size);
if (bytes_read < 0) { if (bytes_read < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
else if (mine->filename[0] == '\0') else if (mine->filename_type == FNT_STDIN)
archive_set_error(a, errno, "Error reading stdin"); archive_set_error(a, errno,
"Error reading stdin");
else if (mine->filename_type == FNT_MBS)
archive_set_error(a, errno,
"Error reading '%s'", mine->filename.m);
else else
archive_set_error(a, errno, "Error reading '%s'", archive_set_error(a, errno,
mine->filename); "Error reading '%S'", mine->filename.w);
} }
return (bytes_read); return (bytes_read);
} }
} }
#if ARCHIVE_API_VERSION < 2 /*
static ssize_t * Regular files and disk-like block devices can use simple lseek
file_skip(struct archive *a, void *client_data, size_t request) * without needing to round the request to the block size.
#else *
static off_t * TODO: This can leave future reads mis-aligned. Since we know the
file_skip(struct archive *a, void *client_data, off_t request) * offset here, we should store it and use it in file_read() above
#endif * to determine whether we should perform a short read to get back
* into alignment. Long series of mis-aligned reads can negatively
* impact disk throughput. (Of course, the performance impact should
* be carefully tested; extra code complexity is only worthwhile if
* it does provide measurable improvement.)
*
* TODO: Be lazy about the actual seek. There are a few pathological
* cases where libarchive makes a bunch of seek requests in a row
* without any intervening reads. This isn't a huge performance
* problem, since the kernel handles seeks lazily already, but
* it would be very slightly faster if we simply remembered the
* seek request here and then actually performed the seek at the
* top of the read callback above.
*/
static int64_t
file_skip_lseek(struct archive *a, void *client_data, int64_t request)
{ {
struct read_file_data *mine = (struct read_file_data *)client_data; struct read_file_data *mine = (struct read_file_data *)client_data;
#if defined(_WIN32) && !defined(__CYGWIN__)
/* We use _lseeki64() on Windows. */
int64_t old_offset, new_offset;
#else
off_t old_offset, new_offset; off_t old_offset, new_offset;
#endif
if (!mine->can_skip) /* We can't skip, so ... */ /* We use off_t here because lseek() is declared that way. */
return (0); /* ... skip zero bytes. */
/* Reduce request to the next smallest multiple of block_size */ /* TODO: Deal with case where off_t isn't 64 bits.
request = (request / mine->block_size) * mine->block_size; * This shouldn't be a problem on Linux or other POSIX
if (request == 0) * systems, since the configuration logic for libarchive
* tries to obtain a 64-bit off_t. It's still an issue
* on Windows, though, so it might suffice to just use
* _lseeki64() on Windows.
*/
if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 &&
(new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0)
return (new_offset - old_offset);
/* If lseek() fails, don't bother trying again. */
mine->use_lseek = 0;
/* Let libarchive recover with read+discard */
if (errno == ESPIPE)
return (0); return (0);
/* /* If the input is corrupted or truncated, fail. */
* Hurray for lazy evaluation: if the first lseek fails, the second if (mine->filename_type == FNT_STDIN)
* one will not be executed. archive_set_error(a, errno, "Error seeking in stdin");
*/ else if (mine->filename_type == FNT_MBS)
if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) < 0) || archive_set_error(a, errno, "Error seeking in '%s'",
((new_offset = lseek(mine->fd, request, SEEK_CUR)) < 0)) mine->filename.m);
{ else
/* If skip failed once, it will probably fail again. */ archive_set_error(a, errno, "Error seeking in '%S'",
mine->can_skip = 0; mine->filename.w);
return (-1);
}
if (errno == ESPIPE)
{ /*
/* * TODO: Implement another file_skip_XXXX that uses MTIO ioctls to
* Failure to lseek() can be caused by the file * accelerate operation on tape drives.
* descriptor pointing to a pipe, socket or FIFO. */
* Return 0 here, so the compression layer will use
* read()s instead to advance the file descriptor. static int64_t
* It's slower of course, but works as well. file_skip(struct archive *a, void *client_data, int64_t request)
*/ {
return (0); struct read_file_data *mine = (struct read_file_data *)client_data;
}
/* /* Delegate skip requests. */
* There's been an error other than ESPIPE. This is most if (mine->use_lseek)
* likely caused by a programmer error (too large request) return (file_skip_lseek(a, client_data, request));
* or a corrupted archive file.
*/ /* If we can't skip, return 0; libarchive will read+discard instead. */
if (mine->filename[0] == '\0') return (0);
/* }
* Should never get here, since lseek() on stdin ought
* to return an ESPIPE error. /*
*/ * TODO: Store the offset and use it in the read callback.
archive_set_error(a, errno, "Error seeking in stdin"); */
else static int64_t
archive_set_error(a, errno, "Error seeking in '%s'", file_seek(struct archive *a, void *client_data, int64_t request, int whence)
mine->filename); {
return (-1); struct read_file_data *mine = (struct read_file_data *)client_data;
} off_t r;
return (new_offset - old_offset);
/* We use off_t here because lseek() is declared that way. */
/* See above for notes about when off_t is less than 64 bits. */
r = lseek(mine->fd, request, whence);
if (r >= 0)
return r;
/* If the input is corrupted or truncated, fail. */
if (mine->filename_type == FNT_STDIN)
archive_set_error(a, errno, "Error seeking in stdin");
else if (mine->filename_type == FNT_MBS)
archive_set_error(a, errno, "Error seeking in '%s'",
mine->filename.m);
else
archive_set_error(a, errno, "Error seeking in '%S'",
mine->filename.w);
return (ARCHIVE_FATAL);
} }
static int static int
@ -246,7 +482,8 @@ file_close(struct archive *a, void *client_data)
/* /*
* Sometimes, we should flush the input before closing. * Sometimes, we should flush the input before closing.
* Regular files: faster to just close without flush. * Regular files: faster to just close without flush.
* Devices: must not flush (user might need to * Disk-like devices: Ditto.
* Tapes: must not flush (user might need to
* read the "next" item on a non-rewind device). * read the "next" item on a non-rewind device).
* Pipes and sockets: must flush (otherwise, the * Pipes and sockets: must flush (otherwise, the
* program feeding the pipe or socket may complain). * program feeding the pipe or socket may complain).
@ -263,7 +500,7 @@ file_close(struct archive *a, void *client_data)
} while (bytesRead > 0); } while (bytesRead > 0);
} }
/* If a named file was opened, then it needs to be closed. */ /* If a named file was opened, then it needs to be closed. */
if (mine->filename[0] != '\0') if (mine->filename_type != FNT_STDIN)
close(mine->fd); close(mine->fd);
} }
free(mine->buffer); free(mine->buffer);

View File

@ -41,18 +41,16 @@ __FBSDID("$FreeBSD$");
*/ */
struct read_memory_data { struct read_memory_data {
unsigned char *buffer; unsigned char *start;
unsigned char *p;
unsigned char *end; unsigned char *end;
ssize_t read_size; ssize_t read_size;
}; };
static int memory_read_close(struct archive *, void *); static int memory_read_close(struct archive *, void *);
static int memory_read_open(struct archive *, void *); static int memory_read_open(struct archive *, void *);
#if ARCHIVE_API_VERSION < 2 static int64_t memory_read_seek(struct archive *, void *, int64_t offset, int whence);
static ssize_t memory_read_skip(struct archive *, void *, size_t request); static int64_t memory_read_skip(struct archive *, void *, int64_t request);
#else
static off_t memory_read_skip(struct archive *, void *, off_t request);
#endif
static ssize_t memory_read(struct archive *, void *, const void **buff); static ssize_t memory_read(struct archive *, void *, const void **buff);
int int
@ -78,11 +76,16 @@ archive_read_open_memory2(struct archive *a, void *buff,
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
memset(mine, 0, sizeof(*mine)); memset(mine, 0, sizeof(*mine));
mine->buffer = (unsigned char *)buff; mine->start = mine->p = (unsigned char *)buff;
mine->end = mine->buffer + size; mine->end = mine->start + size;
mine->read_size = read_size; mine->read_size = read_size;
return (archive_read_open2(a, mine, memory_read_open, archive_read_set_open_callback(a, memory_read_open);
memory_read, memory_read_skip, memory_read_close)); archive_read_set_read_callback(a, memory_read);
archive_read_set_seek_callback(a, memory_read_seek);
archive_read_set_skip_callback(a, memory_read_skip);
archive_read_set_close_callback(a, memory_read_close);
archive_read_set_callback_data(a, mine);
return (archive_read_open1(a));
} }
/* /*
@ -110,11 +113,11 @@ memory_read(struct archive *a, void *client_data, const void **buff)
ssize_t size; ssize_t size;
(void)a; /* UNUSED */ (void)a; /* UNUSED */
*buff = mine->buffer; *buff = mine->p;
size = mine->end - mine->buffer; size = mine->end - mine->p;
if (size > mine->read_size) if (size > mine->read_size)
size = mine->read_size; size = mine->read_size;
mine->buffer += size; mine->p += size;
return (size); return (size);
} }
@ -123,26 +126,54 @@ memory_read(struct archive *a, void *client_data, const void **buff)
* necessary in order to better exercise internal code when used * necessary in order to better exercise internal code when used
* as a test harness. * as a test harness.
*/ */
#if ARCHIVE_API_VERSION < 2 static int64_t
static ssize_t memory_read_skip(struct archive *a, void *client_data, int64_t skip)
memory_read_skip(struct archive *a, void *client_data, size_t skip)
#else
static off_t
memory_read_skip(struct archive *a, void *client_data, off_t skip)
#endif
{ {
struct read_memory_data *mine = (struct read_memory_data *)client_data; struct read_memory_data *mine = (struct read_memory_data *)client_data;
(void)a; /* UNUSED */ (void)a; /* UNUSED */
if ((off_t)skip > (off_t)(mine->end - mine->buffer)) if ((int64_t)skip > (int64_t)(mine->end - mine->p))
skip = mine->end - mine->buffer; skip = mine->end - mine->p;
/* Round down to block size. */ /* Round down to block size. */
skip /= mine->read_size; skip /= mine->read_size;
skip *= mine->read_size; skip *= mine->read_size;
mine->buffer += skip; mine->p += skip;
return (skip); return (skip);
} }
/*
* Seeking.
*/
static int64_t
memory_read_seek(struct archive *a, void *client_data, int64_t offset, int whence)
{
struct read_memory_data *mine = (struct read_memory_data *)client_data;
(void)a; /* UNUSED */
switch (whence) {
case SEEK_SET:
mine->p = mine->start + offset;
break;
case SEEK_CUR:
mine->p += offset;
break;
case SEEK_END:
mine->p = mine->end + offset;
break;
default:
return ARCHIVE_FATAL;
}
if (mine->p < mine->start) {
mine->p = mine->start;
return ARCHIVE_FAILED;
}
if (mine->p > mine->end) {
mine->p = mine->end;
return ARCHIVE_FAILED;
}
return (mine->p - mine->start);
}
/* /*
* Close is just cleaning up our one small bit of data. * Close is just cleaning up our one small bit of data.
*/ */

View File

@ -42,13 +42,18 @@ struct archive_read_filter;
/* /*
* How bidding works for filters: * How bidding works for filters:
* * The bid manager reads the first block from the current source. * * The bid manager initializes the client-provided reader as the
* * It shows that block to each registered bidder. * first filter.
* * It invokes the bidder for each registered filter with the
* current head filter.
* * The bidders can use archive_read_filter_ahead() to peek ahead
* at the incoming data to compose their bids.
* * The bid manager creates a new filter structure for the winning * * The bid manager creates a new filter structure for the winning
* bidder and gives the winning bidder a chance to initialize it. * bidder and gives the winning bidder a chance to initialize it.
* * The new filter becomes the top filter in the archive_read structure * * The new filter becomes the new top filter and we repeat the
* and we repeat the process. * process.
* This ends only when no bidder provides a non-zero bid. * This ends only when no bidder provides a non-zero bid. Then
* we perform a similar dance with the registered format handlers.
*/ */
struct archive_read_filter_bidder { struct archive_read_filter_bidder {
/* Configuration data for the bidder. */ /* Configuration data for the bidder. */
@ -71,6 +76,7 @@ struct archive_read_filter_bidder {
* corresponding bidder above. * corresponding bidder above.
*/ */
struct archive_read_filter { struct archive_read_filter {
int64_t position;
/* Essentially all filters will need these values, so /* Essentially all filters will need these values, so
* just declare them here. */ * just declare them here. */
struct archive_read_filter_bidder *bidder; /* My bidder. */ struct archive_read_filter_bidder *bidder; /* My bidder. */
@ -80,6 +86,8 @@ struct archive_read_filter {
ssize_t (*read)(struct archive_read_filter *, const void **); ssize_t (*read)(struct archive_read_filter *, const void **);
/* Skip forward this many bytes. */ /* Skip forward this many bytes. */
int64_t (*skip)(struct archive_read_filter *self, int64_t request); int64_t (*skip)(struct archive_read_filter *self, int64_t request);
/* Seek to an absolute location. */
int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence);
/* Close (just this filter) and free(self). */ /* Close (just this filter) and free(self). */
int (*close)(struct archive_read_filter *self); int (*close)(struct archive_read_filter *self);
/* My private data. */ /* My private data. */
@ -97,8 +105,8 @@ struct archive_read_filter {
size_t client_total; size_t client_total;
const char *client_next; const char *client_next;
size_t client_avail; size_t client_avail;
int64_t position;
char end_of_file; char end_of_file;
char closed;
char fatal; char fatal;
}; };
@ -111,9 +119,12 @@ struct archive_read_filter {
* so should be deferred at least until libarchive 3.0. * so should be deferred at least until libarchive 3.0.
*/ */
struct archive_read_client { struct archive_read_client {
archive_open_callback *opener;
archive_read_callback *reader; archive_read_callback *reader;
archive_skip_callback *skipper; archive_skip_callback *skipper;
archive_seek_callback *seeker;
archive_close_callback *closer; archive_close_callback *closer;
void *data;
}; };
struct archive_read { struct archive_read {
@ -122,6 +133,7 @@ struct archive_read {
struct archive_entry *entry; struct archive_entry *entry;
/* Dev/ino of the archive being read/written. */ /* Dev/ino of the archive being read/written. */
int skip_file_set;
dev_t skip_file_dev; dev_t skip_file_dev;
ino_t skip_file_ino; ino_t skip_file_ino;
@ -130,21 +142,21 @@ struct archive_read {
* data to client buffers, filling gaps with zero bytes. * data to client buffers, filling gaps with zero bytes.
*/ */
const char *read_data_block; const char *read_data_block;
off_t read_data_offset; int64_t read_data_offset;
off_t read_data_output_offset; int64_t read_data_output_offset;
size_t read_data_remaining; size_t read_data_remaining;
/* Callbacks to open/read/write/close client archive stream. */ /* Callbacks to open/read/write/close client archive stream. */
struct archive_read_client client; struct archive_read_client client;
/* Registered filter bidders. */ /* Registered filter bidders. */
struct archive_read_filter_bidder bidders[8]; struct archive_read_filter_bidder bidders[9];
/* Last filter in chain */ /* Last filter in chain */
struct archive_read_filter *filter; struct archive_read_filter *filter;
/* File offset of beginning of most recently-read header. */ /* File offset of beginning of most recently-read header. */
off_t header_position; int64_t header_position;
/* /*
* Format detection is mostly the same as compression * Format detection is mostly the same as compression
@ -157,14 +169,14 @@ struct archive_read {
struct archive_format_descriptor { struct archive_format_descriptor {
void *data; void *data;
const char *name; const char *name;
int (*bid)(struct archive_read *); int (*bid)(struct archive_read *, int best_bid);
int (*options)(struct archive_read *, const char *key, int (*options)(struct archive_read *, const char *key,
const char *value); const char *value);
int (*read_header)(struct archive_read *, struct archive_entry *); int (*read_header)(struct archive_read *, struct archive_entry *);
int (*read_data)(struct archive_read *, const void **, size_t *, off_t *); int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *);
int (*read_data_skip)(struct archive_read *); int (*read_data_skip)(struct archive_read *);
int (*cleanup)(struct archive_read *); int (*cleanup)(struct archive_read *);
} formats[9]; } formats[16];
struct archive_format_descriptor *format; /* Active format. */ struct archive_format_descriptor *format; /* Active format. */
/* /*
@ -177,23 +189,22 @@ struct archive_read {
int __archive_read_register_format(struct archive_read *a, int __archive_read_register_format(struct archive_read *a,
void *format_data, void *format_data,
const char *name, const char *name,
int (*bid)(struct archive_read *), int (*bid)(struct archive_read *, int),
int (*options)(struct archive_read *, const char *, const char *), int (*options)(struct archive_read *, const char *, const char *),
int (*read_header)(struct archive_read *, struct archive_entry *), int (*read_header)(struct archive_read *, struct archive_entry *),
int (*read_data)(struct archive_read *, const void **, size_t *, off_t *), int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
int (*read_data_skip)(struct archive_read *), int (*read_data_skip)(struct archive_read *),
int (*cleanup)(struct archive_read *)); int (*cleanup)(struct archive_read *));
struct archive_read_filter_bidder int __archive_read_get_bidder(struct archive_read *a,
*__archive_read_get_bidder(struct archive_read *a); struct archive_read_filter_bidder **bidder);
const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *); const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *);
const void *__archive_read_filter_ahead(struct archive_read_filter *, const void *__archive_read_filter_ahead(struct archive_read_filter *,
size_t, ssize_t *); size_t, ssize_t *);
ssize_t __archive_read_consume(struct archive_read *, size_t); int64_t __archive_read_seek(struct archive_read*, int64_t, int);
ssize_t __archive_read_filter_consume(struct archive_read_filter *, size_t); int64_t __archive_read_filter_seek(struct archive_read_filter *, int64_t, int);
int64_t __archive_read_skip(struct archive_read *, int64_t); int64_t __archive_read_consume(struct archive_read *, int64_t);
int64_t __archive_read_skip_lenient(struct archive_read *, int64_t); int64_t __archive_read_filter_consume(struct archive_read_filter *, int64_t);
int64_t __archive_read_filter_skip(struct archive_read_filter *, int64_t);
int __archive_read_program(struct archive_read_filter *, const char *); int __archive_read_program(struct archive_read_filter *, const char *);
#endif #endif

View File

@ -0,0 +1,207 @@
.\" Copyright (c) 2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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$
.\"
.Dd April 13, 2009
.Dt ARCHIVE_READ_OPTIONS 3
.Os
.Sh NAME
.Nm archive_read_set_filter_option ,
.Nm archive_read_set_format_option ,
.Nm archive_read_set_option ,
.Nm archive_read_set_options
.Nd functions controlling options for reading archives
.\"
.Sh SYNOPSIS
.Ft int
.Fo archive_read_set_filter_option
.Fa "struct archive *"
.Fa "const char *module"
.Fa "const char *option"
.Fa "const char *value"
.Fc
.Ft int
.Fo archive_read_set_format_option
.Fa "struct archive *"
.Fa "const char *module"
.Fa "const char *option"
.Fa "const char *value"
.Fc
.Ft int
.Fo archive_read_set_option
.Fa "struct archive *"
.Fa "const char *module"
.Fa "const char *option"
.Fa "const char *value"
.Fc
.Ft int
.Fo archive_read_set_options
.Fa "struct archive *"
.Fa "const char *options"
.Fc
.Sh DESCRIPTION
These functions provide a way for libarchive clients to configure
specific read modules.
.Bl -tag -width indent
.It Xo
.Fn archive_read_set_filter_option ,
.Fn archive_read_set_format_option
.Xc
Specifies an option that will be passed to currently-registered
filters (including decompression filters) or format readers.
.Pp
If
.Ar option
and
.Ar value
are both
.Dv NULL ,
these functions will do nothing and
.Cm ARCHIVE_OK
will be returned.
If
.Ar option
is
.Dv NULL
but
.Ar value
is not, these functions will do nothing and
.Cm ARCHIVE_FAILED
will be returned.
.Pp
If
.Ar module
is not
.Dv NULL ,
.Ar option
and
.Ar value
will be provided to the filter or reader named
.Ar module .
The return value will be that of the module.
If there is no such module,
.Cm ARCHIVE_FAILED
will be returned.
.Pp
If
.Ar module
is
.Dv NULL ,
.Ar option
and
.Ar value
will be provided to every registered module.
If any module returns
.Cm ARCHIVE_FATAL ,
this value will be returned immediately.
Otherwise,
.Cm ARCHIVE_OK
will be returned if any module accepts the option, and
.Cm ARCHIVE_FAILED
in all other cases.
.\"
.It Xo
.Fn archive_read_set_option
.Xc
Calls
.Fn archive_read_set_format_option ,
then
.Fn archive_read_set_filter_option .
If either function returns
.Cm ARCHIVE_FATAL ,
.Cm ARCHIVE_FATAL
will be returned
immediately.
Otherwise, greater of the two values will be returned.
.\"
.It Xo
.Fn archive_read_set_options
.Xc
.Ar options
is a comma-separated list of options.
If
.Ar options
is
.Dv NULL
or empty,
.Cm ARCHIVE_OK
will be returned immediately.
.Pp
Calls
.Fn archive_read_set_option
with each option in turn.
If any
.Fn archive_read_set_option
call returns
.Cm ARCHIVE_FATAL ,
.Cm ARCHIVE_FATAL
will be returned immediately.
.Pp
Individual options have one of the following forms:
.Bl -tag -compact -width indent
.It Ar option=value
The option/value pair will be provided to every module.
Modules that do not accept an option with this name will ignore it.
.It Ar option
The option will be provided to every module with a value of
.Dq 1 .
.It Ar !option
The option will be provided to every module with a NULL value.
.It Ar module:option=value , Ar module:option , Ar module:!option
As above, but the corresponding option and value will be provided
only to modules whose name matches
.Ar module .
.El
.El
.\"
.Sh OPTIONS
.Bl -tag -compact -width indent
.It Format iso9660
.Bl -tag -compact -width indent
.It Cm joliet
Support Joliet extensions.
Defaults to enabled, use
.Cm !joliet
to disable.
.It Cm rockridge
Support RockRidge extensions.
Defaults to enabled, use
.Cm !rockridge
to disable.
.El
.El
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
functions.
.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_write_set_options 3 ,
.Xr archive_read 3

View File

@ -0,0 +1,156 @@
/*-
* Copyright (c) 2011 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 "archive_platform.h"
__FBSDID("$FreeBSD$");
#include "archive_read_private.h"
#include "archive_options_private.h"
static int archive_set_format_option(struct archive *a,
const char *m, const char *o, const char *v);
static int archive_set_filter_option(struct archive *a,
const char *m, const char *o, const char *v);
static int archive_set_option(struct archive *a,
const char *m, const char *o, const char *v);
int
archive_read_set_format_option(struct archive *a, const char *m, const char *o,
const char *v)
{
return _archive_set_option(a, m, o, v,
ARCHIVE_READ_MAGIC, "archive_read_set_format_option",
archive_set_format_option);
}
int
archive_read_set_filter_option(struct archive *a, const char *m, const char *o,
const char *v)
{
return _archive_set_option(a, m, o, v,
ARCHIVE_READ_MAGIC, "archive_read_set_filter_option",
archive_set_filter_option);
}
int
archive_read_set_option(struct archive *a, const char *m, const char *o,
const char *v)
{
return _archive_set_option(a, m, o, v,
ARCHIVE_READ_MAGIC, "archive_read_set_option",
archive_set_option);
}
int
archive_read_set_options(struct archive *a, const char *options)
{
return _archive_set_options(a, options,
ARCHIVE_READ_MAGIC, "archive_read_set_options",
archive_set_option);
}
static int
archive_set_format_option(struct archive *_a, const char *m, const char *o,
const char *v)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_format_descriptor *format;
size_t i;
int r, rv = ARCHIVE_WARN;
for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {
format = &a->formats[i];
if (format == NULL || format->options == NULL ||
format->name == NULL)
/* This format does not support option. */
continue;
if (m != NULL && strcmp(format->name, m) != 0)
continue;
a->format = format;
r = format->options(a, o, v);
a->format = NULL;
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
if (m != NULL)
return (r);
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
/* If the format name didn't match, return a special code for
* _archive_set_option[s]. */
if (rv == ARCHIVE_WARN && m != NULL)
rv = ARCHIVE_WARN - 1;
return (rv);
}
static int
archive_set_filter_option(struct archive *_a, const char *m, const char *o,
const char *v)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter;
struct archive_read_filter_bidder *bidder;
int r, rv = ARCHIVE_WARN;
for (filter = a->filter; filter != NULL; filter = filter->upstream) {
bidder = filter->bidder;
if (bidder == NULL)
continue;
if (bidder->options == NULL)
/* This bidder does not support option */
continue;
if (m != NULL && strcmp(filter->name, m) != 0)
continue;
r = bidder->options(bidder, o, v);
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
if (m != NULL)
return (r);
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
/* If the filter name didn't match, return a special code for
* _archive_set_option[s]. */
if (rv == ARCHIVE_WARN && m != NULL)
rv = ARCHIVE_WARN - 1;
return (rv);
}
static int
archive_set_option(struct archive *a, const char *m, const char *o,
const char *v)
{
return _archive_set_either_option(a, m, o, v,
archive_set_format_option,
archive_set_filter_option);
}

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2003-2011 Tim Kientzle
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -27,27 +27,42 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include "archive.h" #include "archive.h"
#include "archive_private.h"
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int int
archive_read_support_compression_all(struct archive *a) archive_read_support_compression_all(struct archive *a)
{ {
return archive_read_support_filter_all(a);
}
#endif
int
archive_read_support_filter_all(struct archive *a)
{
archive_check_magic(a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_all");
/* Bzip falls back to "bunzip2" command-line */ /* Bzip falls back to "bunzip2" command-line */
archive_read_support_compression_bzip2(a); archive_read_support_filter_bzip2(a);
/* The decompress code doesn't use an outside library. */ /* The decompress code doesn't use an outside library. */
archive_read_support_compression_compress(a); archive_read_support_filter_compress(a);
/* Gzip decompress falls back to "gunzip" command-line. */ /* Gzip decompress falls back to "gunzip" command-line. */
archive_read_support_compression_gzip(a); archive_read_support_filter_gzip(a);
/* Lzip falls back to "unlzip" command-line program. */
archive_read_support_filter_lzip(a);
/* The LZMA file format has a very weak signature, so it /* The LZMA file format has a very weak signature, so it
* may not be feasible to keep this here, but we'll try. * may not be feasible to keep this here, but we'll try.
* This will come back out if there are problems. */ * This will come back out if there are problems. */
/* Lzma falls back to "unlzma" command-line program. */ /* Lzma falls back to "unlzma" command-line program. */
archive_read_support_compression_lzma(a); archive_read_support_filter_lzma(a);
/* Xz falls back to "unxz" command-line program. */ /* Xz falls back to "unxz" command-line program. */
archive_read_support_compression_xz(a); archive_read_support_filter_xz(a);
/* The decode code doesn't use an outside library. */ /* The decode code doesn't use an outside library. */
archive_read_support_compression_uu(a); archive_read_support_filter_uu(a);
/* The decode code doesn't use an outside library. */ /* The decode code doesn't use an outside library. */
archive_read_support_compression_rpm(a); archive_read_support_filter_rpm(a);
/* Note: We always return ARCHIVE_OK here, even if some of the /* Note: We always return ARCHIVE_OK here, even if some of the
* above return ARCHIVE_WARN. The intent here is to enable * above return ARCHIVE_WARN. The intent here is to enable

View File

@ -72,13 +72,25 @@ static int bzip2_reader_bid(struct archive_read_filter_bidder *, struct archive_
static int bzip2_reader_init(struct archive_read_filter *); static int bzip2_reader_init(struct archive_read_filter *);
static int bzip2_reader_free(struct archive_read_filter_bidder *); static int bzip2_reader_free(struct archive_read_filter_bidder *);
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int int
archive_read_support_compression_bzip2(struct archive *_a) archive_read_support_compression_bzip2(struct archive *a)
{
return archive_read_support_filter_bzip2(a);
}
#endif
int
archive_read_support_filter_bzip2(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *reader = __archive_read_get_bidder(a); struct archive_read_filter_bidder *reader;
if (reader == NULL) archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_bzip2");
if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
reader->data = NULL; reader->data = NULL;
@ -124,7 +136,7 @@ bzip2_reader_bid(struct archive_read_filter_bidder *self, struct archive_read_fi
/* First three bytes must be "BZh" */ /* First three bytes must be "BZh" */
bits_checked = 0; bits_checked = 0;
if (buffer[0] != 'B' || buffer[1] != 'Z' || buffer[2] != 'h') if (memcmp(buffer, "BZh", 3) != 0)
return (0); return (0);
bits_checked += 24; bits_checked += 24;
@ -185,7 +197,7 @@ bzip2_reader_init(struct archive_read_filter *self)
state = (struct private_data *)calloc(sizeof(*state), 1); state = (struct private_data *)calloc(sizeof(*state), 1);
out_block = (unsigned char *)malloc(out_block_size); out_block = (unsigned char *)malloc(out_block_size);
if (self == NULL || state == NULL || out_block == NULL) { if (state == NULL || out_block == NULL) {
archive_set_error(&self->archive->archive, ENOMEM, archive_set_error(&self->archive->archive, ENOMEM,
"Can't allocate data for bzip2 decompression"); "Can't allocate data for bzip2 decompression");
free(out_block); free(out_block);
@ -274,8 +286,12 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
* doesn't declare it so. <sigh> */ * doesn't declare it so. <sigh> */
read_buf = read_buf =
__archive_read_filter_ahead(self->upstream, 1, &ret); __archive_read_filter_ahead(self->upstream, 1, &ret);
if (read_buf == NULL) if (read_buf == NULL) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated bzip2 input");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
}
state->stream.next_in = (char *)(uintptr_t)read_buf; state->stream.next_in = (char *)(uintptr_t)read_buf;
state->stream.avail_in = ret; state->stream.avail_in = ret;
/* There is no more data, return whatever we have. */ /* There is no more data, return whatever we have. */
@ -343,6 +359,7 @@ bzip2_filter_close(struct archive_read_filter *self)
"Failed to clean up decompressor"); "Failed to clean up decompressor");
ret = ARCHIVE_FATAL; ret = ARCHIVE_FATAL;
} }
state->valid = 0;
} }
free(state->out_block); free(state->out_block);

View File

@ -95,6 +95,7 @@ struct private_data {
/* Input variables. */ /* Input variables. */
const unsigned char *next_in; const unsigned char *next_in;
size_t avail_in; size_t avail_in;
size_t consume_unnotified;
int bit_buffer; int bit_buffer;
int bits_avail; int bits_avail;
size_t bytes_in_section; size_t bytes_in_section;
@ -140,13 +141,25 @@ static int compress_filter_close(struct archive_read_filter *);
static int getbits(struct archive_read_filter *, int n); static int getbits(struct archive_read_filter *, int n);
static int next_code(struct archive_read_filter *); static int next_code(struct archive_read_filter *);
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int int
archive_read_support_compression_compress(struct archive *_a) archive_read_support_compression_compress(struct archive *a)
{
return archive_read_support_filter_compress(a);
}
#endif
int
archive_read_support_filter_compress(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a); struct archive_read_filter_bidder *bidder;
if (bidder == NULL) archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_compress");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
bidder->data = NULL; bidder->data = NULL;
@ -159,10 +172,7 @@ archive_read_support_compression_compress(struct archive *_a)
/* /*
* Test whether we can handle this data. * Test whether we can handle this data.
* * This logic returns zero if any part of the signature fails.
* This logic returns zero if any part of the signature fails. It
* also tries to Do The Right Thing if a very short buffer prevents us
* from verifying as much as we would like.
*/ */
static int static int
compress_bidder_bid(struct archive_read_filter_bidder *self, compress_bidder_bid(struct archive_read_filter_bidder *self,
@ -180,13 +190,9 @@ compress_bidder_bid(struct archive_read_filter_bidder *self,
return (0); return (0);
bits_checked = 0; bits_checked = 0;
if (buffer[0] != 037) /* Verify first ID byte. */ if (buffer[0] != 0x1F || buffer[1] != 0x9D)
return (0); return (0);
bits_checked += 8; bits_checked += 16;
if (buffer[1] != 0235) /* Verify second ID byte. */
return (0);
bits_checked += 8;
/* /*
* TODO: Verify more. * TODO: Verify more.
@ -420,6 +426,11 @@ getbits(struct archive_read_filter *self, int n)
while (state->bits_avail < n) { while (state->bits_avail < n) {
if (state->avail_in <= 0) { if (state->avail_in <= 0) {
if (state->consume_unnotified) {
__archive_read_filter_consume(self->upstream,
state->consume_unnotified);
state->consume_unnotified = 0;
}
state->next_in state->next_in
= __archive_read_filter_ahead(self->upstream, = __archive_read_filter_ahead(self->upstream,
1, &ret); 1, &ret);
@ -427,8 +438,7 @@ getbits(struct archive_read_filter *self, int n)
return (-1); return (-1);
if (ret < 0 || state->next_in == NULL) if (ret < 0 || state->next_in == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
state->avail_in = ret; state->consume_unnotified = state->avail_in = ret;
__archive_read_filter_consume(self->upstream, ret);
} }
state->bit_buffer |= *state->next_in++ << state->bits_avail; state->bit_buffer |= *state->next_in++ << state->bits_avail;
state->avail_in--; state->avail_in--;

View File

@ -78,13 +78,25 @@ static int gzip_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *); struct archive_read_filter *);
static int gzip_bidder_init(struct archive_read_filter *); static int gzip_bidder_init(struct archive_read_filter *);
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int int
archive_read_support_compression_gzip(struct archive *_a) archive_read_support_compression_gzip(struct archive *a)
{
return archive_read_support_filter_gzip(a);
}
#endif
int
archive_read_support_filter_gzip(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a); struct archive_read_filter_bidder *bidder;
if (bidder == NULL) archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_gzip");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
bidder->data = NULL; bidder->data = NULL;
@ -123,15 +135,10 @@ peek_at_header(struct archive_read_filter *filter, int *pbits)
p = __archive_read_filter_ahead(filter, len, &avail); p = __archive_read_filter_ahead(filter, len, &avail);
if (p == NULL || avail == 0) if (p == NULL || avail == 0)
return (0); return (0);
if (p[0] != 037) /* We only support deflation- third byte must be 0x08. */
if (memcmp(p, "\x1F\x8B\x08", 3) != 0)
return (0); return (0);
bits += 8; bits += 24;
if (p[1] != 0213)
return (0);
bits += 8;
if (p[2] != 8) /* We only support deflation. */
return (0);
bits += 8;
if ((p[3] & 0xE0)!= 0) /* No reserved flags set. */ if ((p[3] & 0xE0)!= 0) /* No reserved flags set. */
return (0); return (0);
bits += 3; bits += 3;
@ -394,8 +401,12 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
* it so, hence this ugly cast. */ * it so, hence this ugly cast. */
state->stream.next_in = (unsigned char *)(uintptr_t) state->stream.next_in = (unsigned char *)(uintptr_t)
__archive_read_filter_ahead(self->upstream, 1, &avail_in); __archive_read_filter_ahead(self->upstream, 1, &avail_in);
if (state->stream.next_in == NULL) if (state->stream.next_in == NULL) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated gzip input");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
}
state->stream.avail_in = avail_in; state->stream.avail_in = avail_in;
/* Decompress and consume some of that data. */ /* Decompress and consume some of that data. */

View File

@ -27,14 +27,26 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include "archive.h" #include "archive.h"
#include "archive_private.h"
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int
archive_read_support_compression_none(struct archive *a)
{
return archive_read_support_filter_none(a);
}
#endif
/* /*
* Uncompressed streams are handled implicitly by the read core, * Uncompressed streams are handled implicitly by the read core,
* so this is now a no-op. * so this is now a no-op.
*/ */
int int
archive_read_support_compression_none(struct archive *a) archive_read_support_filter_none(struct archive *a)
{ {
(void)a; /* UNUSED */ archive_check_magic(a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_none");
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }

View File

@ -55,10 +55,28 @@ __FBSDID("$FreeBSD$");
#include "archive_private.h" #include "archive_private.h"
#include "archive_read_private.h" #include "archive_read_private.h"
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int int
archive_read_support_compression_program(struct archive *a, const char *cmd) archive_read_support_compression_program(struct archive *a, const char *cmd)
{ {
return (archive_read_support_compression_program_signature(a, cmd, NULL, 0)); return archive_read_support_filter_program(a, cmd);
}
int
archive_read_support_compression_program_signature(struct archive *a,
const char *cmd, const void *signature, size_t signature_len)
{
return archive_read_support_filter_program_signature(a,
cmd, signature, signature_len);
}
#endif
int
archive_read_support_filter_program(struct archive *a, const char *cmd)
{
return (archive_read_support_filter_program_signature(a, cmd, NULL, 0));
} }
@ -71,8 +89,8 @@ archive_read_support_compression_program(struct archive *a, const char *cmd)
* this function is actually invoked. * this function is actually invoked.
*/ */
int int
archive_read_support_compression_program_signature(struct archive *_a, archive_read_support_filter_program_signature(struct archive *_a,
const char *cmd, void *signature, size_t signature_len) const char *cmd, const void *signature, size_t signature_len)
{ {
(void)_a; /* UNUSED */ (void)_a; /* UNUSED */
(void)cmd; /* UNUSED */ (void)cmd; /* UNUSED */
@ -135,7 +153,7 @@ static ssize_t program_filter_read(struct archive_read_filter *,
static int program_filter_close(struct archive_read_filter *); static int program_filter_close(struct archive_read_filter *);
int int
archive_read_support_compression_program_signature(struct archive *_a, archive_read_support_filter_program_signature(struct archive *_a,
const char *cmd, const void *signature, size_t signature_len) const char *cmd, const void *signature, size_t signature_len)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
@ -145,8 +163,7 @@ archive_read_support_compression_program_signature(struct archive *_a,
/* /*
* Get a bidder object from the read core. * Get a bidder object from the read core.
*/ */
bidder = __archive_read_get_bidder(a); if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
if (bidder == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
/* /*
@ -388,7 +405,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
free(state->out_buf); free(state->out_buf);
free(state); free(state);
archive_set_error(&self->archive->archive, EINVAL, archive_set_error(&self->archive->archive, EINVAL,
"Can't initialise filter"); "Can't initialize filter; unable to run program \"%s\"", cmd);
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }

View File

@ -63,15 +63,25 @@ static ssize_t rpm_filter_read(struct archive_read_filter *,
const void **); const void **);
static int rpm_filter_close(struct archive_read_filter *); static int rpm_filter_close(struct archive_read_filter *);
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int int
archive_read_support_compression_rpm(struct archive *_a) archive_read_support_compression_rpm(struct archive *a)
{
return archive_read_support_filter_rpm(a);
}
#endif
int
archive_read_support_filter_rpm(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder; struct archive_read_filter_bidder *bidder;
bidder = __archive_read_get_bidder(a); archive_check_magic(_a, ARCHIVE_READ_MAGIC,
archive_clear_error(_a); ARCHIVE_STATE_NEW, "archive_read_support_filter_rpm");
if (bidder == NULL)
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
bidder->data = NULL; bidder->data = NULL;
@ -98,20 +108,11 @@ rpm_bidder_bid(struct archive_read_filter_bidder *self,
bits_checked = 0; bits_checked = 0;
/* /*
* Verify Header Magic Bytes : 0xed 0xab 0xee 0xdb * Verify Header Magic Bytes : 0XED 0XAB 0XEE 0XDB
*/ */
if (b[0] != 0xed) if (memcmp(b, "\xED\xAB\xEE\xDB", 4) != 0)
return (0); return (0);
bits_checked += 8; bits_checked += 32;
if (b[1] != 0xab)
return (0);
bits_checked += 8;
if (b[2] != 0xee)
return (0);
bits_checked += 8;
if (b[3] != 0xdb)
return (0);
bits_checked += 8;
/* /*
* Check major version. * Check major version.
*/ */

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009 Michihiro NAKAJIMA * Copyright (c) 2009-2011 Michihiro NAKAJIMA
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -40,6 +40,9 @@ __FBSDID("$FreeBSD$");
#include "archive_private.h" #include "archive_private.h"
#include "archive_read_private.h" #include "archive_read_private.h"
/* Maximum lookahead during bid phase */
#define UUENCODE_BID_MAX_READ 128*1024 /* in bytes */
struct uudecode { struct uudecode {
int64_t total; int64_t total;
unsigned char *in_buff; unsigned char *in_buff;
@ -63,15 +66,25 @@ static ssize_t uudecode_filter_read(struct archive_read_filter *,
const void **); const void **);
static int uudecode_filter_close(struct archive_read_filter *); static int uudecode_filter_close(struct archive_read_filter *);
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int int
archive_read_support_compression_uu(struct archive *_a) archive_read_support_compression_uu(struct archive *a)
{
return archive_read_support_filter_uu(a);
}
#endif
int
archive_read_support_filter_uu(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder; struct archive_read_filter_bidder *bidder;
bidder = __archive_read_get_bidder(a); archive_check_magic(_a, ARCHIVE_READ_MAGIC,
archive_clear_error(_a); ARCHIVE_STATE_NEW, "archive_read_support_filter_uu");
if (bidder == NULL)
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
bidder->data = NULL; bidder->data = NULL;
@ -194,7 +207,8 @@ get_line(const unsigned char *b, ssize_t avail, ssize_t *nlsize)
static ssize_t static ssize_t
bid_get_line(struct archive_read_filter *filter, bid_get_line(struct archive_read_filter *filter,
const unsigned char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl) const unsigned char **b, ssize_t *avail, ssize_t *ravail,
ssize_t *nl, size_t* nbytes_read)
{ {
ssize_t len; ssize_t len;
int quit; int quit;
@ -205,24 +219,37 @@ bid_get_line(struct archive_read_filter *filter,
len = 0; len = 0;
} else } else
len = get_line(*b, *avail, nl); len = get_line(*b, *avail, nl);
/* /*
* Read bytes more while it does not reach the end of line. * Read bytes more while it does not reach the end of line.
*/ */
while (*nl == 0 && len == *avail && !quit) { while (*nl == 0 && len == *avail && !quit &&
*nbytes_read < UUENCODE_BID_MAX_READ) {
ssize_t diff = *ravail - *avail; ssize_t diff = *ravail - *avail;
size_t nbytes_req = (*ravail+1023) & ~1023U;
ssize_t tested;
*b = __archive_read_filter_ahead(filter, 160 + *ravail, avail); /* Increase reading bytes if it is not enough to at least
* new two lines. */
if (nbytes_req < (size_t)*ravail + 160)
nbytes_req <<= 1;
*b = __archive_read_filter_ahead(filter, nbytes_req, avail);
if (*b == NULL) { if (*b == NULL) {
if (*ravail >= *avail) if (*ravail >= *avail)
return (0); return (0);
/* Reading bytes reaches the end of file. */ /* Reading bytes reaches the end of a stream. */
*b = __archive_read_filter_ahead(filter, *avail, avail); *b = __archive_read_filter_ahead(filter, *avail, avail);
quit = 1; quit = 1;
} }
*nbytes_read = *avail;
*ravail = *avail; *ravail = *avail;
*b += diff; *b += diff;
*avail -= diff; *avail -= diff;
len = get_line(*b, *avail, nl); tested = len;/* Skip some bytes we already determinated. */
len = get_line(*b + tested, *avail - tested, nl);
if (len >= 0)
len += tested;
} }
return (len); return (len);
} }
@ -238,6 +265,7 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
ssize_t len, nl; ssize_t len, nl;
int l; int l;
int firstline; int firstline;
size_t nbytes_read;
(void)self; /* UNUSED */ (void)self; /* UNUSED */
@ -247,13 +275,14 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
firstline = 20; firstline = 20;
ravail = avail; ravail = avail;
nbytes_read = avail;
for (;;) { for (;;) {
len = bid_get_line(filter, &b, &avail, &ravail, &nl); len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
if (len < 0 || nl == 0) if (len < 0 || nl == 0)
return (0);/* Binary data. */ return (0); /* No match found. */
if (memcmp(b, "begin ", 6) == 0 && len - nl >= 11) if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
l = 6; l = 6;
else if (memcmp(b, "begin-base64 ", 13) == 0 && len - nl >= 18) else if (len -nl >= 18 && memcmp(b, "begin-base64 ", 13) == 0)
l = 13; l = 13;
else else
l = 0; l = 0;
@ -268,10 +297,14 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
if (l) if (l)
break; break;
firstline = 0; firstline = 0;
/* Do not read more than UUENCODE_BID_MAX_READ bytes */
if (nbytes_read >= UUENCODE_BID_MAX_READ)
return (0);
} }
if (!avail) if (!avail)
return (0); return (0);
len = bid_get_line(filter, &b, &avail, &ravail, &nl); len = bid_get_line(filter, &b, &avail, &ravail, &nl, &nbytes_read);
if (len < 0 || nl == 0) if (len < 0 || nl == 0)
return (0);/* There are non-ascii characters. */ return (0);/* There are non-ascii characters. */
avail -= len; avail -= len;
@ -392,18 +425,19 @@ ensure_in_buff_size(struct archive_read_filter *self,
else else
newsize += IN_BUFF_SIZE; newsize += IN_BUFF_SIZE;
} while (size > newsize); } while (size > newsize);
/* Allocate the new buffer. */
ptr = malloc(newsize); ptr = malloc(newsize);
if (ptr == NULL || if (ptr == NULL) {
newsize < uudecode->in_allocated) {
free(ptr); free(ptr);
archive_set_error(&self->archive->archive, archive_set_error(&self->archive->archive,
ENOMEM, ENOMEM,
"Can't allocate data for uudecode"); "Can't allocate data for uudecode");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
/* Move the remaining data in in_buff into the new buffer. */
if (uudecode->in_cnt) if (uudecode->in_cnt)
memmove(ptr, uudecode->in_buff, memmove(ptr, uudecode->in_buff, uudecode->in_cnt);
uudecode->in_cnt); /* Replace in_buff with the new buffer. */
free(uudecode->in_buff); free(uudecode->in_buff);
uudecode->in_buff = ptr; uudecode->in_buff = ptr;
uudecode->in_allocated = newsize; uudecode->in_allocated = newsize;
@ -483,11 +517,16 @@ uudecode_filter_read(struct archive_read_filter *self, const void **buff)
} }
break; break;
} }
if (total + len * 2 > OUT_BUFF_SIZE)
break;
switch (uudecode->state) { switch (uudecode->state) {
default: default:
case ST_FIND_HEAD: case ST_FIND_HEAD:
/* Do not read more than UUENCODE_BID_MAX_READ bytes */
if (total + len >= UUENCODE_BID_MAX_READ) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid format data");
return (ARCHIVE_FATAL);
}
if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0) if (len - nl >= 11 && memcmp(b, "begin ", 6) == 0)
l = 6; l = 6;
else if (len - nl >= 18 && else if (len - nl >= 18 &&
@ -505,6 +544,8 @@ uudecode_filter_read(struct archive_read_filter *self, const void **buff)
} }
break; break;
case ST_READ_UU: case ST_READ_UU:
if (total + len * 2 > OUT_BUFF_SIZE)
break;
body = len - nl; body = len - nl;
if (!uuchar[*b] || body <= 0) { if (!uuchar[*b] || body <= 0) {
archive_set_error(&self->archive->archive, archive_set_error(&self->archive->archive,
@ -569,6 +610,8 @@ uudecode_filter_read(struct archive_read_filter *self, const void **buff)
} }
break; break;
case ST_READ_BASE64: case ST_READ_BASE64:
if (total + len * 2 > OUT_BUFF_SIZE)
break;
l = len - nl; l = len - nl;
if (l >= 3 && b[0] == '=' && b[1] == '=' && if (l >= 3 && b[0] == '=' && b[1] == '=' &&
b[2] == '=') { b[2] == '=') {

View File

@ -1,5 +1,5 @@
/*- /*-
* Copyright (c) 2009 Michihiro NAKAJIMA * Copyright (c) 2009-2011 Michihiro NAKAJIMA
* Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna * Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna
* All rights reserved. * All rights reserved.
* *
@ -60,9 +60,24 @@ struct private_data {
size_t out_block_size; size_t out_block_size;
int64_t total_out; int64_t total_out;
char eof; /* True = found end of compressed data. */ char eof; /* True = found end of compressed data. */
char in_stream;
/* Following variables are used for lzip only. */
char lzip_ver;
uint32_t crc32;
int64_t member_in;
int64_t member_out;
}; };
/* Combined lzma/xz filter */ #if LZMA_VERSION_MAJOR >= 5
/* Effectively disable the limiter. */
#define LZMA_MEMLIMIT UINT64_MAX
#else
/* NOTE: This needs to check memory size which running system has. */
#define LZMA_MEMLIMIT (1U << 30)
#endif
/* Combined lzip/lzma/xz filter */
static ssize_t xz_filter_read(struct archive_read_filter *, const void **); static ssize_t xz_filter_read(struct archive_read_filter *, const void **);
static int xz_filter_close(struct archive_read_filter *); static int xz_filter_close(struct archive_read_filter *);
static int xz_lzma_bidder_init(struct archive_read_filter *); static int xz_lzma_bidder_init(struct archive_read_filter *);
@ -94,15 +109,30 @@ static int xz_bidder_init(struct archive_read_filter *);
static int lzma_bidder_bid(struct archive_read_filter_bidder *, static int lzma_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *); struct archive_read_filter *);
static int lzma_bidder_init(struct archive_read_filter *); static int lzma_bidder_init(struct archive_read_filter *);
static int lzip_has_member(struct archive_read_filter *);
static int lzip_bidder_bid(struct archive_read_filter_bidder *,
struct archive_read_filter *);
static int lzip_bidder_init(struct archive_read_filter *);
#if ARCHIVE_VERSION_NUMBER < 4000000
/* Deprecated; remove in libarchive 4.0 */
int
archive_read_support_compression_xz(struct archive *a)
{
return archive_read_support_filter_xz(a);
}
#endif
int int
archive_read_support_compression_xz(struct archive *_a) archive_read_support_filter_xz(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a); struct archive_read_filter_bidder *bidder;
archive_clear_error(_a); archive_check_magic(_a, ARCHIVE_READ_MAGIC,
if (bidder == NULL) ARCHIVE_STATE_NEW, "archive_read_support_filter_xz");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
bidder->data = NULL; bidder->data = NULL;
@ -119,14 +149,24 @@ archive_read_support_compression_xz(struct archive *_a)
#endif #endif
} }
#if ARCHIVE_VERSION_NUMBER < 4000000
int int
archive_read_support_compression_lzma(struct archive *_a) archive_read_support_compression_lzma(struct archive *a)
{
return archive_read_support_filter_lzma(a);
}
#endif
int
archive_read_support_filter_lzma(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a); struct archive_read_filter_bidder *bidder;
archive_clear_error(_a); archive_check_magic(_a, ARCHIVE_READ_MAGIC,
if (bidder == NULL) ARCHIVE_STATE_NEW, "archive_read_support_filter_lzma");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
bidder->data = NULL; bidder->data = NULL;
@ -145,6 +185,41 @@ archive_read_support_compression_lzma(struct archive *_a)
#endif #endif
} }
#if ARCHIVE_VERSION_NUMBER < 4000000
int
archive_read_support_compression_lzip(struct archive *a)
{
return archive_read_support_filter_lzip(a);
}
#endif
int
archive_read_support_filter_lzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter_bidder *bidder;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_filter_lzip");
if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
bidder->data = NULL;
bidder->bid = lzip_bidder_bid;
bidder->init = lzip_bidder_init;
bidder->options = NULL;
bidder->free = NULL;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return (ARCHIVE_OK);
#else
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external lzip program for lzip decompression");
return (ARCHIVE_WARN);
#endif
}
/* /*
* Test whether we can handle this data. * Test whether we can handle this data.
*/ */
@ -154,7 +229,6 @@ xz_bidder_bid(struct archive_read_filter_bidder *self,
{ {
const unsigned char *buffer; const unsigned char *buffer;
ssize_t avail; ssize_t avail;
int bits_checked;
(void)self; /* UNUSED */ (void)self; /* UNUSED */
@ -165,27 +239,10 @@ xz_bidder_bid(struct archive_read_filter_bidder *self,
/* /*
* Verify Header Magic Bytes : FD 37 7A 58 5A 00 * Verify Header Magic Bytes : FD 37 7A 58 5A 00
*/ */
bits_checked = 0; if (memcmp(buffer, "\xFD\x37\x7A\x58\x5A\x00", 6) != 0)
if (buffer[0] != 0xFD)
return (0); return (0);
bits_checked += 8;
if (buffer[1] != 0x37)
return (0);
bits_checked += 8;
if (buffer[2] != 0x7A)
return (0);
bits_checked += 8;
if (buffer[3] != 0x58)
return (0);
bits_checked += 8;
if (buffer[4] != 0x5A)
return (0);
bits_checked += 8;
if (buffer[5] != 0x00)
return (0);
bits_checked += 8;
return (bits_checked); return (48);
} }
/* /*
@ -307,6 +364,49 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self,
return (bits_checked); return (bits_checked);
} }
static int
lzip_has_member(struct archive_read_filter *filter)
{
const unsigned char *buffer;
ssize_t avail;
int bits_checked;
int log2dic;
buffer = __archive_read_filter_ahead(filter, 6, &avail);
if (buffer == NULL)
return (0);
/*
* Verify Header Magic Bytes : 4C 5A 49 50 (`LZIP')
*/
bits_checked = 0;
if (memcmp(buffer, "LZIP", 4) != 0)
return (0);
bits_checked += 32;
/* A version number must be 0 or 1 */
if (buffer[4] != 0 && buffer[4] != 1)
return (0);
bits_checked += 8;
/* Dictionary size. */
log2dic = buffer[5] & 0x1f;
if (log2dic < 12 || log2dic > 27)
return (0);
bits_checked += 8;
return (bits_checked);
}
static int
lzip_bidder_bid(struct archive_read_filter_bidder *self,
struct archive_read_filter *filter)
{
(void)self; /* UNUSED */
return (lzip_has_member(filter));
}
#if HAVE_LZMA_H && HAVE_LIBLZMA #if HAVE_LZMA_H && HAVE_LIBLZMA
/* /*
@ -328,6 +428,62 @@ lzma_bidder_init(struct archive_read_filter *self)
return (xz_lzma_bidder_init(self)); return (xz_lzma_bidder_init(self));
} }
static int
lzip_bidder_init(struct archive_read_filter *self)
{
self->code = ARCHIVE_COMPRESSION_LZIP;
self->name = "lzip";
return (xz_lzma_bidder_init(self));
}
/*
* Set an error code and choose an error message
*/
static void
set_error(struct archive_read_filter *self, int ret)
{
switch (ret) {
case LZMA_STREAM_END: /* Found end of stream. */
case LZMA_OK: /* Decompressor made some progress. */
break;
case LZMA_MEM_ERROR:
archive_set_error(&self->archive->archive, ENOMEM,
"Lzma library error: Cannot allocate memory");
break;
case LZMA_MEMLIMIT_ERROR:
archive_set_error(&self->archive->archive, ENOMEM,
"Lzma library error: Out of memory");
break;
case LZMA_FORMAT_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: format not recognized");
break;
case LZMA_OPTIONS_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: Invalid options");
break;
case LZMA_DATA_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: Corrupted input data");
break;
case LZMA_BUF_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: No progress is possible");
break;
default:
/* Return an error. */
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma decompression failed: Unknown error");
break;
}
}
/* /*
* Setup the callbacks. * Setup the callbacks.
*/ */
@ -361,40 +517,32 @@ xz_lzma_bidder_init(struct archive_read_filter *self)
state->stream.next_out = state->out_block; state->stream.next_out = state->out_block;
state->stream.avail_out = state->out_block_size; state->stream.avail_out = state->out_block_size;
/* Initialize compression library. state->crc32 = 0;
* TODO: I don't know what value is best for memlimit. if (self->code == ARCHIVE_COMPRESSION_LZIP) {
* maybe, it needs to check memory size which /*
* running system has. * We have to read a lzip header and use it to initialize
*/ * compression library, thus we cannot initialize the
* library for lzip here.
*/
state->in_stream = 0;
return (ARCHIVE_OK);
} else
state->in_stream = 1;
/* Initialize compression library. */
if (self->code == ARCHIVE_COMPRESSION_XZ) if (self->code == ARCHIVE_COMPRESSION_XZ)
ret = lzma_stream_decoder(&(state->stream), ret = lzma_stream_decoder(&(state->stream),
(1U << 30),/* memlimit */ LZMA_MEMLIMIT,/* memlimit */
LZMA_CONCATENATED); LZMA_CONCATENATED);
else else
ret = lzma_alone_decoder(&(state->stream), ret = lzma_alone_decoder(&(state->stream),
(1U << 30));/* memlimit */ LZMA_MEMLIMIT);/* memlimit */
if (ret == LZMA_OK) if (ret == LZMA_OK)
return (ARCHIVE_OK); return (ARCHIVE_OK);
/* Library setup failed: Choose an error message and clean up. */ /* Library setup failed: Choose an error message and clean up. */
switch (ret) { set_error(self, ret);
case LZMA_MEM_ERROR:
archive_set_error(&self->archive->archive, ENOMEM,
"Internal error initializing compression library: "
"Cannot allocate memory");
break;
case LZMA_OPTIONS_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"Invalid or unsupported options");
break;
default:
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing lzma library");
break;
}
free(state->out_block); free(state->out_block);
free(state); free(state);
@ -402,6 +550,122 @@ xz_lzma_bidder_init(struct archive_read_filter *self)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
static int
lzip_init(struct archive_read_filter *self)
{
struct private_data *state;
const unsigned char *h;
lzma_filter filters[2];
unsigned char props[5];
ssize_t avail_in;
uint32_t dicsize;
int log2dic, ret;
state = (struct private_data *)self->data;
h = __archive_read_filter_ahead(self->upstream, 6, &avail_in);
if (h == NULL)
return (ARCHIVE_FATAL);
/* Get a version number. */
state->lzip_ver = h[4];
/*
* Setup lzma property.
*/
props[0] = 0x5d;
/* Get dictionary size. */
log2dic = h[5] & 0x1f;
if (log2dic < 12 || log2dic > 27)
return (ARCHIVE_FATAL);
dicsize = 1U << log2dic;
if (log2dic > 12)
dicsize -= (dicsize / 16) * (h[5] >> 5);
archive_le32enc(props+1, dicsize);
/* Consume lzip header. */
__archive_read_filter_consume(self->upstream, 6);
state->member_in = 6;
filters[0].id = LZMA_FILTER_LZMA1;
filters[0].options = NULL;
filters[1].id = LZMA_VLI_UNKNOWN;
filters[1].options = NULL;
ret = lzma_properties_decode(&filters[0], NULL, props, sizeof(props));
if (ret != LZMA_OK) {
set_error(self, ret);
return (ARCHIVE_FATAL);
}
ret = lzma_raw_decoder(&(state->stream), filters);
#if LZMA_VERSION < 50000030
free(filters[0].options);
#endif
if (ret != LZMA_OK) {
set_error(self, ret);
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
}
static int
lzip_tail(struct archive_read_filter *self)
{
struct private_data *state;
const unsigned char *f;
ssize_t avail_in;
int tail;
state = (struct private_data *)self->data;
if (state->lzip_ver == 0)
tail = 12;
else
tail = 20;
f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);
if (f == NULL && avail_in < 0)
return (ARCHIVE_FATAL);
if (avail_in < tail) {
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: Remaining data is less bytes");
return (ARCHIVE_FAILED);
}
/* Check the crc32 value of the uncompressed data of the current
* member */
if (state->crc32 != archive_le32dec(f)) {
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: CRC32 error");
return (ARCHIVE_FAILED);
}
/* Check the uncompressed size of the current member */
if ((uint64_t)state->member_out != archive_le64dec(f + 4)) {
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: Uncompressed size error");
return (ARCHIVE_FAILED);
}
/* Check the total size of the current member */
if (state->lzip_ver == 1 &&
(uint64_t)state->member_in + tail != archive_le64dec(f + 12)) {
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: Member size error");
return (ARCHIVE_FAILED);
}
__archive_read_filter_consume(self->upstream, tail);
/* If current lzip data consists of multi member, try decompressing
* a next member. */
if (lzip_has_member(self->upstream) != 0) {
state->in_stream = 0;
state->crc32 = 0;
state->member_out = 0;
state->member_in = 0;
state->eof = 0;
}
return (ARCHIVE_OK);
}
/* /*
* Return the next block of decompressed data. * Return the next block of decompressed data.
*/ */
@ -421,10 +685,23 @@ xz_filter_read(struct archive_read_filter *self, const void **p)
/* Try to fill the output buffer. */ /* Try to fill the output buffer. */
while (state->stream.avail_out > 0 && !state->eof) { while (state->stream.avail_out > 0 && !state->eof) {
if (!state->in_stream) {
/*
* Initialize liblzma for lzip
*/
ret = lzip_init(self);
if (ret != ARCHIVE_OK)
return (ret);
state->in_stream = 1;
}
state->stream.next_in = state->stream.next_in =
__archive_read_filter_ahead(self->upstream, 1, &avail_in); __archive_read_filter_ahead(self->upstream, 1, &avail_in);
if (state->stream.next_in == NULL && avail_in < 0) if (state->stream.next_in == NULL && avail_in < 0) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated input");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
}
state->stream.avail_in = avail_in; state->stream.avail_in = avail_in;
/* Decompress as much as we can in one pass. */ /* Decompress as much as we can in one pass. */
@ -437,50 +714,32 @@ xz_filter_read(struct archive_read_filter *self, const void **p)
case LZMA_OK: /* Decompressor made some progress. */ case LZMA_OK: /* Decompressor made some progress. */
__archive_read_filter_consume(self->upstream, __archive_read_filter_consume(self->upstream,
avail_in - state->stream.avail_in); avail_in - state->stream.avail_in);
state->member_in +=
avail_in - state->stream.avail_in;
break; break;
case LZMA_MEM_ERROR:
archive_set_error(&self->archive->archive, ENOMEM,
"Lzma library error: Cannot allocate memory");
return (ARCHIVE_FATAL);
case LZMA_MEMLIMIT_ERROR:
archive_set_error(&self->archive->archive, ENOMEM,
"Lzma library error: Out of memory");
return (ARCHIVE_FATAL);
case LZMA_FORMAT_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: format not recognized");
return (ARCHIVE_FATAL);
case LZMA_OPTIONS_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: Invalid options");
return (ARCHIVE_FATAL);
case LZMA_DATA_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: Corrupted input data");
return (ARCHIVE_FATAL);
case LZMA_BUF_ERROR:
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma library error: No progress is possible");
return (ARCHIVE_FATAL);
default: default:
/* Return an error. */ set_error(self, ret);
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"Lzma decompression failed: Unknown error");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
} }
decompressed = state->stream.next_out - state->out_block; decompressed = state->stream.next_out - state->out_block;
state->total_out += decompressed; state->total_out += decompressed;
state->member_out += decompressed;
if (decompressed == 0) if (decompressed == 0)
*p = NULL; *p = NULL;
else else {
*p = state->out_block; *p = state->out_block;
if (self->code == ARCHIVE_COMPRESSION_LZIP) {
state->crc32 = lzma_crc32(state->out_block,
decompressed, state->crc32);
if (state->eof) {
ret = lzip_tail(self);
if (ret != ARCHIVE_OK)
return (ret);
}
}
}
return (decompressed); return (decompressed);
} }
@ -600,8 +859,12 @@ lzma_filter_read(struct archive_read_filter *self, const void **p)
while (state->stream.avail_out > 0 && !state->eof) { while (state->stream.avail_out > 0 && !state->eof) {
state->stream.next_in = (unsigned char *)(uintptr_t) state->stream.next_in = (unsigned char *)(uintptr_t)
__archive_read_filter_ahead(self->upstream, 1, &avail_in); __archive_read_filter_ahead(self->upstream, 1, &avail_in);
if (state->stream.next_in == NULL && avail_in < 0) if (state->stream.next_in == NULL && avail_in < 0) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC,
"truncated lzma input");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
}
state->stream.avail_in = avail_in; state->stream.avail_in = avail_in;
/* Decompress as much as we can in one pass. */ /* Decompress as much as we can in one pass. */
@ -704,5 +967,19 @@ xz_bidder_init(struct archive_read_filter *self)
return (r); return (r);
} }
static int
lzip_bidder_init(struct archive_read_filter *self)
{
int r;
r = __archive_read_program(self, "unlzip");
/* Note: We set the format here even if __archive_read_program()
* above fails. We do, after all, know what the format is
* even if we weren't able to read it. */
self->code = ARCHIVE_COMPRESSION_LZIP;
self->name = "lzip";
return (r);
}
#endif /* HAVE_LZMA_H */ #endif /* HAVE_LZMA_H */

File diff suppressed because it is too large Load Diff

View File

@ -27,17 +27,53 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#include "archive.h" #include "archive.h"
#include "archive_private.h"
int int
archive_read_support_format_all(struct archive *a) archive_read_support_format_all(struct archive *a)
{ {
archive_check_magic(a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_all");
/* TODO: It would be nice to compute the ordering
* here automatically so that people who enable just
* a few formats can still get the benefits. That
* may just require the format registration to include
* a "maximum read-ahead" value (anything that uses seek
* would be essentially infinite read-ahead). The core
* bid management can then sort the bidders before calling
* them.
*
* If you implement the above, please return the list below
* to alphabetic order.
*/
/*
* These bidders are all pretty cheap; they just examine a
* small initial part of the archive. If one of these bids
* high, we can maybe avoid running any of the more expensive
* bidders below.
*/
archive_read_support_format_ar(a); archive_read_support_format_ar(a);
archive_read_support_format_cpio(a); archive_read_support_format_cpio(a);
archive_read_support_format_empty(a); archive_read_support_format_empty(a);
archive_read_support_format_iso9660(a); archive_read_support_format_lha(a);
archive_read_support_format_mtree(a); archive_read_support_format_mtree(a);
archive_read_support_format_tar(a); archive_read_support_format_tar(a);
archive_read_support_format_xar(a); archive_read_support_format_xar(a);
/*
* Install expensive bidders last. By doing them last, we
* increase the chance that a high bid from someone else will
* make it unnecessary for these to do anything at all.
*/
/* These three have potentially large look-ahead. */
archive_read_support_format_7zip(a);
archive_read_support_format_cab(a);
archive_read_support_format_rar(a);
archive_read_support_format_iso9660(a);
/* Seek is really bad, since it forces the read-ahead
* logic to discard buffered data. */
archive_read_support_format_zip(a); archive_read_support_format_zip(a);
/* Note: We always return ARCHIVE_OK here, even if some of the /* Note: We always return ARCHIVE_OK here, even if some of the

View File

@ -50,11 +50,17 @@ __FBSDID("$FreeBSD$");
#include "archive_read_private.h" #include "archive_read_private.h"
struct ar { struct ar {
off_t entry_bytes_remaining; int64_t entry_bytes_remaining;
off_t entry_offset; /* unconsumed is purely to track data we've gotten from readahead,
off_t entry_padding; * but haven't yet marked as consumed. Must be paired with
* entry_bytes_remaining usage/modification.
*/
size_t entry_bytes_unconsumed;
int64_t entry_offset;
int64_t entry_padding;
char *strtab; char *strtab;
size_t strtab_size; size_t strtab_size;
char read_global_header;
}; };
/* /*
@ -75,10 +81,10 @@ struct ar {
#define AR_fmag_offset 58 #define AR_fmag_offset 58
#define AR_fmag_size 2 #define AR_fmag_size 2
static int archive_read_format_ar_bid(struct archive_read *a); static int archive_read_format_ar_bid(struct archive_read *a, int);
static int archive_read_format_ar_cleanup(struct archive_read *a); static int archive_read_format_ar_cleanup(struct archive_read *a);
static int archive_read_format_ar_read_data(struct archive_read *a, static int archive_read_format_ar_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset); const void **buff, size_t *size, int64_t *offset);
static int archive_read_format_ar_skip(struct archive_read *a); static int archive_read_format_ar_skip(struct archive_read *a);
static int archive_read_format_ar_read_header(struct archive_read *a, static int archive_read_format_ar_read_header(struct archive_read *a,
struct archive_entry *e); struct archive_entry *e);
@ -95,6 +101,9 @@ archive_read_support_format_ar(struct archive *_a)
struct ar *ar; struct ar *ar;
int r; int r;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_ar");
ar = (struct ar *)malloc(sizeof(*ar)); ar = (struct ar *)malloc(sizeof(*ar));
if (ar == NULL) { if (ar == NULL) {
archive_set_error(&a->archive, ENOMEM, archive_set_error(&a->archive, ENOMEM,
@ -135,14 +144,11 @@ archive_read_format_ar_cleanup(struct archive_read *a)
} }
static int static int
archive_read_format_ar_bid(struct archive_read *a) archive_read_format_ar_bid(struct archive_read *a, int best_bid)
{ {
const void *h; const void *h;
if (a->archive.archive_format != 0 && (void)best_bid; /* UNUSED */
(a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
ARCHIVE_FORMAT_AR)
return(0);
/* /*
* Verify the 8-byte file signature. * Verify the 8-byte file signature.
@ -150,45 +156,23 @@ archive_read_format_ar_bid(struct archive_read *a)
*/ */
if ((h = __archive_read_ahead(a, 8, NULL)) == NULL) if ((h = __archive_read_ahead(a, 8, NULL)) == NULL)
return (-1); return (-1);
if (strncmp((const char*)h, "!<arch>\n", 8) == 0) { if (memcmp(h, "!<arch>\n", 8) == 0) {
return (64); return (64);
} }
return (-1); return (-1);
} }
static int static int
archive_read_format_ar_read_header(struct archive_read *a, _ar_read_header(struct archive_read *a, struct archive_entry *entry,
struct archive_entry *entry) struct ar *ar, const char *h, size_t *unconsumed)
{ {
char filename[AR_name_size + 1]; char filename[AR_name_size + 1];
struct ar *ar;
uint64_t number; /* Used to hold parsed numbers before validation. */ uint64_t number; /* Used to hold parsed numbers before validation. */
ssize_t bytes_read;
size_t bsd_name_length, entry_size; size_t bsd_name_length, entry_size;
char *p, *st; char *p, *st;
const void *b; const void *b;
const char *h;
int r; int r;
ar = (struct ar*)(a->format->data);
if (a->archive.file_position == 0) {
/*
* We are now at the beginning of the archive,
* so we need first consume the ar global header.
*/
__archive_read_consume(a, 8);
/* Set a default format code for now. */
a->archive.archive_format = ARCHIVE_FORMAT_AR;
}
/* Read the header for the next file entry. */
if ((b = __archive_read_ahead(a, 60, &bytes_read)) == NULL)
/* Broken header. */
return (ARCHIVE_EOF);
__archive_read_consume(a, 60);
h = (const char *)b;
/* Verify the magic signature on the file header. */ /* Verify the magic signature on the file header. */
if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) { if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {
archive_set_error(&a->archive, EINVAL, archive_set_error(&a->archive, EINVAL,
@ -292,6 +276,12 @@ archive_read_format_ar_read_header(struct archive_read *a,
} }
ar->strtab = st; ar->strtab = st;
ar->strtab_size = entry_size; ar->strtab_size = entry_size;
if (*unconsumed) {
__archive_read_consume(a, *unconsumed);
*unconsumed = 0;
}
if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL) if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
memcpy(st, b, entry_size); memcpy(st, b, entry_size);
@ -347,7 +337,7 @@ archive_read_format_ar_read_header(struct archive_read *a,
* overflowing a size_t and against the filename size * overflowing a size_t and against the filename size
* being larger than the entire entry. */ * being larger than the entire entry. */
if (number > (uint64_t)(bsd_name_length + 1) if (number > (uint64_t)(bsd_name_length + 1)
|| (off_t)bsd_name_length > ar->entry_bytes_remaining) { || (int64_t)bsd_name_length > ar->entry_bytes_remaining) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Bad input file size"); "Bad input file size");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
@ -356,14 +346,17 @@ archive_read_format_ar_read_header(struct archive_read *a,
/* Adjust file size reported to client. */ /* Adjust file size reported to client. */
archive_entry_set_size(entry, ar->entry_bytes_remaining); archive_entry_set_size(entry, ar->entry_bytes_remaining);
if (*unconsumed) {
__archive_read_consume(a, *unconsumed);
*unconsumed = 0;
}
/* Read the long name into memory. */ /* Read the long name into memory. */
if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) { if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file"); "Truncated input file");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
__archive_read_consume(a, bsd_name_length);
/* Store it in the entry. */ /* Store it in the entry. */
p = (char *)malloc(bsd_name_length + 1); p = (char *)malloc(bsd_name_length + 1);
if (p == NULL) { if (p == NULL) {
@ -373,6 +366,9 @@ archive_read_format_ar_read_header(struct archive_read *a,
} }
strncpy(p, b, bsd_name_length); strncpy(p, b, bsd_name_length);
p[bsd_name_length] = '\0'; p[bsd_name_length] = '\0';
__archive_read_consume(a, bsd_name_length);
archive_entry_copy_pathname(entry, p); archive_entry_copy_pathname(entry, p);
free(p); free(p);
return (ARCHIVE_OK); return (ARCHIVE_OK);
@ -408,6 +404,42 @@ archive_read_format_ar_read_header(struct archive_read *a,
return (ar_parse_common_header(ar, entry, h)); return (ar_parse_common_header(ar, entry, h));
} }
static int
archive_read_format_ar_read_header(struct archive_read *a,
struct archive_entry *entry)
{
struct ar *ar = (struct ar*)(a->format->data);
size_t unconsumed;
const void *header_data;
int ret;
if (!ar->read_global_header) {
/*
* We are now at the beginning of the archive,
* so we need first consume the ar global header.
*/
__archive_read_consume(a, 8);
ar->read_global_header = 1;
/* Set a default format code for now. */
a->archive.archive_format = ARCHIVE_FORMAT_AR;
}
/* Read the header for the next file entry. */
if ((header_data = __archive_read_ahead(a, 60, NULL)) == NULL)
/* Broken header. */
return (ARCHIVE_EOF);
unconsumed = 60;
ret = _ar_read_header(a, entry, ar, (const char *)header_data, &unconsumed);
if (unconsumed)
__archive_read_consume(a, unconsumed);
return ret;
}
static int static int
ar_parse_common_header(struct ar *ar, struct archive_entry *entry, ar_parse_common_header(struct ar *ar, struct archive_entry *entry,
const char *h) const char *h)
@ -434,13 +466,18 @@ ar_parse_common_header(struct ar *ar, struct archive_entry *entry,
static int static int
archive_read_format_ar_read_data(struct archive_read *a, archive_read_format_ar_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset) const void **buff, size_t *size, int64_t *offset)
{ {
ssize_t bytes_read; ssize_t bytes_read;
struct ar *ar; struct ar *ar;
ar = (struct ar *)(a->format->data); ar = (struct ar *)(a->format->data);
if (ar->entry_bytes_unconsumed) {
__archive_read_consume(a, ar->entry_bytes_unconsumed);
ar->entry_bytes_unconsumed = 0;
}
if (ar->entry_bytes_remaining > 0) { if (ar->entry_bytes_remaining > 0) {
*buff = __archive_read_ahead(a, 1, &bytes_read); *buff = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read == 0) { if (bytes_read == 0) {
@ -453,20 +490,22 @@ archive_read_format_ar_read_data(struct archive_read *a,
if (bytes_read > ar->entry_bytes_remaining) if (bytes_read > ar->entry_bytes_remaining)
bytes_read = (ssize_t)ar->entry_bytes_remaining; bytes_read = (ssize_t)ar->entry_bytes_remaining;
*size = bytes_read; *size = bytes_read;
ar->entry_bytes_unconsumed = bytes_read;
*offset = ar->entry_offset; *offset = ar->entry_offset;
ar->entry_offset += bytes_read; ar->entry_offset += bytes_read;
ar->entry_bytes_remaining -= bytes_read; ar->entry_bytes_remaining -= bytes_read;
__archive_read_consume(a, (size_t)bytes_read);
return (ARCHIVE_OK); return (ARCHIVE_OK);
} else { } else {
while (ar->entry_padding > 0) { int64_t skipped = __archive_read_consume(a, ar->entry_padding);
*buff = __archive_read_ahead(a, 1, &bytes_read); if (skipped >= 0) {
if (bytes_read <= 0) ar->entry_padding -= skipped;
return (ARCHIVE_FATAL); }
if (bytes_read > ar->entry_padding) if (ar->entry_padding) {
bytes_read = (ssize_t)ar->entry_padding; if (skipped >= 0) {
__archive_read_consume(a, (size_t)bytes_read); archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
ar->entry_padding -= bytes_read; "Truncated ar archive- failed consuming padding");
}
return (ARCHIVE_FATAL);
} }
*buff = NULL; *buff = NULL;
*size = 0; *size = 0;
@ -478,17 +517,19 @@ archive_read_format_ar_read_data(struct archive_read *a,
static int static int
archive_read_format_ar_skip(struct archive_read *a) archive_read_format_ar_skip(struct archive_read *a)
{ {
off_t bytes_skipped; int64_t bytes_skipped;
struct ar* ar; struct ar* ar;
ar = (struct ar *)(a->format->data); ar = (struct ar *)(a->format->data);
bytes_skipped = __archive_read_skip(a, bytes_skipped = __archive_read_consume(a,
ar->entry_bytes_remaining + ar->entry_padding); ar->entry_bytes_remaining + ar->entry_padding
+ ar->entry_bytes_unconsumed);
if (bytes_skipped < 0) if (bytes_skipped < 0)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
ar->entry_bytes_remaining = 0; ar->entry_bytes_remaining = 0;
ar->entry_bytes_unconsumed = 0;
ar->entry_padding = 0; ar->entry_padding = 0;
return (ARCHIVE_OK); return (ARCHIVE_OK);

View File

@ -0,0 +1,74 @@
/*-
* Copyright (c) 2003-2011 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 "archive_platform.h"
__FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
int
archive_read_support_format_by_code(struct archive *a, int format_code)
{
archive_check_magic(a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_by_code");
switch (format_code & ARCHIVE_FORMAT_BASE_MASK) {
case ARCHIVE_FORMAT_7ZIP:
return archive_read_support_format_7zip(a);
break;
case ARCHIVE_FORMAT_AR:
return archive_read_support_format_ar(a);
break;
case ARCHIVE_FORMAT_CAB:
return archive_read_support_format_cab(a);
break;
case ARCHIVE_FORMAT_CPIO:
return archive_read_support_format_cpio(a);
break;
case ARCHIVE_FORMAT_ISO9660:
return archive_read_support_format_iso9660(a);
break;
case ARCHIVE_FORMAT_LHA:
return archive_read_support_format_lha(a);
break;
case ARCHIVE_FORMAT_MTREE:
return archive_read_support_format_mtree(a);
break;
case ARCHIVE_FORMAT_RAR:
return archive_read_support_format_rar(a);
break;
case ARCHIVE_FORMAT_TAR:
return archive_read_support_format_tar(a);
break;
case ARCHIVE_FORMAT_XAR:
return archive_read_support_format_xar(a);
break;
case ARCHIVE_FORMAT_ZIP:
return archive_read_support_format_zip(a);
break;
}
return (ARCHIVE_FATAL);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
/*- /*-
* Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2010-2012 Michihiro NAKAJIMA
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -39,62 +40,127 @@ __FBSDID("$FreeBSD$");
#include "archive.h" #include "archive.h"
#include "archive_entry.h" #include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_private.h" #include "archive_private.h"
#include "archive_read_private.h" #include "archive_read_private.h"
#ifdef _MSC_VER #define bin_magic_offset 0
#define __packed #define bin_magic_size 2
#pragma pack(push, 1) #define bin_dev_offset 2
#endif #define bin_dev_size 2
struct cpio_bin_header { #define bin_ino_offset 4
unsigned char c_magic[2]; #define bin_ino_size 2
unsigned char c_dev[2]; #define bin_mode_offset 6
unsigned char c_ino[2]; #define bin_mode_size 2
unsigned char c_mode[2]; #define bin_uid_offset 8
unsigned char c_uid[2]; #define bin_uid_size 2
unsigned char c_gid[2]; #define bin_gid_offset 10
unsigned char c_nlink[2]; #define bin_gid_size 2
unsigned char c_rdev[2]; #define bin_nlink_offset 12
unsigned char c_mtime[4]; #define bin_nlink_size 2
unsigned char c_namesize[2]; #define bin_rdev_offset 14
unsigned char c_filesize[4]; #define bin_rdev_size 2
} __packed; #define bin_mtime_offset 16
#define bin_mtime_size 4
#define bin_namesize_offset 20
#define bin_namesize_size 2
#define bin_filesize_offset 22
#define bin_filesize_size 4
#define bin_header_size 26
struct cpio_odc_header { #define odc_magic_offset 0
char c_magic[6]; #define odc_magic_size 6
char c_dev[6]; #define odc_dev_offset 6
char c_ino[6]; #define odc_dev_size 6
char c_mode[6]; #define odc_ino_offset 12
char c_uid[6]; #define odc_ino_size 6
char c_gid[6]; #define odc_mode_offset 18
char c_nlink[6]; #define odc_mode_size 6
char c_rdev[6]; #define odc_uid_offset 24
char c_mtime[11]; #define odc_uid_size 6
char c_namesize[6]; #define odc_gid_offset 30
char c_filesize[11]; #define odc_gid_size 6
} __packed; #define odc_nlink_offset 36
#define odc_nlink_size 6
#define odc_rdev_offset 42
#define odc_rdev_size 6
#define odc_mtime_offset 48
#define odc_mtime_size 11
#define odc_namesize_offset 59
#define odc_namesize_size 6
#define odc_filesize_offset 65
#define odc_filesize_size 11
#define odc_header_size 76
struct cpio_newc_header { #define newc_magic_offset 0
char c_magic[6]; #define newc_magic_size 6
char c_ino[8]; #define newc_ino_offset 6
char c_mode[8]; #define newc_ino_size 8
char c_uid[8]; #define newc_mode_offset 14
char c_gid[8]; #define newc_mode_size 8
char c_nlink[8]; #define newc_uid_offset 22
char c_mtime[8]; #define newc_uid_size 8
char c_filesize[8]; #define newc_gid_offset 30
char c_devmajor[8]; #define newc_gid_size 8
char c_devminor[8]; #define newc_nlink_offset 38
char c_rdevmajor[8]; #define newc_nlink_size 8
char c_rdevminor[8]; #define newc_mtime_offset 46
char c_namesize[8]; #define newc_mtime_size 8
char c_crc[8]; #define newc_filesize_offset 54
} __packed; #define newc_filesize_size 8
#define newc_devmajor_offset 62
#define newc_devmajor_size 8
#define newc_devminor_offset 70
#define newc_devminor_size 8
#define newc_rdevmajor_offset 78
#define newc_rdevmajor_size 8
#define newc_rdevminor_offset 86
#define newc_rdevminor_size 8
#define newc_namesize_offset 94
#define newc_namesize_size 8
#define newc_checksum_offset 102
#define newc_checksum_size 8
#define newc_header_size 110
/*
* An afio large ASCII header, which they named itself.
* afio utility uses this header, if a file size is larger than 2G bytes
* or inode/uid/gid is bigger than 65535(0xFFFF) or mtime is bigger than
* 0x7fffffff, which we cannot record to odc header because of its limit.
* If not, uses odc header.
*/
#define afiol_magic_offset 0
#define afiol_magic_size 6
#define afiol_dev_offset 6
#define afiol_dev_size 8 /* hex */
#define afiol_ino_offset 14
#define afiol_ino_size 16 /* hex */
#define afiol_ino_m_offset 30 /* 'm' */
#define afiol_mode_offset 31
#define afiol_mode_size 6 /* oct */
#define afiol_uid_offset 37
#define afiol_uid_size 8 /* hex */
#define afiol_gid_offset 45
#define afiol_gid_size 8 /* hex */
#define afiol_nlink_offset 53
#define afiol_nlink_size 8 /* hex */
#define afiol_rdev_offset 61
#define afiol_rdev_size 8 /* hex */
#define afiol_mtime_offset 69
#define afiol_mtime_size 16 /* hex */
#define afiol_mtime_n_offset 85 /* 'n' */
#define afiol_namesize_offset 86
#define afiol_namesize_size 4 /* hex */
#define afiol_flag_offset 90
#define afiol_flag_size 4 /* hex */
#define afiol_xsize_offset 94
#define afiol_xsize_size 4 /* hex */
#define afiol_xsize_s_offset 98 /* 's' */
#define afiol_filesize_offset 99
#define afiol_filesize_size 16 /* hex */
#define afiol_filesize_c_offset 115 /* ':' */
#define afiol_header_size 116
#ifdef _MSC_VER
#undef __packed
#pragma pack(pop)
#endif
struct links_entry { struct links_entry {
struct links_entry *next; struct links_entry *next;
@ -111,21 +177,27 @@ struct cpio {
int (*read_header)(struct archive_read *, struct cpio *, int (*read_header)(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *); struct archive_entry *, size_t *, size_t *);
struct links_entry *links_head; struct links_entry *links_head;
struct archive_string entry_name; int64_t entry_bytes_remaining;
struct archive_string entry_linkname; int64_t entry_bytes_unconsumed;
off_t entry_bytes_remaining; int64_t entry_offset;
off_t entry_offset; int64_t entry_padding;
off_t entry_padding;
struct archive_string_conv *opt_sconv;
struct archive_string_conv *sconv_default;
int init_default_conversion;
}; };
static int64_t atol16(const char *, unsigned); static int64_t atol16(const char *, unsigned);
static int64_t atol8(const char *, unsigned); static int64_t atol8(const char *, unsigned);
static int archive_read_format_cpio_bid(struct archive_read *); static int archive_read_format_cpio_bid(struct archive_read *, int);
static int archive_read_format_cpio_options(struct archive_read *,
const char *, const char *);
static int archive_read_format_cpio_cleanup(struct archive_read *); static int archive_read_format_cpio_cleanup(struct archive_read *);
static int archive_read_format_cpio_read_data(struct archive_read *, static int archive_read_format_cpio_read_data(struct archive_read *,
const void **, size_t *, off_t *); const void **, size_t *, int64_t *);
static int archive_read_format_cpio_read_header(struct archive_read *, static int archive_read_format_cpio_read_header(struct archive_read *,
struct archive_entry *); struct archive_entry *);
static int archive_read_format_cpio_skip(struct archive_read *);
static int be4(const unsigned char *); static int be4(const unsigned char *);
static int find_odc_header(struct archive_read *); static int find_odc_header(struct archive_read *);
static int find_newc_header(struct archive_read *); static int find_newc_header(struct archive_read *);
@ -137,10 +209,13 @@ static int header_newc(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *); struct archive_entry *, size_t *, size_t *);
static int header_odc(struct archive_read *, struct cpio *, static int header_odc(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *); struct archive_entry *, size_t *, size_t *);
static int header_afiol(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *);
static int is_octal(const char *, size_t); static int is_octal(const char *, size_t);
static int is_hex(const char *, size_t); static int is_hex(const char *, size_t);
static int le4(const unsigned char *); static int le4(const unsigned char *);
static void record_hardlink(struct cpio *cpio, struct archive_entry *entry); static int record_hardlink(struct archive_read *a,
struct cpio *cpio, struct archive_entry *entry);
int int
archive_read_support_format_cpio(struct archive *_a) archive_read_support_format_cpio(struct archive *_a)
@ -149,22 +224,24 @@ archive_read_support_format_cpio(struct archive *_a)
struct cpio *cpio; struct cpio *cpio;
int r; int r;
cpio = (struct cpio *)malloc(sizeof(*cpio)); archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_cpio");
cpio = (struct cpio *)calloc(1, sizeof(*cpio));
if (cpio == NULL) { if (cpio == NULL) {
archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
memset(cpio, 0, sizeof(*cpio));
cpio->magic = CPIO_MAGIC; cpio->magic = CPIO_MAGIC;
r = __archive_read_register_format(a, r = __archive_read_register_format(a,
cpio, cpio,
"cpio", "cpio",
archive_read_format_cpio_bid, archive_read_format_cpio_bid,
NULL, archive_read_format_cpio_options,
archive_read_format_cpio_read_header, archive_read_format_cpio_read_header,
archive_read_format_cpio_read_data, archive_read_format_cpio_read_data,
NULL, archive_read_format_cpio_skip,
archive_read_format_cpio_cleanup); archive_read_format_cpio_cleanup);
if (r != ARCHIVE_OK) if (r != ARCHIVE_OK)
@ -174,19 +251,19 @@ archive_read_support_format_cpio(struct archive *_a)
static int static int
archive_read_format_cpio_bid(struct archive_read *a) archive_read_format_cpio_bid(struct archive_read *a, int best_bid)
{ {
const void *h;
const unsigned char *p; const unsigned char *p;
struct cpio *cpio; struct cpio *cpio;
int bid; int bid;
(void)best_bid; /* UNUSED */
cpio = (struct cpio *)(a->format->data); cpio = (struct cpio *)(a->format->data);
if ((h = __archive_read_ahead(a, 6, NULL)) == NULL) if ((p = __archive_read_ahead(a, 6, NULL)) == NULL)
return (-1); return (-1);
p = (const unsigned char *)h;
bid = 0; bid = 0;
if (memcmp(p, "070707", 6) == 0) { if (memcmp(p, "070707", 6) == 0) {
/* ASCII cpio archive (odc, POSIX.1) */ /* ASCII cpio archive (odc, POSIX.1) */
@ -196,6 +273,14 @@ archive_read_format_cpio_bid(struct archive_read *a)
* XXX TODO: More verification; Could check that only octal * XXX TODO: More verification; Could check that only octal
* digits appear in appropriate header locations. XXX * digits appear in appropriate header locations. XXX
*/ */
} else if (memcmp(p, "070727", 6) == 0) {
/* afio large ASCII cpio archive */
cpio->read_header = header_odc;
bid += 48;
/*
* XXX TODO: More verification; Could check that almost hex
* digits appear in appropriate header locations. XXX
*/
} else if (memcmp(p, "070701", 6) == 0) { } else if (memcmp(p, "070701", 6) == 0) {
/* ASCII cpio archive (SVR4 without CRC) */ /* ASCII cpio archive (SVR4 without CRC) */
cpio->read_header = header_newc; cpio->read_header = header_newc;
@ -229,17 +314,63 @@ archive_read_format_cpio_bid(struct archive_read *a)
return (bid); return (bid);
} }
static int
archive_read_format_cpio_options(struct archive_read *a,
const char *key, const char *val)
{
struct cpio *cpio;
int ret = ARCHIVE_FAILED;
cpio = (struct cpio *)(a->format->data);
if (strcmp(key, "compat-2x") == 0) {
/* Handle filnames as libarchive 2.x */
cpio->init_default_conversion = (val != NULL)?1:0;
return (ARCHIVE_OK);
} else if (strcmp(key, "hdrcharset") == 0) {
if (val == NULL || val[0] == 0)
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"cpio: hdrcharset option needs a character-set name");
else {
cpio->opt_sconv =
archive_string_conversion_from_charset(
&a->archive, val, 0);
if (cpio->opt_sconv != NULL)
ret = ARCHIVE_OK;
else
ret = ARCHIVE_FATAL;
}
return (ret);
}
/* Note: The "warn" return is just to inform the options
* supervisor that we didn't handle it. It will generate
* a suitable error if no one used this option. */
return (ARCHIVE_WARN);
}
static int static int
archive_read_format_cpio_read_header(struct archive_read *a, archive_read_format_cpio_read_header(struct archive_read *a,
struct archive_entry *entry) struct archive_entry *entry)
{ {
struct cpio *cpio; struct cpio *cpio;
const void *h; const void *h;
struct archive_string_conv *sconv;
size_t namelength; size_t namelength;
size_t name_pad; size_t name_pad;
int r; int r;
cpio = (struct cpio *)(a->format->data); cpio = (struct cpio *)(a->format->data);
sconv = cpio->opt_sconv;
if (sconv == NULL) {
if (!cpio->init_default_conversion) {
cpio->sconv_default =
archive_string_default_conversion_for_read(
&(a->archive));
cpio->init_default_conversion = 1;
}
sconv = cpio->sconv_default;
}
r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad)); r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad));
if (r < ARCHIVE_WARN) if (r < ARCHIVE_WARN)
@ -249,20 +380,42 @@ archive_read_format_cpio_read_header(struct archive_read *a,
h = __archive_read_ahead(a, namelength + name_pad, NULL); h = __archive_read_ahead(a, namelength + name_pad, NULL);
if (h == NULL) if (h == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
__archive_read_consume(a, namelength + name_pad); if (archive_entry_copy_pathname_l(entry,
archive_strncpy(&cpio->entry_name, (const char *)h, namelength); (const char *)h, namelength, sconv) != 0) {
archive_entry_set_pathname(entry, cpio->entry_name.s); if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Pathname");
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Pathname can't be converted from %s to current locale.",
archive_string_conversion_charset_name(sconv));
r = ARCHIVE_WARN;
}
cpio->entry_offset = 0; cpio->entry_offset = 0;
__archive_read_consume(a, namelength + name_pad);
/* If this is a symlink, read the link contents. */ /* If this is a symlink, read the link contents. */
if (archive_entry_filetype(entry) == AE_IFLNK) { if (archive_entry_filetype(entry) == AE_IFLNK) {
h = __archive_read_ahead(a, cpio->entry_bytes_remaining, NULL); h = __archive_read_ahead(a, cpio->entry_bytes_remaining, NULL);
if (h == NULL) if (h == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
if (archive_entry_copy_symlink_l(entry, (const char *)h,
cpio->entry_bytes_remaining, sconv) != 0) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Linkname");
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Linkname can't be converted from %s to "
"current locale.",
archive_string_conversion_charset_name(sconv));
r = ARCHIVE_WARN;
}
__archive_read_consume(a, cpio->entry_bytes_remaining); __archive_read_consume(a, cpio->entry_bytes_remaining);
archive_strncpy(&cpio->entry_linkname, (const char *)h,
cpio->entry_bytes_remaining);
archive_entry_set_symlink(entry, cpio->entry_linkname.s);
cpio->entry_bytes_remaining = 0; cpio->entry_bytes_remaining = 0;
} }
@ -279,19 +432,27 @@ archive_read_format_cpio_read_header(struct archive_read *a,
} }
/* Detect and record hardlinks to previously-extracted entries. */ /* Detect and record hardlinks to previously-extracted entries. */
record_hardlink(cpio, entry); if (record_hardlink(a, cpio, entry) != ARCHIVE_OK) {
return (ARCHIVE_FATAL);
}
return (r); return (r);
} }
static int static int
archive_read_format_cpio_read_data(struct archive_read *a, archive_read_format_cpio_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset) const void **buff, size_t *size, int64_t *offset)
{ {
ssize_t bytes_read; ssize_t bytes_read;
struct cpio *cpio; struct cpio *cpio;
cpio = (struct cpio *)(a->format->data); cpio = (struct cpio *)(a->format->data);
if (cpio->entry_bytes_unconsumed) {
__archive_read_consume(a, cpio->entry_bytes_unconsumed);
cpio->entry_bytes_unconsumed = 0;
}
if (cpio->entry_bytes_remaining > 0) { if (cpio->entry_bytes_remaining > 0) {
*buff = __archive_read_ahead(a, 1, &bytes_read); *buff = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read <= 0) if (bytes_read <= 0)
@ -299,21 +460,17 @@ archive_read_format_cpio_read_data(struct archive_read *a,
if (bytes_read > cpio->entry_bytes_remaining) if (bytes_read > cpio->entry_bytes_remaining)
bytes_read = cpio->entry_bytes_remaining; bytes_read = cpio->entry_bytes_remaining;
*size = bytes_read; *size = bytes_read;
cpio->entry_bytes_unconsumed = bytes_read;
*offset = cpio->entry_offset; *offset = cpio->entry_offset;
cpio->entry_offset += bytes_read; cpio->entry_offset += bytes_read;
cpio->entry_bytes_remaining -= bytes_read; cpio->entry_bytes_remaining -= bytes_read;
__archive_read_consume(a, bytes_read);
return (ARCHIVE_OK); return (ARCHIVE_OK);
} else { } else {
while (cpio->entry_padding > 0) { if (cpio->entry_padding !=
*buff = __archive_read_ahead(a, 1, &bytes_read); __archive_read_consume(a, cpio->entry_padding)) {
if (bytes_read <= 0) return (ARCHIVE_FATAL);
return (ARCHIVE_FATAL);
if (bytes_read > cpio->entry_padding)
bytes_read = cpio->entry_padding;
__archive_read_consume(a, bytes_read);
cpio->entry_padding -= bytes_read;
} }
cpio->entry_padding = 0;
*buff = NULL; *buff = NULL;
*size = 0; *size = 0;
*offset = cpio->entry_offset; *offset = cpio->entry_offset;
@ -321,6 +478,22 @@ archive_read_format_cpio_read_data(struct archive_read *a,
} }
} }
static int
archive_read_format_cpio_skip(struct archive_read *a)
{
struct cpio *cpio = (struct cpio *)(a->format->data);
int64_t to_skip = cpio->entry_bytes_remaining + cpio->entry_padding +
cpio->entry_bytes_unconsumed;
if (to_skip != __archive_read_consume(a, to_skip)) {
return (ARCHIVE_FATAL);
}
cpio->entry_bytes_remaining = 0;
cpio->entry_padding = 0;
cpio->entry_bytes_unconsumed = 0;
return (ARCHIVE_OK);
}
/* /*
* Skip forward to the next cpio newc header by searching for the * Skip forward to the next cpio newc header by searching for the
* 07070[12] string. This should be generalized and merged with * 07070[12] string. This should be generalized and merged with
@ -349,7 +522,7 @@ find_newc_header(struct archive_read *a)
ssize_t bytes; ssize_t bytes;
for (;;) { for (;;) {
h = __archive_read_ahead(a, sizeof(struct cpio_newc_header), &bytes); h = __archive_read_ahead(a, newc_header_size, &bytes);
if (h == NULL) if (h == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
p = h; p = h;
@ -358,19 +531,19 @@ find_newc_header(struct archive_read *a)
/* Try the typical case first, then go into the slow search.*/ /* Try the typical case first, then go into the slow search.*/
if (memcmp("07070", p, 5) == 0 if (memcmp("07070", p, 5) == 0
&& (p[5] == '1' || p[5] == '2') && (p[5] == '1' || p[5] == '2')
&& is_hex(p, sizeof(struct cpio_newc_header))) && is_hex(p, newc_header_size))
return (ARCHIVE_OK); return (ARCHIVE_OK);
/* /*
* Scan ahead until we find something that looks * Scan ahead until we find something that looks
* like an odc header. * like a newc header.
*/ */
while (p + sizeof(struct cpio_newc_header) <= q) { while (p + newc_header_size <= q) {
switch (p[5]) { switch (p[5]) {
case '1': case '1':
case '2': case '2':
if (memcmp("07070", p, 5) == 0 if (memcmp("07070", p, 5) == 0
&& is_hex(p, sizeof(struct cpio_newc_header))) { && is_hex(p, newc_header_size)) {
skip = p - (const char *)h; skip = p - (const char *)h;
__archive_read_consume(a, skip); __archive_read_consume(a, skip);
skipped += skip; skipped += skip;
@ -405,7 +578,7 @@ header_newc(struct archive_read *a, struct cpio *cpio,
struct archive_entry *entry, size_t *namelength, size_t *name_pad) struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{ {
const void *h; const void *h;
const struct cpio_newc_header *header; const char *header;
int r; int r;
r = find_newc_header(a); r = find_newc_header(a);
@ -413,35 +586,34 @@ header_newc(struct archive_read *a, struct cpio *cpio,
return (r); return (r);
/* Read fixed-size portion of header. */ /* Read fixed-size portion of header. */
h = __archive_read_ahead(a, sizeof(struct cpio_newc_header), NULL); h = __archive_read_ahead(a, newc_header_size, NULL);
if (h == NULL) if (h == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
__archive_read_consume(a, sizeof(struct cpio_newc_header));
/* Parse out hex fields. */ /* Parse out hex fields. */
header = (const struct cpio_newc_header *)h; header = (const char *)h;
if (memcmp(header->c_magic, "070701", 6) == 0) { if (memcmp(header + newc_magic_offset, "070701", 6) == 0) {
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)"; a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)";
} else if (memcmp(header->c_magic, "070702", 6) == 0) { } else if (memcmp(header + newc_magic_offset, "070702", 6) == 0) {
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)"; a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)";
} else { } else {
/* TODO: Abort here? */ /* TODO: Abort here? */
} }
archive_entry_set_devmajor(entry, atol16(header->c_devmajor, sizeof(header->c_devmajor))); archive_entry_set_devmajor(entry, atol16(header + newc_devmajor_offset, newc_devmajor_size));
archive_entry_set_devminor(entry, atol16(header->c_devminor, sizeof(header->c_devminor))); archive_entry_set_devminor(entry, atol16(header + newc_devminor_offset, newc_devminor_size));
archive_entry_set_ino(entry, atol16(header->c_ino, sizeof(header->c_ino))); archive_entry_set_ino(entry, atol16(header + newc_ino_offset, newc_ino_size));
archive_entry_set_mode(entry, atol16(header->c_mode, sizeof(header->c_mode))); archive_entry_set_mode(entry, atol16(header + newc_mode_offset, newc_mode_size));
archive_entry_set_uid(entry, atol16(header->c_uid, sizeof(header->c_uid))); archive_entry_set_uid(entry, atol16(header + newc_uid_offset, newc_uid_size));
archive_entry_set_gid(entry, atol16(header->c_gid, sizeof(header->c_gid))); archive_entry_set_gid(entry, atol16(header + newc_gid_offset, newc_gid_size));
archive_entry_set_nlink(entry, atol16(header->c_nlink, sizeof(header->c_nlink))); archive_entry_set_nlink(entry, atol16(header + newc_nlink_offset, newc_nlink_size));
archive_entry_set_rdevmajor(entry, atol16(header->c_rdevmajor, sizeof(header->c_rdevmajor))); archive_entry_set_rdevmajor(entry, atol16(header + newc_rdevmajor_offset, newc_rdevmajor_size));
archive_entry_set_rdevminor(entry, atol16(header->c_rdevminor, sizeof(header->c_rdevminor))); archive_entry_set_rdevminor(entry, atol16(header + newc_rdevminor_offset, newc_rdevminor_size));
archive_entry_set_mtime(entry, atol16(header->c_mtime, sizeof(header->c_mtime)), 0); archive_entry_set_mtime(entry, atol16(header + newc_mtime_offset, newc_mtime_size), 0);
*namelength = atol16(header->c_namesize, sizeof(header->c_namesize)); *namelength = atol16(header + newc_namesize_offset, newc_namesize_size);
/* Pad name to 2 more than a multiple of 4. */ /* Pad name to 2 more than a multiple of 4. */
*name_pad = (2 - *namelength) & 3; *name_pad = (2 - *namelength) & 3;
@ -451,10 +623,11 @@ header_newc(struct archive_read *a, struct cpio *cpio,
* size. * size.
*/ */
cpio->entry_bytes_remaining = cpio->entry_bytes_remaining =
atol16(header->c_filesize, sizeof(header->c_filesize)); atol16(header + newc_filesize_offset, newc_filesize_size);
archive_entry_set_size(entry, cpio->entry_bytes_remaining); archive_entry_set_size(entry, cpio->entry_bytes_remaining);
/* Pad file contents to a multiple of 4. */ /* Pad file contents to a multiple of 4. */
cpio->entry_padding = 3 & -cpio->entry_bytes_remaining; cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
__archive_read_consume(a, newc_header_size);
return (r); return (r);
} }
@ -475,6 +648,27 @@ is_octal(const char *p, size_t len)
return (1); return (1);
} }
static int
is_afio_large(const char *h, size_t len)
{
if (len < afiol_header_size)
return (0);
if (h[afiol_ino_m_offset] != 'm'
|| h[afiol_mtime_n_offset] != 'n'
|| h[afiol_xsize_s_offset] != 's'
|| h[afiol_filesize_c_offset] != ':')
return (0);
if (!is_hex(h + afiol_dev_offset, afiol_ino_m_offset - afiol_dev_offset))
return (0);
if (!is_hex(h + afiol_mode_offset, afiol_mtime_n_offset - afiol_mode_offset))
return (0);
if (!is_hex(h + afiol_namesize_offset, afiol_xsize_s_offset - afiol_namesize_offset))
return (0);
if (!is_hex(h + afiol_filesize_offset, afiol_filesize_size))
return (0);
return (1);
}
static int static int
find_odc_header(struct archive_read *a) find_odc_header(struct archive_read *a)
{ {
@ -484,29 +678,37 @@ find_odc_header(struct archive_read *a)
ssize_t bytes; ssize_t bytes;
for (;;) { for (;;) {
h = __archive_read_ahead(a, sizeof(struct cpio_odc_header), &bytes); h = __archive_read_ahead(a, odc_header_size, &bytes);
if (h == NULL) if (h == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
p = h; p = h;
q = p + bytes; q = p + bytes;
/* Try the typical case first, then go into the slow search.*/ /* Try the typical case first, then go into the slow search.*/
if (memcmp("070707", p, 6) == 0 if (memcmp("070707", p, 6) == 0 && is_octal(p, odc_header_size))
&& is_octal(p, sizeof(struct cpio_odc_header)))
return (ARCHIVE_OK); return (ARCHIVE_OK);
if (memcmp("070727", p, 6) == 0 && is_afio_large(p, bytes)) {
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
return (ARCHIVE_OK);
}
/* /*
* Scan ahead until we find something that looks * Scan ahead until we find something that looks
* like an odc header. * like an odc header.
*/ */
while (p + sizeof(struct cpio_odc_header) <= q) { while (p + odc_header_size <= q) {
switch (p[5]) { switch (p[5]) {
case '7': case '7':
if (memcmp("070707", p, 6) == 0 if ((memcmp("070707", p, 6) == 0
&& is_octal(p, sizeof(struct cpio_odc_header))) { && is_octal(p, odc_header_size))
|| (memcmp("070727", p, 6) == 0
&& is_afio_large(p, q - p))) {
skip = p - (const char *)h; skip = p - (const char *)h;
__archive_read_consume(a, skip); __archive_read_consume(a, skip);
skipped += skip; skipped += skip;
if (p[4] == '2')
a->archive.archive_format =
ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
if (skipped > 0) { if (skipped > 0) {
archive_set_error(&a->archive, archive_set_error(&a->archive,
0, 0,
@ -539,7 +741,7 @@ header_odc(struct archive_read *a, struct cpio *cpio,
{ {
const void *h; const void *h;
int r; int r;
const struct cpio_odc_header *header; const char *header;
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
a->archive.archive_format_name = "POSIX octet-oriented cpio"; a->archive.archive_format_name = "POSIX octet-oriented cpio";
@ -549,24 +751,31 @@ header_odc(struct archive_read *a, struct cpio *cpio,
if (r < ARCHIVE_WARN) if (r < ARCHIVE_WARN)
return (r); return (r);
if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_AFIO_LARGE) {
int r2 = (header_afiol(a, cpio, entry, namelength, name_pad));
if (r2 == ARCHIVE_OK)
return (r);
else
return (r2);
}
/* Read fixed-size portion of header. */ /* Read fixed-size portion of header. */
h = __archive_read_ahead(a, sizeof(struct cpio_odc_header), NULL); h = __archive_read_ahead(a, odc_header_size, NULL);
if (h == NULL) if (h == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
__archive_read_consume(a, sizeof(struct cpio_odc_header));
/* Parse out octal fields. */ /* Parse out octal fields. */
header = (const struct cpio_odc_header *)h; header = (const char *)h;
archive_entry_set_dev(entry, atol8(header->c_dev, sizeof(header->c_dev))); archive_entry_set_dev(entry, atol8(header + odc_dev_offset, odc_dev_size));
archive_entry_set_ino(entry, atol8(header->c_ino, sizeof(header->c_ino))); archive_entry_set_ino(entry, atol8(header + odc_ino_offset, odc_ino_size));
archive_entry_set_mode(entry, atol8(header->c_mode, sizeof(header->c_mode))); archive_entry_set_mode(entry, atol8(header + odc_mode_offset, odc_mode_size));
archive_entry_set_uid(entry, atol8(header->c_uid, sizeof(header->c_uid))); archive_entry_set_uid(entry, atol8(header + odc_uid_offset, odc_uid_size));
archive_entry_set_gid(entry, atol8(header->c_gid, sizeof(header->c_gid))); archive_entry_set_gid(entry, atol8(header + odc_gid_offset, odc_gid_size));
archive_entry_set_nlink(entry, atol8(header->c_nlink, sizeof(header->c_nlink))); archive_entry_set_nlink(entry, atol8(header + odc_nlink_offset, odc_nlink_size));
archive_entry_set_rdev(entry, atol8(header->c_rdev, sizeof(header->c_rdev))); archive_entry_set_rdev(entry, atol8(header + odc_rdev_offset, odc_rdev_size));
archive_entry_set_mtime(entry, atol8(header->c_mtime, sizeof(header->c_mtime)), 0); archive_entry_set_mtime(entry, atol8(header + odc_mtime_offset, odc_mtime_size), 0);
*namelength = atol8(header->c_namesize, sizeof(header->c_namesize)); *namelength = atol8(header + odc_namesize_offset, odc_namesize_size);
*name_pad = 0; /* No padding of filename. */ *name_pad = 0; /* No padding of filename. */
/* /*
@ -575,45 +784,91 @@ header_odc(struct archive_read *a, struct cpio *cpio,
* size. * size.
*/ */
cpio->entry_bytes_remaining = cpio->entry_bytes_remaining =
atol8(header->c_filesize, sizeof(header->c_filesize)); atol8(header + odc_filesize_offset, odc_filesize_size);
archive_entry_set_size(entry, cpio->entry_bytes_remaining); archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = 0; cpio->entry_padding = 0;
__archive_read_consume(a, odc_header_size);
return (r); return (r);
} }
/*
* NOTE: if a filename suffix is ".z", it is the file gziped by afio.
* it would be nice that we can show uncompressed file size and we can
* uncompressed file contents automatically, unfortunately we have nothing
* to get a uncompressed file size while reading each header. it means
* we also cannot uncompressed file contens under the our framework.
*/
static int
header_afiol(struct archive_read *a, struct cpio *cpio,
struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
const void *h;
const char *header;
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_AFIO_LARGE;
a->archive.archive_format_name = "afio large ASCII";
/* Read fixed-size portion of header. */
h = __archive_read_ahead(a, afiol_header_size, NULL);
if (h == NULL)
return (ARCHIVE_FATAL);
/* Parse out octal fields. */
header = (const char *)h;
archive_entry_set_dev(entry, atol16(header + afiol_dev_offset, afiol_dev_size));
archive_entry_set_ino(entry, atol16(header + afiol_ino_offset, afiol_ino_size));
archive_entry_set_mode(entry, atol8(header + afiol_mode_offset, afiol_mode_size));
archive_entry_set_uid(entry, atol16(header + afiol_uid_offset, afiol_uid_size));
archive_entry_set_gid(entry, atol16(header + afiol_gid_offset, afiol_gid_size));
archive_entry_set_nlink(entry, atol16(header + afiol_nlink_offset, afiol_nlink_size));
archive_entry_set_rdev(entry, atol16(header + afiol_rdev_offset, afiol_rdev_size));
archive_entry_set_mtime(entry, atol16(header + afiol_mtime_offset, afiol_mtime_size), 0);
*namelength = atol16(header + afiol_namesize_offset, afiol_namesize_size);
*name_pad = 0; /* No padding of filename. */
cpio->entry_bytes_remaining =
atol16(header + afiol_filesize_offset, afiol_filesize_size);
archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = 0;
__archive_read_consume(a, afiol_header_size);
return (ARCHIVE_OK);
}
static int static int
header_bin_le(struct archive_read *a, struct cpio *cpio, header_bin_le(struct archive_read *a, struct cpio *cpio,
struct archive_entry *entry, size_t *namelength, size_t *name_pad) struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{ {
const void *h; const void *h;
const struct cpio_bin_header *header; const unsigned char *header;
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
a->archive.archive_format_name = "cpio (little-endian binary)"; a->archive.archive_format_name = "cpio (little-endian binary)";
/* Read fixed-size portion of header. */ /* Read fixed-size portion of header. */
h = __archive_read_ahead(a, sizeof(struct cpio_bin_header), NULL); h = __archive_read_ahead(a, bin_header_size, NULL);
if (h == NULL) if (h == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
__archive_read_consume(a, sizeof(struct cpio_bin_header));
/* Parse out binary fields. */ /* Parse out binary fields. */
header = (const struct cpio_bin_header *)h; header = (const unsigned char *)h;
archive_entry_set_dev(entry, header->c_dev[0] + header->c_dev[1] * 256); archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256);
archive_entry_set_ino(entry, header->c_ino[0] + header->c_ino[1] * 256); archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256);
archive_entry_set_mode(entry, header->c_mode[0] + header->c_mode[1] * 256); archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256);
archive_entry_set_uid(entry, header->c_uid[0] + header->c_uid[1] * 256); archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256);
archive_entry_set_gid(entry, header->c_gid[0] + header->c_gid[1] * 256); archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256);
archive_entry_set_nlink(entry, header->c_nlink[0] + header->c_nlink[1] * 256); archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256);
archive_entry_set_rdev(entry, header->c_rdev[0] + header->c_rdev[1] * 256); archive_entry_set_rdev(entry, header[bin_rdev_offset] + header[bin_rdev_offset + 1] * 256);
archive_entry_set_mtime(entry, le4(header->c_mtime), 0); archive_entry_set_mtime(entry, le4(header + bin_mtime_offset), 0);
*namelength = header->c_namesize[0] + header->c_namesize[1] * 256; *namelength = header[bin_namesize_offset] + header[bin_namesize_offset + 1] * 256;
*name_pad = *namelength & 1; /* Pad to even. */ *name_pad = *namelength & 1; /* Pad to even. */
cpio->entry_bytes_remaining = le4(header->c_filesize); cpio->entry_bytes_remaining = le4(header + bin_filesize_offset);
archive_entry_set_size(entry, cpio->entry_bytes_remaining); archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */ cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
__archive_read_consume(a, bin_header_size);
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
@ -622,33 +877,34 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
struct archive_entry *entry, size_t *namelength, size_t *name_pad) struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{ {
const void *h; const void *h;
const struct cpio_bin_header *header; const unsigned char *header;
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE; a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
a->archive.archive_format_name = "cpio (big-endian binary)"; a->archive.archive_format_name = "cpio (big-endian binary)";
/* Read fixed-size portion of header. */ /* Read fixed-size portion of header. */
h = __archive_read_ahead(a, sizeof(struct cpio_bin_header), NULL); h = __archive_read_ahead(a, bin_header_size, NULL);
if (h == NULL) if (h == NULL)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
__archive_read_consume(a, sizeof(struct cpio_bin_header));
/* Parse out binary fields. */ /* Parse out binary fields. */
header = (const struct cpio_bin_header *)h; header = (const unsigned char *)h;
archive_entry_set_dev(entry, header->c_dev[0] * 256 + header->c_dev[1]);
archive_entry_set_ino(entry, header->c_ino[0] * 256 + header->c_ino[1]); archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);
archive_entry_set_mode(entry, header->c_mode[0] * 256 + header->c_mode[1]); archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);
archive_entry_set_uid(entry, header->c_uid[0] * 256 + header->c_uid[1]); archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);
archive_entry_set_gid(entry, header->c_gid[0] * 256 + header->c_gid[1]); archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);
archive_entry_set_nlink(entry, header->c_nlink[0] * 256 + header->c_nlink[1]); archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);
archive_entry_set_rdev(entry, header->c_rdev[0] * 256 + header->c_rdev[1]); archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);
archive_entry_set_mtime(entry, be4(header->c_mtime), 0); archive_entry_set_rdev(entry, header[bin_rdev_offset] * 256 + header[bin_rdev_offset + 1]);
*namelength = header->c_namesize[0] * 256 + header->c_namesize[1]; archive_entry_set_mtime(entry, be4(header + bin_mtime_offset), 0);
*namelength = header[bin_namesize_offset] * 256 + header[bin_namesize_offset + 1];
*name_pad = *namelength & 1; /* Pad to even. */ *name_pad = *namelength & 1; /* Pad to even. */
cpio->entry_bytes_remaining = be4(header->c_filesize); cpio->entry_bytes_remaining = be4(header + bin_filesize_offset);
archive_entry_set_size(entry, cpio->entry_bytes_remaining); archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */ cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
__archive_read_consume(a, bin_header_size);
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
@ -667,7 +923,6 @@ archive_read_format_cpio_cleanup(struct archive_read *a)
free(cpio->links_head); free(cpio->links_head);
cpio->links_head = lp; cpio->links_head = lp;
} }
archive_string_free(&cpio->entry_name);
free(cpio); free(cpio);
(a->format->data) = NULL; (a->format->data) = NULL;
return (ARCHIVE_OK); return (ARCHIVE_OK);
@ -733,15 +988,16 @@ atol16(const char *p, unsigned char_cnt)
return (l); return (l);
} }
static void static int
record_hardlink(struct cpio *cpio, struct archive_entry *entry) record_hardlink(struct archive_read *a,
struct cpio *cpio, struct archive_entry *entry)
{ {
struct links_entry *le; struct links_entry *le;
dev_t dev; dev_t dev;
int64_t ino; int64_t ino;
if (archive_entry_nlink(entry) <= 1) if (archive_entry_nlink(entry) <= 1)
return; return (ARCHIVE_OK);
dev = archive_entry_dev(entry); dev = archive_entry_dev(entry);
ino = archive_entry_ino64(entry); ino = archive_entry_ino64(entry);
@ -765,13 +1021,16 @@ record_hardlink(struct cpio *cpio, struct archive_entry *entry)
free(le); free(le);
} }
return; return (ARCHIVE_OK);
} }
} }
le = (struct links_entry *)malloc(sizeof(struct links_entry)); le = (struct links_entry *)malloc(sizeof(struct links_entry));
if (le == NULL) if (le == NULL) {
__archive_errx(1, "Out of memory adding file to list"); archive_set_error(&a->archive,
ENOMEM, "Out of memory adding file to list");
return (ARCHIVE_FATAL);
}
if (cpio->links_head != NULL) if (cpio->links_head != NULL)
cpio->links_head->previous = le; cpio->links_head->previous = le;
le->next = cpio->links_head; le->next = cpio->links_head;
@ -781,6 +1040,11 @@ record_hardlink(struct cpio *cpio, struct archive_entry *entry)
le->ino = ino; le->ino = ino;
le->links = archive_entry_nlink(entry) - 1; le->links = archive_entry_nlink(entry) - 1;
le->name = strdup(archive_entry_pathname(entry)); le->name = strdup(archive_entry_pathname(entry));
if (le->name == NULL) if (le->name == NULL) {
__archive_errx(1, "Out of memory adding file to list"); archive_set_error(&a->archive,
ENOMEM, "Out of memory adding file to list");
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
} }

View File

@ -31,9 +31,9 @@ __FBSDID("$FreeBSD$");
#include "archive_private.h" #include "archive_private.h"
#include "archive_read_private.h" #include "archive_read_private.h"
static int archive_read_format_empty_bid(struct archive_read *); static int archive_read_format_empty_bid(struct archive_read *, int);
static int archive_read_format_empty_read_data(struct archive_read *, static int archive_read_format_empty_read_data(struct archive_read *,
const void **, size_t *, off_t *); const void **, size_t *, int64_t *);
static int archive_read_format_empty_read_header(struct archive_read *, static int archive_read_format_empty_read_header(struct archive_read *,
struct archive_entry *); struct archive_entry *);
int int
@ -42,6 +42,9 @@ archive_read_support_format_empty(struct archive *_a)
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
int r; int r;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_empty");
r = __archive_read_register_format(a, r = __archive_read_register_format(a,
NULL, NULL,
NULL, NULL,
@ -57,14 +60,11 @@ archive_read_support_format_empty(struct archive *_a)
static int static int
archive_read_format_empty_bid(struct archive_read *a) archive_read_format_empty_bid(struct archive_read *a, int best_bid)
{ {
ssize_t avail; if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) == NULL)
return (1);
(void)__archive_read_ahead(a, 1, &avail); return (-1);
if (avail != 0)
return (-1);
return (1);
} }
static int static int
@ -82,7 +82,7 @@ archive_read_format_empty_read_header(struct archive_read *a,
static int static int
archive_read_format_empty_read_data(struct archive_read *a, archive_read_format_empty_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset) const void **buff, size_t *size, int64_t *offset)
{ {
(void)a; /* UNUSED */ (void)a; /* UNUSED */
(void)buff; /* UNUSED */ (void)buff; /* UNUSED */

View File

@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h" #include "archive.h"
#include "archive_endian.h" #include "archive_endian.h"
#include "archive_entry.h" #include "archive_entry.h"
#include "archive_entry_locale.h"
#include "archive_private.h" #include "archive_private.h"
#include "archive_read_private.h" #include "archive_read_private.h"
#include "archive_string.h" #include "archive_string.h"
@ -285,6 +286,8 @@ struct file_info {
int64_t number; int64_t number;
int nlinks; int nlinks;
struct archive_string name; /* Pathname */ struct archive_string name; /* Pathname */
unsigned char *utf16be_name;
size_t utf16be_bytes;
char name_continues; /* Non-zero if name continues */ char name_continues; /* Non-zero if name continues */
struct archive_string symlink; struct archive_string symlink;
char symlink_continues; /* Non-zero if link continues */ char symlink_continues; /* Non-zero if link continues */
@ -357,22 +360,34 @@ struct iso9660 {
uint32_t size; uint32_t size;
} primary, joliet; } primary, joliet;
off_t entry_sparse_offset; int64_t entry_sparse_offset;
int64_t entry_bytes_remaining; int64_t entry_bytes_remaining;
size_t entry_bytes_unconsumed;
struct zisofs entry_zisofs; struct zisofs entry_zisofs;
struct content *entry_content; struct content *entry_content;
struct archive_string_conv *sconv_utf16be;
/*
* Buffers for a full pathname in UTF-16BE in Joliet extensions.
*/
#define UTF16_NAME_MAX 1024
unsigned char *utf16be_path;
size_t utf16be_path_len;
unsigned char *utf16be_previous_path;
size_t utf16be_previous_path_len;
}; };
static int archive_read_format_iso9660_bid(struct archive_read *); static int archive_read_format_iso9660_bid(struct archive_read *, int);
static int archive_read_format_iso9660_options(struct archive_read *, static int archive_read_format_iso9660_options(struct archive_read *,
const char *, const char *); const char *, const char *);
static int archive_read_format_iso9660_cleanup(struct archive_read *); static int archive_read_format_iso9660_cleanup(struct archive_read *);
static int archive_read_format_iso9660_read_data(struct archive_read *, static int archive_read_format_iso9660_read_data(struct archive_read *,
const void **, size_t *, off_t *); const void **, size_t *, int64_t *);
static int archive_read_format_iso9660_read_data_skip(struct archive_read *); static int archive_read_format_iso9660_read_data_skip(struct archive_read *);
static int archive_read_format_iso9660_read_header(struct archive_read *, static int archive_read_format_iso9660_read_header(struct archive_read *,
struct archive_entry *); struct archive_entry *);
static const char *build_pathname(struct archive_string *, struct file_info *); static const char *build_pathname(struct archive_string *, struct file_info *);
static int build_pathname_utf16be(unsigned char *, size_t, size_t *,
struct file_info *);
#if DEBUG #if DEBUG
static void dump_isodirrec(FILE *, const unsigned char *isodirrec); static void dump_isodirrec(FILE *, const unsigned char *isodirrec);
#endif #endif
@ -388,8 +403,8 @@ static int isEVD(struct iso9660 *, const unsigned char *);
static int isPVD(struct iso9660 *, const unsigned char *); static int isPVD(struct iso9660 *, const unsigned char *);
static int next_cache_entry(struct archive_read *, struct iso9660 *, static int next_cache_entry(struct archive_read *, struct iso9660 *,
struct file_info **); struct file_info **);
static int next_entry_seek(struct archive_read *a, struct iso9660 *iso9660, static int next_entry_seek(struct archive_read *, struct iso9660 *,
struct file_info **pfile); struct file_info **);
static struct file_info * static struct file_info *
parse_file_info(struct archive_read *a, parse_file_info(struct archive_read *a,
struct file_info *parent, const unsigned char *isodirrec); struct file_info *parent, const unsigned char *isodirrec);
@ -417,12 +432,12 @@ static inline struct file_info * rede_get_entry(struct file_info *);
static inline void cache_add_entry(struct iso9660 *iso9660, static inline void cache_add_entry(struct iso9660 *iso9660,
struct file_info *file); struct file_info *file);
static inline struct file_info *cache_get_entry(struct iso9660 *iso9660); static inline struct file_info *cache_get_entry(struct iso9660 *iso9660);
static void heap_add_entry(struct heap_queue *heap, static int heap_add_entry(struct archive_read *a, struct heap_queue *heap,
struct file_info *file, uint64_t key); struct file_info *file, uint64_t key);
static struct file_info *heap_get_entry(struct heap_queue *heap); static struct file_info *heap_get_entry(struct heap_queue *heap);
#define add_entry(iso9660, file) \ #define add_entry(arch, iso9660, file) \
heap_add_entry(&((iso9660)->pending_files), file, file->offset) heap_add_entry(arch, &((iso9660)->pending_files), file, file->offset)
#define next_entry(iso9660) \ #define next_entry(iso9660) \
heap_get_entry(&((iso9660)->pending_files)) heap_get_entry(&((iso9660)->pending_files))
@ -433,12 +448,15 @@ archive_read_support_format_iso9660(struct archive *_a)
struct iso9660 *iso9660; struct iso9660 *iso9660;
int r; int r;
iso9660 = (struct iso9660 *)malloc(sizeof(*iso9660)); archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_iso9660");
iso9660 = (struct iso9660 *)calloc(1, sizeof(*iso9660));
if (iso9660 == NULL) { if (iso9660 == NULL) {
archive_set_error(&a->archive, ENOMEM, "Can't allocate iso9660 data"); archive_set_error(&a->archive, ENOMEM,
"Can't allocate iso9660 data");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
memset(iso9660, 0, sizeof(*iso9660));
iso9660->magic = ISO9660_MAGIC; iso9660->magic = ISO9660_MAGIC;
iso9660->cache_files.first = NULL; iso9660->cache_files.first = NULL;
iso9660->cache_files.last = &(iso9660->cache_files.first); iso9660->cache_files.last = &(iso9660->cache_files.first);
@ -468,14 +486,18 @@ archive_read_support_format_iso9660(struct archive *_a)
static int static int
archive_read_format_iso9660_bid(struct archive_read *a) archive_read_format_iso9660_bid(struct archive_read *a, int best_bid)
{ {
struct iso9660 *iso9660; struct iso9660 *iso9660;
ssize_t bytes_read; ssize_t bytes_read;
const void *h;
const unsigned char *p; const unsigned char *p;
int seenTerminator; int seenTerminator;
/* If there's already a better bid than we can ever
make, don't bother testing. */
if (best_bid > 48)
return (-1);
iso9660 = (struct iso9660 *)(a->format->data); iso9660 = (struct iso9660 *)(a->format->data);
/* /*
@ -484,12 +506,11 @@ archive_read_format_iso9660_bid(struct archive_read *a)
* if the I/O layer gives us more, we'll take it. * if the I/O layer gives us more, we'll take it.
*/ */
#define RESERVED_AREA (SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE) #define RESERVED_AREA (SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE)
h = __archive_read_ahead(a, p = __archive_read_ahead(a,
RESERVED_AREA + 8 * LOGICAL_BLOCK_SIZE, RESERVED_AREA + 8 * LOGICAL_BLOCK_SIZE,
&bytes_read); &bytes_read);
if (h == NULL) if (p == NULL)
return (-1); return (-1);
p = (const unsigned char *)h;
/* Skip the reserved area. */ /* Skip the reserved area. */
bytes_read -= RESERVED_AREA; bytes_read -= RESERVED_AREA;
@ -505,10 +526,8 @@ archive_read_format_iso9660_bid(struct archive_read *a)
/* Standard Identifier must be "CD001" */ /* Standard Identifier must be "CD001" */
if (memcmp(p + 1, "CD001", 5) != 0) if (memcmp(p + 1, "CD001", 5) != 0)
return (0); return (0);
if (!iso9660->primary.location) { if (isPVD(iso9660, p))
if (isPVD(iso9660, p)) continue;
continue;
}
if (!iso9660->joliet.location) { if (!iso9660->joliet.location) {
if (isJolietSVD(iso9660, p)) if (isJolietSVD(iso9660, p))
continue; continue;
@ -564,7 +583,7 @@ archive_read_format_iso9660_options(struct archive_read *a,
/* Note: The "warn" return is just to inform the options /* Note: The "warn" return is just to inform the options
* supervisor that we didn't handle it. It will generate * supervisor that we didn't handle it. It will generate
* a suitable error if noone used this option. */ * a suitable error if no one used this option. */
return (ARCHIVE_WARN); return (ARCHIVE_WARN);
} }
@ -893,10 +912,10 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
return (0); return (0);
/* Reserved field must be 0. */ /* Reserved field must be 0. */
/* FreeBSD: makefs erroneously created images with 0x20 */ /* But accept NetBSD/FreeBSD "makefs" images with 0x20 here. */
for (i = 0; i < PVD_reserved4_size; ++i) for (i = 0; i < PVD_reserved4_size; ++i)
if (h[PVD_reserved4_offset + i] != 0 && if (h[PVD_reserved4_offset + i] != 0
h[PVD_reserved4_offset + i] != 32) && h[PVD_reserved4_offset + i] != 0x20)
return (0); return (0);
/* Reserved field must be 0. */ /* Reserved field must be 0. */
@ -912,11 +931,13 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
if (p[DR_length_offset] != 34) if (p[DR_length_offset] != 34)
return (0); return (0);
iso9660->logical_block_size = logical_block_size; if (!iso9660->primary.location) {
iso9660->volume_block = volume_block; iso9660->logical_block_size = logical_block_size;
iso9660->volume_size = logical_block_size * (uint64_t)volume_block; iso9660->volume_block = volume_block;
iso9660->primary.location = archive_le32dec(p + DR_extent_offset); iso9660->volume_size = logical_block_size * (uint64_t)volume_block;
iso9660->primary.size = archive_le32dec(p + DR_size_offset); iso9660->primary.location = archive_le32dec(p + DR_extent_offset);
iso9660->primary.size = archive_le32dec(p + DR_size_offset);
}
return (48); return (48);
} }
@ -927,7 +948,7 @@ read_children(struct archive_read *a, struct file_info *parent)
struct iso9660 *iso9660; struct iso9660 *iso9660;
const unsigned char *b, *p; const unsigned char *b, *p;
struct file_info *multi; struct file_info *multi;
size_t step; size_t step, skip_size;
iso9660 = (struct iso9660 *)(a->format->data); iso9660 = (struct iso9660 *)(a->format->data);
if (iso9660->current_position > parent->offset) { if (iso9660->current_position > parent->offset) {
@ -948,7 +969,7 @@ read_children(struct archive_read *a, struct file_info *parent)
int64_t skipsize; int64_t skipsize;
skipsize = parent->offset - iso9660->current_position; skipsize = parent->offset - iso9660->current_position;
skipsize = __archive_read_skip(a, skipsize); skipsize = __archive_read_consume(a, skipsize);
if (skipsize < 0) if (skipsize < 0)
return ((int)skipsize); return ((int)skipsize);
iso9660->current_position = parent->offset; iso9660->current_position = parent->offset;
@ -963,9 +984,9 @@ read_children(struct archive_read *a, struct file_info *parent)
"ISO9660 directory list"); "ISO9660 directory list");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
__archive_read_consume(a, step);
iso9660->current_position += step; iso9660->current_position += step;
multi = NULL; multi = NULL;
skip_size = step;
while (step) { while (step) {
p = b; p = b;
b += iso9660->logical_block_size; b += iso9660->logical_block_size;
@ -987,8 +1008,10 @@ read_children(struct archive_read *a, struct file_info *parent)
&& *(p + DR_name_offset) == '\001') && *(p + DR_name_offset) == '\001')
continue; continue;
child = parse_file_info(a, parent, p); child = parse_file_info(a, parent, p);
if (child == NULL) if (child == NULL) {
__archive_read_consume(a, skip_size);
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
}
if (child->cl_offset == 0 && if (child->cl_offset == 0 &&
(child->multi_extent || multi != NULL)) { (child->multi_extent || multi != NULL)) {
struct content *con; struct content *con;
@ -1003,8 +1026,8 @@ read_children(struct archive_read *a, struct file_info *parent)
if (con == NULL) { if (con == NULL) {
archive_set_error( archive_set_error(
&a->archive, ENOMEM, &a->archive, ENOMEM,
"No memory for " "No memory for multi extent");
"multi extent"); __archive_read_consume(a, skip_size);
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
con->offset = child->offset; con->offset = child->offset;
@ -1012,18 +1035,23 @@ read_children(struct archive_read *a, struct file_info *parent)
con->next = NULL; con->next = NULL;
*multi->contents.last = con; *multi->contents.last = con;
multi->contents.last = &(con->next); multi->contents.last = &(con->next);
if (multi == child) if (multi == child) {
add_entry(iso9660, child); if (add_entry(a, iso9660, child)
else { != ARCHIVE_OK)
return (ARCHIVE_FATAL);
} else {
multi->size += child->size; multi->size += child->size;
if (!child->multi_extent) if (!child->multi_extent)
multi = NULL; multi = NULL;
} }
} else } else
add_entry(iso9660, child); if (add_entry(a, iso9660, child) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
} }
} }
__archive_read_consume(a, skip_size);
/* Read data which recorded by RRIP "CE" extension. */ /* Read data which recorded by RRIP "CE" extension. */
if (read_CE(a, iso9660) != ARCHIVE_OK) if (read_CE(a, iso9660) != ARCHIVE_OK)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
@ -1061,7 +1089,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
vd = &(iso9660->joliet); vd = &(iso9660->joliet);
skipsize = LOGICAL_BLOCK_SIZE * vd->location; skipsize = LOGICAL_BLOCK_SIZE * vd->location;
skipsize = __archive_read_skip(a, skipsize); skipsize = __archive_read_consume(a, skipsize);
if (skipsize < 0) if (skipsize < 0)
return ((int)skipsize); return ((int)skipsize);
iso9660->current_position = skipsize; iso9660->current_position = skipsize;
@ -1099,7 +1127,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
vd = &(iso9660->joliet); vd = &(iso9660->joliet);
skipsize = LOGICAL_BLOCK_SIZE * vd->location; skipsize = LOGICAL_BLOCK_SIZE * vd->location;
skipsize -= iso9660->current_position; skipsize -= iso9660->current_position;
skipsize = __archive_read_skip(a, skipsize); skipsize = __archive_read_consume(a, skipsize);
if (skipsize < 0) if (skipsize < 0)
return ((int)skipsize); return ((int)skipsize);
iso9660->current_position += skipsize; iso9660->current_position += skipsize;
@ -1112,7 +1140,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
"ISO9660 directory list"); "ISO9660 directory list");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
seenJoliet = iso9660->seenJoliet;/* Save flag. */
iso9660->seenJoliet = 0; iso9660->seenJoliet = 0;
file = parse_file_info(a, NULL, block); file = parse_file_info(a, NULL, block);
if (file == NULL) if (file == NULL)
@ -1120,7 +1147,8 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
iso9660->seenJoliet = seenJoliet; iso9660->seenJoliet = seenJoliet;
} }
/* Store the root directory in the pending list. */ /* Store the root directory in the pending list. */
add_entry(iso9660, file); if (add_entry(a, iso9660, file) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
if (iso9660->seenRockridge) { if (iso9660->seenRockridge) {
a->archive.archive_format = a->archive.archive_format =
ARCHIVE_FORMAT_ISO9660_ROCKRIDGE; ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
@ -1129,17 +1157,82 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
} }
} }
file = NULL;/* Eliminate a warning. */
/* Get the next entry that appears after the current offset. */ /* Get the next entry that appears after the current offset. */
r = next_entry_seek(a, iso9660, &file); r = next_entry_seek(a, iso9660, &file);
if (r != ARCHIVE_OK) if (r != ARCHIVE_OK)
return (r); return (r);
if (iso9660->seenJoliet) {
/*
* Convert UTF-16BE of a filename to local locale MBS
* and store the result into a filename field.
*/
if (iso9660->sconv_utf16be == NULL) {
iso9660->sconv_utf16be =
archive_string_conversion_from_charset(
&(a->archive), "UTF-16BE", 1);
if (iso9660->sconv_utf16be == NULL)
/* Coundn't allocate memory */
return (ARCHIVE_FATAL);
}
if (iso9660->utf16be_path == NULL) {
iso9660->utf16be_path = malloc(UTF16_NAME_MAX);
if (iso9660->utf16be_path == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory");
return (ARCHIVE_FATAL);
}
}
if (iso9660->utf16be_previous_path == NULL) {
iso9660->utf16be_previous_path = malloc(UTF16_NAME_MAX);
if (iso9660->utf16be_previous_path == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory");
return (ARCHIVE_FATAL);
}
}
iso9660->utf16be_path_len = 0;
if (build_pathname_utf16be(iso9660->utf16be_path,
UTF16_NAME_MAX, &(iso9660->utf16be_path_len), file) != 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Pathname is too long");
}
r = archive_entry_copy_pathname_l(entry,
(const char *)iso9660->utf16be_path,
iso9660->utf16be_path_len,
iso9660->sconv_utf16be);
if (r != 0) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"No memory for Pathname");
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Pathname cannot be converted "
"from %s to current locale.",
archive_string_conversion_charset_name(
iso9660->sconv_utf16be));
rd_r = ARCHIVE_WARN;
}
} else {
archive_string_empty(&iso9660->pathname);
archive_entry_set_pathname(entry,
build_pathname(&iso9660->pathname, file));
}
iso9660->entry_bytes_remaining = file->size; iso9660->entry_bytes_remaining = file->size;
iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */ iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */
if (file->offset + file->size > iso9660->volume_size) { if (file->offset + file->size > iso9660->volume_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"File is beyond end-of-media: %s", file->name.s); "File is beyond end-of-media: %s",
archive_entry_pathname(entry));
iso9660->entry_bytes_remaining = 0; iso9660->entry_bytes_remaining = 0;
iso9660->entry_sparse_offset = 0; iso9660->entry_sparse_offset = 0;
return (ARCHIVE_WARN); return (ARCHIVE_WARN);
@ -1160,9 +1253,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
/* N.B.: Rock Ridge supports 64-bit device numbers. */ /* N.B.: Rock Ridge supports 64-bit device numbers. */
archive_entry_set_rdev(entry, (dev_t)file->rdev); archive_entry_set_rdev(entry, (dev_t)file->rdev);
archive_entry_set_size(entry, iso9660->entry_bytes_remaining); archive_entry_set_size(entry, iso9660->entry_bytes_remaining);
archive_string_empty(&iso9660->pathname);
archive_entry_set_pathname(entry,
build_pathname(&iso9660->pathname, file));
if (file->symlink.s != NULL) if (file->symlink.s != NULL)
archive_entry_copy_symlink(entry, file->symlink.s); archive_entry_copy_symlink(entry, file->symlink.s);
@ -1172,12 +1262,32 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
* original entry. */ * original entry. */
if (file->number != -1 && if (file->number != -1 &&
file->number == iso9660->previous_number) { file->number == iso9660->previous_number) {
archive_entry_set_hardlink(entry, if (iso9660->seenJoliet) {
iso9660->previous_pathname.s); r = archive_entry_copy_hardlink_l(entry,
(const char *)iso9660->utf16be_previous_path,
iso9660->utf16be_previous_path_len,
iso9660->sconv_utf16be);
if (r != 0) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"No memory for Linkname");
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Linkname cannot be converted "
"from %s to current locale.",
archive_string_conversion_charset_name(
iso9660->sconv_utf16be));
rd_r = ARCHIVE_WARN;
}
} else
archive_entry_set_hardlink(entry,
iso9660->previous_pathname.s);
archive_entry_unset_size(entry); archive_entry_unset_size(entry);
iso9660->entry_bytes_remaining = 0; iso9660->entry_bytes_remaining = 0;
iso9660->entry_sparse_offset = 0; iso9660->entry_sparse_offset = 0;
return (ARCHIVE_OK); return (rd_r);
} }
/* Except for the hardlink case above, if the offset of the /* Except for the hardlink case above, if the offset of the
@ -1198,7 +1308,8 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
if ((file->mode & AE_IFMT) != AE_IFDIR && if ((file->mode & AE_IFMT) != AE_IFDIR &&
file->offset < iso9660->current_position) { file->offset < iso9660->current_position) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Ignoring out-of-order file (%s) %jd < %jd", "Ignoring out-of-order file @%jx (%s) %jd < %jd",
(intmax_t)file->number,
iso9660->pathname.s, iso9660->pathname.s,
(intmax_t)file->offset, (intmax_t)file->offset,
(intmax_t)iso9660->current_position); (intmax_t)iso9660->current_position);
@ -1226,7 +1337,13 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
} }
iso9660->previous_number = file->number; iso9660->previous_number = file->number;
archive_strcpy(&iso9660->previous_pathname, iso9660->pathname.s); if (iso9660->seenJoliet) {
memcpy(iso9660->utf16be_previous_path, iso9660->utf16be_path,
iso9660->utf16be_path_len);
iso9660->utf16be_previous_path_len = iso9660->utf16be_path_len;
} else
archive_strcpy(
&iso9660->previous_pathname, iso9660->pathname.s);
/* Reset entry_bytes_remaining if the file is multi extent. */ /* Reset entry_bytes_remaining if the file is multi extent. */
iso9660->entry_content = file->contents.first; iso9660->entry_content = file->contents.first;
@ -1260,7 +1377,7 @@ archive_read_format_iso9660_read_data_skip(struct archive_read *a)
static int static int
zisofs_read_data(struct archive_read *a, zisofs_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset) const void **buff, size_t *size, int64_t *offset)
{ {
struct iso9660 *iso9660; struct iso9660 *iso9660;
struct zisofs *zisofs; struct zisofs *zisofs;
@ -1382,7 +1499,7 @@ zisofs_read_data(struct archive_read *a,
} }
if (!zisofs->initialized) if (!zisofs->initialized)
goto next_data; /* We need more datas. */ goto next_data; /* We need more data. */
} }
/* /*
@ -1393,21 +1510,26 @@ zisofs_read_data(struct archive_read *a,
if (zisofs->block_off + 4 >= zisofs->block_pointers_size) { if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
/* There isn't a pair of offsets. */ /* There isn't a pair of offsets. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Illegal zisofs block pointers"); "Illegal zisofs block pointers");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
bst = archive_le32dec(zisofs->block_pointers + zisofs->block_off); bst = archive_le32dec(
zisofs->block_pointers + zisofs->block_off);
if (bst != zisofs->pz_offset + (bytes_read - avail)) { if (bst != zisofs->pz_offset + (bytes_read - avail)) {
/* TODO: Should we seek offset of current file by bst ? */ /* TODO: Should we seek offset of current file
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, * by bst ? */
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Illegal zisofs block pointers(cannot seek)"); "Illegal zisofs block pointers(cannot seek)");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
bed = archive_le32dec( bed = archive_le32dec(
zisofs->block_pointers + zisofs->block_off + 4); zisofs->block_pointers + zisofs->block_off + 4);
if (bed < bst) { if (bed < bst) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Illegal zisofs block pointers"); "Illegal zisofs block pointers");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
@ -1430,7 +1552,7 @@ zisofs_read_data(struct archive_read *a,
} }
/* /*
* Make uncompressed datas. * Make uncompressed data.
*/ */
if (zisofs->block_avail == 0) { if (zisofs->block_avail == 0) {
memset(zisofs->uncompressed_buffer, 0, memset(zisofs->uncompressed_buffer, 0,
@ -1469,7 +1591,7 @@ zisofs_read_data(struct archive_read *a,
iso9660->entry_bytes_remaining -= bytes_read; iso9660->entry_bytes_remaining -= bytes_read;
iso9660->current_position += bytes_read; iso9660->current_position += bytes_read;
zisofs->pz_offset += bytes_read; zisofs->pz_offset += bytes_read;
__archive_read_consume(a, bytes_read); iso9660->entry_bytes_unconsumed += bytes_read;
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
@ -1478,7 +1600,7 @@ zisofs_read_data(struct archive_read *a,
static int static int
zisofs_read_data(struct archive_read *a, zisofs_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset) const void **buff, size_t *size, int64_t *offset)
{ {
(void)buff;/* UNUSED */ (void)buff;/* UNUSED */
@ -1493,12 +1615,18 @@ zisofs_read_data(struct archive_read *a,
static int static int
archive_read_format_iso9660_read_data(struct archive_read *a, archive_read_format_iso9660_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset) const void **buff, size_t *size, int64_t *offset)
{ {
ssize_t bytes_read; ssize_t bytes_read;
struct iso9660 *iso9660; struct iso9660 *iso9660;
iso9660 = (struct iso9660 *)(a->format->data); iso9660 = (struct iso9660 *)(a->format->data);
if (iso9660->entry_bytes_unconsumed) {
__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
iso9660->entry_bytes_unconsumed = 0;
}
if (iso9660->entry_bytes_remaining <= 0) { if (iso9660->entry_bytes_remaining <= 0) {
if (iso9660->entry_content != NULL) if (iso9660->entry_content != NULL)
iso9660->entry_content = iso9660->entry_content->next; iso9660->entry_content = iso9660->entry_content->next;
@ -1514,7 +1642,7 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
step = iso9660->entry_content->offset - step = iso9660->entry_content->offset -
iso9660->current_position; iso9660->current_position;
step = __archive_read_skip(a, step); step = __archive_read_consume(a, step);
if (step < 0) if (step < 0)
return ((int)step); return ((int)step);
iso9660->current_position = iso9660->current_position =
@ -1548,8 +1676,8 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
*offset = iso9660->entry_sparse_offset; *offset = iso9660->entry_sparse_offset;
iso9660->entry_sparse_offset += bytes_read; iso9660->entry_sparse_offset += bytes_read;
iso9660->entry_bytes_remaining -= bytes_read; iso9660->entry_bytes_remaining -= bytes_read;
iso9660->entry_bytes_unconsumed = bytes_read;
iso9660->current_position += bytes_read; iso9660->current_position += bytes_read;
__archive_read_consume(a, bytes_read);
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
@ -1577,6 +1705,8 @@ archive_read_format_iso9660_cleanup(struct archive_read *a)
} }
} }
#endif #endif
free(iso9660->utf16be_path);
free(iso9660->utf16be_previous_path);
free(iso9660); free(iso9660);
(a->format->data) = NULL; (a->format->data) = NULL;
return (r); return (r);
@ -1627,20 +1757,26 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
if (location > 0 && if (location > 0 &&
(location + ((fsize + iso9660->logical_block_size -1) (location + ((fsize + iso9660->logical_block_size -1)
/ iso9660->logical_block_size)) / iso9660->logical_block_size))
> (uint32_t)iso9660->volume_block) { > (uint32_t)iso9660->volume_block) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid location of extent of file");
return (NULL);
}
/* Sanity check that location doesn't have a negative value
* when the file is not empty. it's too large. */
if (fsize != 0 && location < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid location of extent of file"); "Invalid location of extent of file");
return (NULL); return (NULL);
} }
/* Create a new file entry and copy data from the ISO dir record. */ /* Create a new file entry and copy data from the ISO dir record. */
file = (struct file_info *)malloc(sizeof(*file)); file = (struct file_info *)calloc(1, sizeof(*file));
if (file == NULL) { if (file == NULL) {
archive_set_error(&a->archive, ENOMEM, archive_set_error(&a->archive, ENOMEM,
"No memory for file entry"); "No memory for file entry");
return (NULL); return (NULL);
} }
memset(file, 0, sizeof(*file));
file->parent = parent; file->parent = parent;
file->offset = iso9660->logical_block_size * (uint64_t)location; file->offset = iso9660->logical_block_size * (uint64_t)location;
file->size = fsize; file->size = fsize;
@ -1661,24 +1797,13 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
* names which are 103 UCS2 characters(206 bytes) by their * names which are 103 UCS2 characters(206 bytes) by their
* option '-joliet-long'. * option '-joliet-long'.
*/ */
wchar_t wbuff[103+1], *wp;
const unsigned char *c;
if (name_len > 206) if (name_len > 206)
name_len = 206; name_len = 206;
/* convert BE UTF-16 to wchar_t */ name_len &= ~1;
for (c = p, wp = wbuff;
c < (p + name_len) &&
wp < (wbuff + sizeof(wbuff)/sizeof(*wbuff) - 1);
c += 2) {
*wp++ = (((255 & (int)c[0]) << 8) | (255 & (int)c[1]));
}
*wp = L'\0';
#if 0 /* untested code, is it at all useful on Joliet? */
/* trim trailing first version and dot from filename. /* trim trailing first version and dot from filename.
* *
* Remember we where in UTF-16BE land! * Remember we were in UTF-16BE land!
* SEPARATOR 1 (.) and SEPARATOR 2 (;) are both * SEPARATOR 1 (.) and SEPARATOR 2 (;) are both
* 16 bits big endian characters on Joliet. * 16 bits big endian characters on Joliet.
* *
@ -1687,18 +1812,21 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
* *, /, :, ;, ? and \. * *, /, :, ;, ? and \.
*/ */
/* Chop off trailing ';1' from files. */ /* Chop off trailing ';1' from files. */
if (*(wp-2) == ';' && *(wp-1) == '1') { if (name_len > 4 && p[name_len-4] == 0 && p[name_len-3] == ';'
wp-=2; && p[name_len-2] == 0 && p[name_len-1] == '1')
*wp = L'\0'; name_len -= 4;
} #if 0 /* XXX: this somehow manages to strip of single-character file extensions, like '.c'. */
/* Chop off trailing '.' from filenames. */ /* Chop off trailing '.' from filenames. */
if (*(wp-1) == '.') if (name_len > 2 && p[name_len-2] == 0 && p[name_len-1] == '.')
*(--wp) = L'\0'; name_len -= 2;
#endif #endif
if ((file->utf16be_name = malloc(name_len)) == NULL) {
/* store the result in the file name field. */ archive_set_error(&a->archive, ENOMEM,
archive_strappend_w_utf8(&file->name, wbuff); "No memory for file name");
return (NULL);
}
memcpy(file->utf16be_name, p, name_len);
file->utf16be_bytes = name_len;
} else { } else {
/* Chop off trailing ';1' from files. */ /* Chop off trailing ';1' from files. */
if (name_len > 2 && p[name_len - 2] == ';' && if (name_len > 2 && p[name_len - 2] == ';' &&
@ -1721,22 +1849,24 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
else else
file->multi_extent = 0; file->multi_extent = 0;
/* /*
* Use location for file number. * Use a location for the file number, which is treated as an inode
* File number is treated as inode number to find out harlink * number to find out hardlink target. If Rockridge extensions is
* target. If Rockridge extensions is being used, file number * being used, the file number will be overwritten by FILE SERIAL
* will be overwritten by FILE SERIAL NUMBER of RRIP "PX" * NUMBER of RRIP "PX" extension.
* extension. * Note: Old mkisofs did not record that FILE SERIAL NUMBER
* NOTE: Old mkisofs did not record that FILE SERIAL NUMBER
* in ISO images. * in ISO images.
* Note2: xorriso set 0 to the location of a symlink file.
*/ */
if (file->size == 0 && location >= 0) if (file->size == 0 && location >= 0) {
/* If file->size is zero, its location points wrong place. /* If file->size is zero, its location points wrong place,
* Dot not use it for file number. * and so we should not use it for the file number.
* When location has negative value, it can be used * When the location has negative value, it can be used
* for file number. * for the file number.
*/ */
file->number = -1; file->number = -1;
else /* Do not appear before any directory entries. */
file->offset = -1;
} else
file->number = (int64_t)(uint32_t)location; file->number = (int64_t)(uint32_t)location;
/* Rockridge extensions overwrite information from above. */ /* Rockridge extensions overwrite information from above. */
@ -2123,9 +2253,13 @@ register_CE(struct archive_read *a, int32_t location,
offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size; offset = ((uint64_t)location) * (uint64_t)iso9660->logical_block_size;
if (((file->mode & AE_IFMT) == AE_IFREG && if (((file->mode & AE_IFMT) == AE_IFREG &&
offset >= file->offset) || offset >= file->offset) ||
offset < iso9660->current_position) { offset < iso9660->current_position ||
(((uint64_t)file->ce_offset) + file->ce_size)
> (uint64_t)iso9660->logical_block_size ||
offset + file->ce_offset + file->ce_size
> iso9660->volume_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid location in SUSP \"CE\" extension"); "Invalid parameter in SUSP \"CE\" extension");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
@ -2139,11 +2273,15 @@ register_CE(struct archive_read *a, int32_t location,
else else
new_size = heap->allocated * 2; new_size = heap->allocated * 2;
/* Overflow might keep us from growing the list. */ /* Overflow might keep us from growing the list. */
if (new_size <= heap->allocated) if (new_size <= heap->allocated) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
p = malloc(new_size * sizeof(p[0])); p = malloc(new_size * sizeof(p[0]));
if (p == NULL) if (p == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
if (heap->reqs != NULL) { if (heap->reqs != NULL) {
memcpy(p, heap->reqs, heap->cnt * sizeof(*p)); memcpy(p, heap->reqs, heap->cnt * sizeof(*p));
free(heap->reqs); free(heap->reqs);
@ -2164,7 +2302,7 @@ register_CE(struct archive_read *a, int32_t location,
heap->reqs[hole].file = file; heap->reqs[hole].file = file;
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
// Move parent into hole <==> move hole up tree. /* Move parent into hole <==> move hole up tree. */
heap->reqs[hole] = heap->reqs[parent]; heap->reqs[hole] = heap->reqs[parent];
hole = parent; hole = parent;
} }
@ -2191,14 +2329,14 @@ next_CE(struct read_ce_queue *heap)
/* /*
* Rebalance the heap. * Rebalance the heap.
*/ */
a = 0; // Starting element and its offset a = 0; /* Starting element and its offset */
a_offset = heap->reqs[a].offset; a_offset = heap->reqs[a].offset;
for (;;) { for (;;) {
b = a + a + 1; // First child b = a + a + 1; /* First child */
if (b >= heap->cnt) if (b >= heap->cnt)
return; return;
b_offset = heap->reqs[b].offset; b_offset = heap->reqs[b].offset;
c = b + 1; // Use second child if it is smaller. c = b + 1; /* Use second child if it is smaller. */
if (c < heap->cnt) { if (c < heap->cnt) {
c_offset = heap->reqs[c].offset; c_offset = heap->reqs[c].offset;
if (c_offset < b_offset) { if (c_offset < b_offset) {
@ -2240,6 +2378,12 @@ read_CE(struct archive_read *a, struct iso9660 *iso9660)
} }
do { do {
file = heap->reqs[0].file; file = heap->reqs[0].file;
if (file->ce_offset + file->ce_size > step) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Malformed CE information");
return (ARCHIVE_FATAL);
}
p = b + file->ce_offset; p = b + file->ce_offset;
end = p + file->ce_size; end = p + file->ce_size;
next_CE(heap); next_CE(heap);
@ -2280,12 +2424,14 @@ parse_rockridge_NM1(struct file_info *file,
case 0: case 0:
if (data_length < 2) if (data_length < 2)
return; return;
archive_strncat(&file->name, (const char *)data + 1, data_length - 1); archive_strncat(&file->name,
(const char *)data + 1, data_length - 1);
break; break;
case 1: case 1:
if (data_length < 2) if (data_length < 2)
return; return;
archive_strncat(&file->name, (const char *)data + 1, data_length - 1); archive_strncat(&file->name,
(const char *)data + 1, data_length - 1);
file->name_continues = 1; file->name_continues = 1;
break; break;
case 2: case 2:
@ -2496,6 +2642,7 @@ release_files(struct iso9660 *iso9660)
archive_string_free(&file->name); archive_string_free(&file->name);
archive_string_free(&file->symlink); archive_string_free(&file->symlink);
free(file->utf16be_name);
con = file->contents.first; con = file->contents.first;
while (con != NULL) { while (con != NULL) {
connext = con->next; connext = con->next;
@ -2523,12 +2670,19 @@ next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
if (file->size == 0) if (file->size == 0)
file->offset = iso9660->current_position; file->offset = iso9660->current_position;
/* flush any remaining bytes from the last round to ensure
* we're positioned */
if (iso9660->entry_bytes_unconsumed) {
__archive_read_consume(a, iso9660->entry_bytes_unconsumed);
iso9660->entry_bytes_unconsumed = 0;
}
/* Seek forward to the start of the entry. */ /* Seek forward to the start of the entry. */
if (iso9660->current_position < file->offset) { if (iso9660->current_position < file->offset) {
int64_t step; int64_t step;
step = file->offset - iso9660->current_position; step = file->offset - iso9660->current_position;
step = __archive_read_skip(a, step); step = __archive_read_consume(a, step);
if (step < 0) if (step < 0)
return ((int)step); return ((int)step);
iso9660->current_position = file->offset; iso9660->current_position = file->offset;
@ -2819,13 +2973,15 @@ cache_get_entry(struct iso9660 *iso9660)
if ((file = iso9660->cache_files.first) != NULL) { if ((file = iso9660->cache_files.first) != NULL) {
iso9660->cache_files.first = file->next; iso9660->cache_files.first = file->next;
if (iso9660->cache_files.first == NULL) if (iso9660->cache_files.first == NULL)
iso9660->cache_files.last = &(iso9660->cache_files.first); iso9660->cache_files.last =
&(iso9660->cache_files.first);
} }
return (file); return (file);
} }
static void static int
heap_add_entry(struct heap_queue *heap, struct file_info *file, uint64_t key) heap_add_entry(struct archive_read *a, struct heap_queue *heap,
struct file_info *file, uint64_t key)
{ {
uint64_t file_key, parent_key; uint64_t file_key, parent_key;
int hole, parent; int hole, parent;
@ -2838,12 +2994,18 @@ heap_add_entry(struct heap_queue *heap, struct file_info *file, uint64_t key)
if (heap->allocated < 1024) if (heap->allocated < 1024)
new_size = 1024; new_size = 1024;
/* Overflow might keep us from growing the list. */ /* Overflow might keep us from growing the list. */
if (new_size <= heap->allocated) if (new_size <= heap->allocated) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive,
ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
new_pending_files = (struct file_info **) new_pending_files = (struct file_info **)
malloc(new_size * sizeof(new_pending_files[0])); malloc(new_size * sizeof(new_pending_files[0]));
if (new_pending_files == NULL) if (new_pending_files == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive,
ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
memcpy(new_pending_files, heap->files, memcpy(new_pending_files, heap->files,
heap->allocated * sizeof(new_pending_files[0])); heap->allocated * sizeof(new_pending_files[0]));
if (heap->files != NULL) if (heap->files != NULL)
@ -2863,13 +3025,15 @@ heap_add_entry(struct heap_queue *heap, struct file_info *file, uint64_t key)
parent_key = heap->files[parent]->key; parent_key = heap->files[parent]->key;
if (file_key >= parent_key) { if (file_key >= parent_key) {
heap->files[hole] = file; heap->files[hole] = file;
return; return (ARCHIVE_OK);
} }
// Move parent into hole <==> move hole up tree. /* Move parent into hole <==> move hole up tree. */
heap->files[hole] = heap->files[parent]; heap->files[hole] = heap->files[parent];
hole = parent; hole = parent;
} }
heap->files[0] = file; heap->files[0] = file;
return (ARCHIVE_OK);
} }
static struct file_info * static struct file_info *
@ -2895,14 +3059,14 @@ heap_get_entry(struct heap_queue *heap)
/* /*
* Rebalance the heap. * Rebalance the heap.
*/ */
a = 0; // Starting element and its heap key a = 0; /* Starting element and its heap key */
a_key = heap->files[a]->key; a_key = heap->files[a]->key;
for (;;) { for (;;) {
b = a + a + 1; // First child b = a + a + 1; /* First child */
if (b >= heap->used) if (b >= heap->used)
return (r); return (r);
b_key = heap->files[b]->key; b_key = heap->files[b]->key;
c = b + 1; // Use second child if it is smaller. c = b + 1; /* Use second child if it is smaller. */
if (c < heap->used) { if (c < heap->used) {
c_key = heap->files[c]->key; c_key = heap->files[c]->key;
if (c_key < b_key) { if (c_key < b_key) {
@ -2980,6 +3144,8 @@ time_from_tm(struct tm *t)
#if HAVE_TIMEGM #if HAVE_TIMEGM
/* Use platform timegm() if available. */ /* Use platform timegm() if available. */
return (timegm(t)); return (timegm(t));
#elif HAVE__MKGMTIME64
return (_mkgmtime64(t));
#else #else
/* Else use direct calculation using POSIX assumptions. */ /* Else use direct calculation using POSIX assumptions. */
/* First, fix up tm_yday based on the year/month/day. */ /* First, fix up tm_yday based on the year/month/day. */
@ -3007,6 +3173,32 @@ build_pathname(struct archive_string *as, struct file_info *file)
return (as->s); return (as->s);
} }
static int
build_pathname_utf16be(unsigned char *p, size_t max, size_t *len,
struct file_info *file)
{
if (file->parent != NULL && file->parent->utf16be_bytes > 0) {
if (build_pathname_utf16be(p, max, len, file->parent) != 0)
return (-1);
p[*len] = 0;
p[*len + 1] = '/';
*len += 2;
}
if (file->utf16be_bytes == 0) {
if (*len + 2 > max)
return (-1);/* Path is too long! */
p[*len] = 0;
p[*len + 1] = '.';
*len += 2;
} else {
if (*len + file->utf16be_bytes > max)
return (-1);/* Path is too long! */
memcpy(p + *len, file->utf16be_name, file->utf16be_bytes);
*len += file->utf16be_bytes;
}
return (0);
}
#if DEBUG #if DEBUG
static void static void
dump_isodirrec(FILE *out, const unsigned char *isodirrec) dump_isodirrec(FILE *out, const unsigned char *isodirrec)
@ -3019,7 +3211,7 @@ dump_isodirrec(FILE *out, const unsigned char *isodirrec)
toi(isodirrec + DR_extent_offset, DR_extent_size)); toi(isodirrec + DR_extent_offset, DR_extent_size));
fprintf(out, " s %d,", fprintf(out, " s %d,",
toi(isodirrec + DR_size_offset, DR_extent_size)); toi(isodirrec + DR_size_offset, DR_extent_size));
fprintf(out, " f 0x%02x,", fprintf(out, " f 0x%x,",
toi(isodirrec + DR_flags_offset, DR_flags_size)); toi(isodirrec + DR_flags_offset, DR_flags_size));
fprintf(out, " u %d,", fprintf(out, " u %d,",
toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size)); toi(isodirrec + DR_file_unit_size_offset, DR_file_unit_size_size));

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
/*- /*-
* Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2008 Joerg Sonnenberger * Copyright (c) 2008 Joerg Sonnenberger
* Copyright (c) 2011 Michihiro NAKAJIMA
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -86,9 +87,8 @@ struct mtree {
struct archive_string line; struct archive_string line;
size_t buffsize; size_t buffsize;
char *buff; char *buff;
off_t offset; int64_t offset;
int fd; int fd;
int filetype;
int archive_format; int archive_format;
const char *archive_format_name; const char *archive_format_name;
struct mtree_entry *entries; struct mtree_entry *entries;
@ -98,11 +98,12 @@ struct mtree {
struct archive_entry_linkresolver *resolver; struct archive_entry_linkresolver *resolver;
off_t cur_size, cur_offset; int64_t cur_size;
}; };
static int bid_keycmp(const char *, const char *, ssize_t);
static int cleanup(struct archive_read *); static int cleanup(struct archive_read *);
static int mtree_bid(struct archive_read *); static int mtree_bid(struct archive_read *, int);
static int parse_file(struct archive_read *, struct archive_entry *, static int parse_file(struct archive_read *, struct archive_entry *,
struct mtree *, struct mtree_entry *, int *); struct mtree *, struct mtree_entry *, int *);
static void parse_escapes(char *, struct mtree_entry *); static void parse_escapes(char *, struct mtree_entry *);
@ -111,7 +112,7 @@ static int parse_line(struct archive_read *, struct archive_entry *,
static int parse_keyword(struct archive_read *, struct mtree *, static int parse_keyword(struct archive_read *, struct mtree *,
struct archive_entry *, struct mtree_option *, int *); struct archive_entry *, struct mtree_option *, int *);
static int read_data(struct archive_read *a, static int read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset); const void **buff, size_t *size, int64_t *offset);
static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t); static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t);
static int skip(struct archive_read *a); static int skip(struct archive_read *a);
static int read_header(struct archive_read *, static int read_header(struct archive_read *,
@ -120,6 +121,53 @@ static int64_t mtree_atol10(char **);
static int64_t mtree_atol8(char **); static int64_t mtree_atol8(char **);
static int64_t mtree_atol(char **); static int64_t mtree_atol(char **);
/*
* There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them
* here. TODO: Move this to configure time, but be careful
* about cross-compile environments.
*/
static int64_t
get_time_t_max(void)
{
#if defined(TIME_T_MAX)
return TIME_T_MAX;
#else
static time_t t;
time_t a;
if (t == 0) {
a = 1;
while (a > t) {
t = a;
a = a * 2 + 1;
}
}
return t;
#endif
}
static int64_t
get_time_t_min(void)
{
#if defined(TIME_T_MIN)
return TIME_T_MIN;
#else
/* 't' will hold the minimum value, which will be zero (if
* time_t is unsigned) or -2^n (if time_t is signed). */
static int computed;
static time_t t;
time_t a;
if (computed == 0) {
a = (time_t)-1;
while (a < t) {
t = a;
a = a * 2;
}
computed = 1;
}
return t;
#endif
}
static void static void
free_options(struct mtree_option *head) free_options(struct mtree_option *head)
{ {
@ -139,6 +187,9 @@ archive_read_support_format_mtree(struct archive *_a)
struct mtree *mtree; struct mtree *mtree;
int r; int r;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_mtree");
mtree = (struct mtree *)malloc(sizeof(*mtree)); mtree = (struct mtree *)malloc(sizeof(*mtree));
if (mtree == NULL) { if (mtree == NULL) {
archive_set_error(&a->archive, ENOMEM, archive_set_error(&a->archive, ENOMEM,
@ -183,20 +234,389 @@ cleanup(struct archive_read *a)
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
static ssize_t
get_line_size(const char *b, ssize_t avail, ssize_t *nlsize)
{
ssize_t len;
len = 0;
while (len < avail) {
switch (*b) {
case '\0':/* Non-ascii character or control character. */
if (nlsize != NULL)
*nlsize = 0;
return (-1);
case '\r':
if (avail-len > 1 && b[1] == '\n') {
if (nlsize != NULL)
*nlsize = 2;
return (len+2);
}
/* FALL THROUGH */
case '\n':
if (nlsize != NULL)
*nlsize = 1;
return (len+1);
default:
b++;
len++;
break;
}
}
if (nlsize != NULL)
*nlsize = 0;
return (avail);
}
static ssize_t
next_line(struct archive_read *a,
const char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)
{
ssize_t len;
int quit;
quit = 0;
if (*avail == 0) {
*nl = 0;
len = 0;
} else
len = get_line_size(*b, *avail, nl);
/*
* Read bytes more while it does not reach the end of line.
*/
while (*nl == 0 && len == *avail && !quit) {
ssize_t diff = *ravail - *avail;
size_t nbytes_req = (*ravail+1023) & ~1023U;
ssize_t tested;
/* Increase reading bytes if it is not enough to at least
* new two lines. */
if (nbytes_req < (size_t)*ravail + 160)
nbytes_req <<= 1;
*b = __archive_read_ahead(a, nbytes_req, avail);
if (*b == NULL) {
if (*ravail >= *avail)
return (0);
/* Reading bytes reaches the end of file. */
*b = __archive_read_ahead(a, *avail, avail);
quit = 1;
}
*ravail = *avail;
*b += diff;
*avail -= diff;
tested = len;/* Skip some bytes we already determinated. */
len = get_line_size(*b, *avail, nl);
if (len >= 0)
len += tested;
}
return (len);
}
/*
* Compare characters with a mtree keyword.
* Returns the length of a mtree keyword if matched.
* Returns 0 if not matched.
*/
static int
bid_keycmp(const char *p, const char *key, ssize_t len)
{
int match_len = 0;
while (len > 0 && *p && *key) {
if (*p == *key) {
--len;
++p;
++key;
++match_len;
continue;
}
return (0);/* Not match */
}
if (*key != '\0')
return (0);/* Not match */
/* A following character should be specified characters */
if (p[0] == '=' || p[0] == ' ' || p[0] == '\t' ||
p[0] == '\n' || p[0] == '\r' ||
(p[0] == '\\' && (p[1] == '\n' || p[1] == '\r')))
return (match_len);
return (0);/* Not match */
}
/*
* Test whether the characters 'p' has is mtree keyword.
* Returns the length of a detected keyword.
* Returns 0 if any keywords were not found.
*/
static ssize_t
bid_keyword(const char *p, ssize_t len)
{
static const char *keys_c[] = {
"content", "contents", "cksum", NULL
};
static const char *keys_df[] = {
"device", "flags", NULL
};
static const char *keys_g[] = {
"gid", "gname", NULL
};
static const char *keys_il[] = {
"ignore", "link", NULL
};
static const char *keys_m[] = {
"md5", "md5digest", "mode", NULL
};
static const char *keys_no[] = {
"nlink", "optional", NULL
};
static const char *keys_r[] = {
"rmd160", "rmd160digest", NULL
};
static const char *keys_s[] = {
"sha1", "sha1digest",
"sha256", "sha256digest",
"sha384", "sha384digest",
"sha512", "sha512digest",
"size", NULL
};
static const char *keys_t[] = {
"tags", "time", "type", NULL
};
static const char *keys_u[] = {
"uid", "uname", NULL
};
const char **keys;
int i;
switch (*p) {
case 'c': keys = keys_c; break;
case 'd': case 'f': keys = keys_df; break;
case 'g': keys = keys_g; break;
case 'i': case 'l': keys = keys_il; break;
case 'm': keys = keys_m; break;
case 'n': case 'o': keys = keys_no; break;
case 'r': keys = keys_r; break;
case 's': keys = keys_s; break;
case 't': keys = keys_t; break;
case 'u': keys = keys_u; break;
default: return (0);/* Unknown key */
}
for (i = 0; keys[i] != NULL; i++) {
int l = bid_keycmp(p, keys[i], len);
if (l > 0)
return (l);
}
return (0);/* Unknown key */
}
/*
* Test whether there is a set of mtree keywords.
* Returns the number of keyword.
* Returns -1 if we got incorrect sequence.
* This function expects a set of "<space characters>keyword=value".
* When "unset" is specified, expects a set of "<space characters>keyword".
*/
static int
bid_keyword_list(const char *p, ssize_t len, int unset)
{
int l;
int keycnt = 0;
while (len > 0 && *p) {
int blank = 0;
/* Test whether there are blank characters in the line. */
while (len >0 && (*p == ' ' || *p == '\t')) {
++p;
--len;
blank = 1;
}
if (*p == '\n' || *p == '\r')
break;
if (p[0] == '\\' && (p[1] == '\n' || p[1] == '\r'))
break;
if (!blank) /* No blank character. */
return (-1);
if (unset) {
l = bid_keycmp(p, "all", len);
if (l > 0)
return (1);
}
/* Test whether there is a correct key in the line. */
l = bid_keyword(p, len);
if (l == 0)
return (-1);/* Unknown keyword was found. */
p += l;
len -= l;
keycnt++;
/* Skip value */
if (*p == '=') {
int value = 0;
++p;
--len;
while (len > 0 && *p != ' ' && *p != '\t') {
++p;
--len;
value = 1;
}
/* A keyword should have a its value unless
* "/unset" operation. */
if (!unset && value == 0)
return (-1);
}
}
return (keycnt);
}
static int static int
mtree_bid(struct archive_read *a) bid_entry(const char *p, ssize_t len)
{
int f = 0;
static const unsigned char safe_char[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 0F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 1F */
/* !"$%&'()*+,-./ EXCLUSION:( )(#) */
0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
/* 0123456789:;<>? EXCLUSION:(=) */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, /* 30 - 3F */
/* @ABCDEFGHIJKLMNO */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
/* PQRSTUVWXYZ[\]^_ */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
/* `abcdefghijklmno */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
/* pqrstuvwxyz{|}~ */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* 70 - 7F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
};
/*
* Skip the path-name which is quoted.
*/
while (len > 0 && *p != ' ' && *p != '\t') {
if (!safe_char[*(const unsigned char *)p])
return (-1);
++p;
--len;
++f;
}
/* If a path-name was not found, returns error. */
if (f == 0)
return (-1);
return (bid_keyword_list(p, len, 0));
}
#define MAX_BID_ENTRY 3
static int
mtree_bid(struct archive_read *a, int best_bid)
{ {
const char *signature = "#mtree"; const char *signature = "#mtree";
const char *p; const char *p;
ssize_t avail, ravail;
ssize_t len, nl;
int detected_bytes = 0, entry_cnt = 0, multiline = 0;
(void)best_bid; /* UNUSED */
/* Now let's look at the actual header and see if it matches. */ /* Now let's look at the actual header and see if it matches. */
p = __archive_read_ahead(a, strlen(signature), NULL); p = __archive_read_ahead(a, strlen(signature), &avail);
if (p == NULL) if (p == NULL)
return (-1); return (-1);
if (strncmp(p, signature, strlen(signature)) == 0) if (memcmp(p, signature, strlen(signature)) == 0)
return (8 * (int)strlen(signature)); return (8 * (int)strlen(signature));
/*
* There is not a mtree signature. Let's try to detect mtree format.
*/
ravail = avail;
for (;;) {
len = next_line(a, &p, &avail, &ravail, &nl);
/* The terminal character of the line should be
* a new line character, '\r\n' or '\n'. */
if (len <= 0 || nl == 0)
break;
if (!multiline) {
/* Leading whitespace is never significant,
* ignore it. */
while (len > 0 && (*p == ' ' || *p == '\t')) {
++p;
--avail;
--len;
}
/* Skip comment or empty line. */
if (p[0] == '#' || p[0] == '\n' || p[0] == '\r') {
p += len;
avail -= len;
continue;
}
} else {
/* A continuance line; the terminal
* character of previous line was '\' character. */
if (bid_keyword_list(p, len, 0) <= 0)
break;
if (multiline == 1)
detected_bytes += len;
if (p[len-nl-1] != '\\') {
if (multiline == 1 &&
++entry_cnt >= MAX_BID_ENTRY)
break;
multiline = 0;
}
p += len;
avail -= len;
continue;
}
if (p[0] != '/') {
if (bid_entry(p, len) >= 0) {
detected_bytes += len;
if (p[len-nl-1] == '\\')
/* This line continues. */
multiline = 1;
else {
/* We've got plenty of correct lines
* to assume that this file is a mtree
* format. */
if (++entry_cnt >= MAX_BID_ENTRY)
break;
}
} else
break;
} else if (strncmp(p, "/set", 4) == 0) {
if (bid_keyword_list(p+4, len-4, 0) <= 0)
break;
/* This line continues. */
if (p[len-nl-1] == '\\')
multiline = 2;
} else if (strncmp(p, "/unset", 6) == 0) {
if (bid_keyword_list(p+6, len-6, 1) <= 0)
break;
/* This line continues. */
if (p[len-nl-1] == '\\')
multiline = 2;
} else
break;
/* Test next line. */
p += len;
avail -= len;
}
if (entry_cnt >= MAX_BID_ENTRY || (entry_cnt > 0 && len == 0))
return (32);
return (0); return (0);
} }
@ -215,21 +635,21 @@ static int
add_option(struct archive_read *a, struct mtree_option **global, add_option(struct archive_read *a, struct mtree_option **global,
const char *value, size_t len) const char *value, size_t len)
{ {
struct mtree_option *option; struct mtree_option *opt;
if ((option = malloc(sizeof(*option))) == NULL) { if ((opt = malloc(sizeof(*opt))) == NULL) {
archive_set_error(&a->archive, errno, "Can't allocate memory"); archive_set_error(&a->archive, errno, "Can't allocate memory");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
if ((option->value = malloc(len + 1)) == NULL) { if ((opt->value = malloc(len + 1)) == NULL) {
free(option); free(opt);
archive_set_error(&a->archive, errno, "Can't allocate memory"); archive_set_error(&a->archive, errno, "Can't allocate memory");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
memcpy(option->value, value, len); memcpy(opt->value, value, len);
option->value[len] = '\0'; opt->value[len] = '\0';
option->next = *global; opt->next = *global;
*global = option; *global = opt;
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
@ -400,7 +820,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
last_entry = NULL; last_entry = NULL;
for (counter = 1; ; ++counter) { for (counter = 1; ; ++counter) {
len = readline(a, mtree, &p, 256); len = readline(a, mtree, &p, 65536);
if (len == 0) { if (len == 0) {
mtree->this_entry = mtree->entries; mtree->this_entry = mtree->entries;
free_options(global); free_options(global);
@ -518,12 +938,12 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
struct stat st_storage, *st; struct stat st_storage, *st;
struct mtree_entry *mp; struct mtree_entry *mp;
struct archive_entry *sparse_entry; struct archive_entry *sparse_entry;
int r = ARCHIVE_OK, r1, parsed_kws, mismatched_type; int r = ARCHIVE_OK, r1, parsed_kws;
mentry->used = 1; mentry->used = 1;
/* Initialize reasonable defaults. */ /* Initialize reasonable defaults. */
mtree->filetype = AE_IFREG; archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_set_size(entry, 0); archive_entry_set_size(entry, 0);
archive_string_empty(&mtree->contents_name); archive_string_empty(&mtree->contents_name);
@ -618,44 +1038,49 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
* the type of the contents object on disk. * the type of the contents object on disk.
*/ */
if (st != NULL) { if (st != NULL) {
mismatched_type = 0; if (
if ((st->st_mode & S_IFMT) == S_IFREG && ((st->st_mode & S_IFMT) == S_IFREG &&
archive_entry_filetype(entry) != AE_IFREG) archive_entry_filetype(entry) == AE_IFREG)
mismatched_type = 1; #ifdef S_IFLNK
if ((st->st_mode & S_IFMT) == S_IFLNK && || ((st->st_mode & S_IFMT) == S_IFLNK &&
archive_entry_filetype(entry) != AE_IFLNK) archive_entry_filetype(entry) == AE_IFLNK)
mismatched_type = 1; #endif
if ((st->st_mode & S_IFSOCK) == S_IFSOCK && #ifdef S_IFSOCK
archive_entry_filetype(entry) != AE_IFSOCK) || ((st->st_mode & S_IFSOCK) == S_IFSOCK &&
mismatched_type = 1; archive_entry_filetype(entry) == AE_IFSOCK)
if ((st->st_mode & S_IFMT) == S_IFCHR && #endif
archive_entry_filetype(entry) != AE_IFCHR) #ifdef S_IFCHR
mismatched_type = 1; || ((st->st_mode & S_IFMT) == S_IFCHR &&
if ((st->st_mode & S_IFMT) == S_IFBLK && archive_entry_filetype(entry) == AE_IFCHR)
archive_entry_filetype(entry) != AE_IFBLK) #endif
mismatched_type = 1; #ifdef S_IFBLK
if ((st->st_mode & S_IFMT) == S_IFDIR && || ((st->st_mode & S_IFMT) == S_IFBLK &&
archive_entry_filetype(entry) != AE_IFDIR) archive_entry_filetype(entry) == AE_IFBLK)
mismatched_type = 1; #endif
if ((st->st_mode & S_IFMT) == S_IFIFO && || ((st->st_mode & S_IFMT) == S_IFDIR &&
archive_entry_filetype(entry) != AE_IFIFO) archive_entry_filetype(entry) == AE_IFDIR)
mismatched_type = 1; #ifdef S_IFIFO
|| ((st->st_mode & S_IFMT) == S_IFIFO &&
if (mismatched_type) { archive_entry_filetype(entry) == AE_IFIFO)
if ((parsed_kws & MTREE_HAS_OPTIONAL) == 0) { #endif
) {
/* Types match. */
} else {
/* Types don't match; bail out gracefully. */
if (mtree->fd >= 0)
close(mtree->fd);
mtree->fd = -1;
if (parsed_kws & MTREE_HAS_OPTIONAL) {
/* It's not an error for an optional entry
to not match disk. */
*use_next = 1;
} else if (r == ARCHIVE_OK) {
archive_set_error(&a->archive, archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC, ARCHIVE_ERRNO_MISC,
"mtree specification has different type for %s", "mtree specification has different type for %s",
archive_entry_pathname(entry)); archive_entry_pathname(entry));
r = ARCHIVE_WARN; r = ARCHIVE_WARN;
} else {
*use_next = 1;
} }
/* Don't hold a non-regular file open. */
if (mtree->fd >= 0)
close(mtree->fd);
mtree->fd = -1;
st = NULL;
return r; return r;
} }
} }
@ -735,7 +1160,7 @@ parse_line(struct archive_read *a, struct archive_entry *entry,
if (r1 < r) if (r1 < r)
r = r1; r = r1;
} }
if ((*parsed_kws & MTREE_HAS_TYPE) == 0) { if (r == ARCHIVE_OK && (*parsed_kws & MTREE_HAS_TYPE) == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Missing type keyword in mtree specification"); "Missing type keyword in mtree specification");
return (ARCHIVE_WARN); return (ARCHIVE_WARN);
@ -779,11 +1204,11 @@ parse_device(struct archive *a, struct archive_entry *entry, char *val)
*/ */
static int static int
parse_keyword(struct archive_read *a, struct mtree *mtree, parse_keyword(struct archive_read *a, struct mtree *mtree,
struct archive_entry *entry, struct mtree_option *option, int *parsed_kws) struct archive_entry *entry, struct mtree_option *opt, int *parsed_kws)
{ {
char *val, *key; char *val, *key;
key = option->value; key = opt->value;
if (*key == '\0') if (*key == '\0')
return (ARCHIVE_OK); return (ARCHIVE_OK);
@ -900,58 +1325,67 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
break; break;
} }
if (strcmp(key, "time") == 0) { if (strcmp(key, "time") == 0) {
time_t m; int64_t m;
int64_t my_time_t_max = get_time_t_max();
int64_t my_time_t_min = get_time_t_min();
long ns; long ns;
*parsed_kws |= MTREE_HAS_MTIME; *parsed_kws |= MTREE_HAS_MTIME;
m = (time_t)mtree_atol10(&val); m = mtree_atol10(&val);
/* Replicate an old mtree bug:
* 123456789.1 represents 123456789
* seconds and 1 nanosecond. */
if (*val == '.') { if (*val == '.') {
++val; ++val;
ns = (long)mtree_atol10(&val); ns = (long)mtree_atol10(&val);
} else } else
ns = 0; ns = 0;
archive_entry_set_mtime(entry, m, ns); if (m > my_time_t_max)
m = my_time_t_max;
else if (m < my_time_t_min)
m = my_time_t_min;
archive_entry_set_mtime(entry, (time_t)m, ns);
break; break;
} }
if (strcmp(key, "type") == 0) { if (strcmp(key, "type") == 0) {
*parsed_kws |= MTREE_HAS_TYPE;
switch (val[0]) { switch (val[0]) {
case 'b': case 'b':
if (strcmp(val, "block") == 0) { if (strcmp(val, "block") == 0) {
mtree->filetype = AE_IFBLK; archive_entry_set_filetype(entry, AE_IFBLK);
break; break;
} }
case 'c': case 'c':
if (strcmp(val, "char") == 0) { if (strcmp(val, "char") == 0) {
mtree->filetype = AE_IFCHR; archive_entry_set_filetype(entry, AE_IFCHR);
break; break;
} }
case 'd': case 'd':
if (strcmp(val, "dir") == 0) { if (strcmp(val, "dir") == 0) {
mtree->filetype = AE_IFDIR; archive_entry_set_filetype(entry, AE_IFDIR);
break; break;
} }
case 'f': case 'f':
if (strcmp(val, "fifo") == 0) { if (strcmp(val, "fifo") == 0) {
mtree->filetype = AE_IFIFO; archive_entry_set_filetype(entry, AE_IFIFO);
break; break;
} }
if (strcmp(val, "file") == 0) { if (strcmp(val, "file") == 0) {
mtree->filetype = AE_IFREG; archive_entry_set_filetype(entry, AE_IFREG);
break; break;
} }
case 'l': case 'l':
if (strcmp(val, "link") == 0) { if (strcmp(val, "link") == 0) {
mtree->filetype = AE_IFLNK; archive_entry_set_filetype(entry, AE_IFLNK);
break; break;
} }
default: default:
archive_set_error(&a->archive, archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized file type \"%s\"", val); "Unrecognized file type \"%s\"; assuming \"file\"", val);
archive_entry_set_filetype(entry, AE_IFREG);
return (ARCHIVE_WARN); return (ARCHIVE_WARN);
} }
archive_entry_set_filetype(entry, mtree->filetype); *parsed_kws |= MTREE_HAS_TYPE;
break; break;
} }
case 'u': case 'u':
@ -974,7 +1408,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
} }
static int static int
read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset) read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset)
{ {
size_t bytes_to_read; size_t bytes_to_read;
ssize_t bytes_read; ssize_t bytes_read;
@ -999,7 +1433,7 @@ read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset
*buff = mtree->buff; *buff = mtree->buff;
*offset = mtree->offset; *offset = mtree->offset;
if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset) if ((int64_t)mtree->buffsize > mtree->cur_size - mtree->offset)
bytes_to_read = mtree->cur_size - mtree->offset; bytes_to_read = mtree->cur_size - mtree->offset;
else else
bytes_to_read = mtree->buffsize; bytes_to_read = mtree->buffsize;
@ -1147,28 +1581,43 @@ mtree_atol10(char **p)
int base, digit, sign; int base, digit, sign;
base = 10; base = 10;
limit = INT64_MAX / base;
last_digit_limit = INT64_MAX % base;
if (**p == '-') { if (**p == '-') {
sign = -1; sign = -1;
limit = ((uint64_t)(INT64_MAX) + 1) / base;
last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
++(*p); ++(*p);
} else } else {
sign = 1; sign = 1;
limit = INT64_MAX / base;
last_digit_limit = INT64_MAX % base;
}
l = 0; l = 0;
digit = **p - '0'; digit = **p - '0';
while (digit >= 0 && digit < base) { while (digit >= 0 && digit < base) {
if (l > limit || (l == limit && digit > last_digit_limit)) { if (l > limit || (l == limit && digit > last_digit_limit))
l = INT64_MAX; /* Truncate on overflow. */ return (sign < 0) ? INT64_MIN : INT64_MAX;
break;
}
l = (l * base) + digit; l = (l * base) + digit;
digit = *++(*p) - '0'; digit = *++(*p) - '0';
} }
return (sign < 0) ? -l : l; return (sign < 0) ? -l : l;
} }
/* Parse a hex digit. */
static int
parsehex(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a';
else if (c >= 'A' && c <= 'F')
return c - 'A';
else
return -1;
}
/* /*
* Note that this implementation does not (and should not!) obey * Note that this implementation does not (and should not!) obey
* locale settings; you cannot simply substitute strtol here, since * locale settings; you cannot simply substitute strtol here, since
@ -1181,38 +1630,25 @@ mtree_atol16(char **p)
int base, digit, sign; int base, digit, sign;
base = 16; base = 16;
limit = INT64_MAX / base;
last_digit_limit = INT64_MAX % base;
if (**p == '-') { if (**p == '-') {
sign = -1; sign = -1;
limit = ((uint64_t)(INT64_MAX) + 1) / base;
last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
++(*p); ++(*p);
} else } else {
sign = 1; sign = 1;
limit = INT64_MAX / base;
last_digit_limit = INT64_MAX % base;
}
l = 0; l = 0;
if (**p >= '0' && **p <= '9') digit = parsehex(**p);
digit = **p - '0';
else if (**p >= 'a' && **p <= 'f')
digit = **p - 'a' + 10;
else if (**p >= 'A' && **p <= 'F')
digit = **p - 'A' + 10;
else
digit = -1;
while (digit >= 0 && digit < base) { while (digit >= 0 && digit < base) {
if (l > limit || (l == limit && digit > last_digit_limit)) { if (l > limit || (l == limit && digit > last_digit_limit))
l = INT64_MAX; /* Truncate on overflow. */ return (sign < 0) ? INT64_MIN : INT64_MAX;
break;
}
l = (l * base) + digit; l = (l * base) + digit;
if (**p >= '0' && **p <= '9') digit = parsehex(*++(*p));
digit = **p - '0';
else if (**p >= 'a' && **p <= 'f')
digit = **p - 'a' + 10;
else if (**p >= 'A' && **p <= 'F')
digit = **p - 'A' + 10;
else
digit = -1;
} }
return (sign < 0) ? -l : l; return (sign < 0) ? -l : l;
} }

File diff suppressed because it is too large Load Diff

View File

@ -40,13 +40,14 @@ __FBSDID("$FreeBSD$");
struct raw_info { struct raw_info {
int64_t offset; /* Current position in the file. */ int64_t offset; /* Current position in the file. */
int64_t unconsumed;
int end_of_file; int end_of_file;
}; };
static int archive_read_format_raw_bid(struct archive_read *); static int archive_read_format_raw_bid(struct archive_read *, int);
static int archive_read_format_raw_cleanup(struct archive_read *); static int archive_read_format_raw_cleanup(struct archive_read *);
static int archive_read_format_raw_read_data(struct archive_read *, static int archive_read_format_raw_read_data(struct archive_read *,
const void **, size_t *, off_t *); const void **, size_t *, int64_t *);
static int archive_read_format_raw_read_data_skip(struct archive_read *); static int archive_read_format_raw_read_data_skip(struct archive_read *);
static int archive_read_format_raw_read_header(struct archive_read *, static int archive_read_format_raw_read_header(struct archive_read *,
struct archive_entry *); struct archive_entry *);
@ -58,6 +59,9 @@ archive_read_support_format_raw(struct archive *_a)
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
int r; int r;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_raw");
info = (struct raw_info *)calloc(1, sizeof(*info)); info = (struct raw_info *)calloc(1, sizeof(*info));
if (info == NULL) { if (info == NULL) {
archive_set_error(&a->archive, ENOMEM, archive_set_error(&a->archive, ENOMEM,
@ -87,12 +91,11 @@ archive_read_support_format_raw(struct archive *_a)
* include "raw" as part of support_format_all(). * include "raw" as part of support_format_all().
*/ */
static int static int
archive_read_format_raw_bid(struct archive_read *a) archive_read_format_raw_bid(struct archive_read *a, int best_bid)
{ {
if (best_bid < 1 && __archive_read_ahead(a, 1, NULL) != NULL)
if (__archive_read_ahead(a, 1, NULL) == NULL) return (1);
return (-1); return (-1);
return (1);
} }
/* /*
@ -109,32 +112,40 @@ archive_read_format_raw_read_header(struct archive_read *a,
return (ARCHIVE_EOF); return (ARCHIVE_EOF);
a->archive.archive_format = ARCHIVE_FORMAT_RAW; a->archive.archive_format = ARCHIVE_FORMAT_RAW;
a->archive.archive_format_name = "Raw data"; a->archive.archive_format_name = "raw";
archive_entry_set_pathname(entry, "data"); archive_entry_set_pathname(entry, "data");
/* XXX should we set mode to mimic a regular file? XXX */ archive_entry_set_filetype(entry, AE_IFREG);
archive_entry_set_perm(entry, 0644);
/* I'm deliberately leaving most fields unset here. */ /* I'm deliberately leaving most fields unset here. */
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
static int static int
archive_read_format_raw_read_data(struct archive_read *a, archive_read_format_raw_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset) const void **buff, size_t *size, int64_t *offset)
{ {
struct raw_info *info; struct raw_info *info;
ssize_t avail; ssize_t avail;
info = (struct raw_info *)(a->format->data); info = (struct raw_info *)(a->format->data);
/* Consume the bytes we read last time. */
if (info->unconsumed) {
__archive_read_consume(a, info->unconsumed);
info->unconsumed = 0;
}
if (info->end_of_file) if (info->end_of_file)
return (ARCHIVE_EOF); return (ARCHIVE_EOF);
/* Get whatever bytes are immediately available. */ /* Get whatever bytes are immediately available. */
*buff = __archive_read_ahead(a, 1, &avail); *buff = __archive_read_ahead(a, 1, &avail);
if (avail > 0) { if (avail > 0) {
/* Consume and return the bytes we just read */ /* Return the bytes we just read */
__archive_read_consume(a, avail);
*size = avail; *size = avail;
*offset = info->offset; *offset = info->offset;
info->offset += *size; info->offset += *size;
info->unconsumed = avail;
return (ARCHIVE_OK); return (ARCHIVE_OK);
} else if (0 == avail) { } else if (0 == avail) {
/* Record and return end-of-file. */ /* Record and return end-of-file. */
@ -153,24 +164,15 @@ archive_read_format_raw_read_data(struct archive_read *a,
static int static int
archive_read_format_raw_read_data_skip(struct archive_read *a) archive_read_format_raw_read_data_skip(struct archive_read *a)
{ {
struct raw_info *info; struct raw_info *info = (struct raw_info *)(a->format->data);
off_t bytes_skipped;
int64_t request = 1024 * 1024 * 1024UL; /* Skip 1 GB at a time. */
info = (struct raw_info *)(a->format->data); /* Consume the bytes we read last time. */
if (info->end_of_file) if (info->unconsumed) {
return (ARCHIVE_EOF); __archive_read_consume(a, info->unconsumed);
info->end_of_file = 1; info->unconsumed = 0;
for (;;) {
bytes_skipped = __archive_read_skip_lenient(a, request);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
if (bytes_skipped < request)
return (ARCHIVE_OK);
/* We skipped all the bytes we asked for. There might
* be more, so try again. */
} }
info->end_of_file = 1;
return (ARCHIVE_OK);
} }
static int static int

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_ERRNO_H #ifdef HAVE_ERRNO_H
#include <errno.h> #include <errno.h>
#endif #endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H #ifdef HAVE_STDLIB_H
#include <stdlib.h> #include <stdlib.h>
#endif #endif
@ -52,9 +51,10 @@ __FBSDID("$FreeBSD$");
#endif #endif
#include "archive.h" #include "archive.h"
#include "archive_crypto_private.h"
#include "archive_endian.h" #include "archive_endian.h"
#include "archive_entry.h" #include "archive_entry.h"
#include "archive_hash.h" #include "archive_entry_locale.h"
#include "archive_private.h" #include "archive_private.h"
#include "archive_read_private.h" #include "archive_read_private.h"
@ -74,6 +74,8 @@ int
archive_read_support_format_xar(struct archive *_a) archive_read_support_format_xar(struct archive *_a)
{ {
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_xar");
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Xar not supported on this platform"); "Xar not supported on this platform");
@ -82,8 +84,8 @@ archive_read_support_format_xar(struct archive *_a)
#else /* Support xar format */ #else /* Support xar format */
//#define DEBUG 1 /* #define DEBUG 1 */
//#define DEBUG_PRINT_TOC 1 /* #define DEBUG_PRINT_TOC 1 */
#if DEBUG_PRINT_TOC #if DEBUG_PRINT_TOC
#define PRINT_TOC(d, outbytes) do { \ #define PRINT_TOC(d, outbytes) do { \
unsigned char *x = (unsigned char *)(uintptr_t)d; \ unsigned char *x = (unsigned char *)(uintptr_t)d; \
@ -303,7 +305,8 @@ struct xar {
int64_t total; int64_t total;
uint64_t h_base; uint64_t h_base;
int end_of_file; int end_of_file;
unsigned char buff[1024*32]; #define OUTBUFF_SIZE (1024 * 64)
unsigned char *outbuff;
enum xmlstatus xmlsts; enum xmlstatus xmlsts;
enum xmlstatus xmlsts_unknown; enum xmlstatus xmlsts_unknown;
@ -350,10 +353,13 @@ struct xar {
int entry_init; int entry_init;
uint64_t entry_total; uint64_t entry_total;
uint64_t entry_remaining; uint64_t entry_remaining;
size_t entry_unconsumed;
uint64_t entry_size; uint64_t entry_size;
enum enctype entry_encoding; enum enctype entry_encoding;
struct chksumval entry_a_sum; struct chksumval entry_a_sum;
struct chksumval entry_e_sum; struct chksumval entry_e_sum;
struct archive_string_conv *sconv;
}; };
struct xmlattr { struct xmlattr {
@ -367,11 +373,11 @@ struct xmlattr_list {
struct xmlattr **last; struct xmlattr **last;
}; };
static int xar_bid(struct archive_read *); static int xar_bid(struct archive_read *, int);
static int xar_read_header(struct archive_read *, static int xar_read_header(struct archive_read *,
struct archive_entry *); struct archive_entry *);
static int xar_read_data(struct archive_read *, static int xar_read_data(struct archive_read *,
const void **, size_t *, off_t *); const void **, size_t *, int64_t *);
static int xar_read_data_skip(struct archive_read *); static int xar_read_data_skip(struct archive_read *);
static int xar_cleanup(struct archive_read *); static int xar_cleanup(struct archive_read *);
static int move_reading_point(struct archive_read *, uint64_t); static int move_reading_point(struct archive_read *, uint64_t);
@ -383,9 +389,11 @@ static uint64_t atol10(const char *, size_t);
static int64_t atol8(const char *, size_t); static int64_t atol8(const char *, size_t);
static size_t atohex(unsigned char *, size_t, const char *, size_t); static size_t atohex(unsigned char *, size_t, const char *, size_t);
static time_t parse_time(const char *p, size_t n); static time_t parse_time(const char *p, size_t n);
static void heap_add_entry(struct heap_queue *, struct xar_file *); static int heap_add_entry(struct archive_read *a,
struct heap_queue *, struct xar_file *);
static struct xar_file *heap_get_entry(struct heap_queue *); static struct xar_file *heap_get_entry(struct heap_queue *);
static void add_link(struct xar *, struct xar_file *); static int add_link(struct archive_read *,
struct xar *, struct xar_file *);
static void checksum_init(struct archive_read *, int, int); static void checksum_init(struct archive_read *, int, int);
static void checksum_update(struct archive_read *, const void *, static void checksum_update(struct archive_read *, const void *,
size_t, const void *, size_t); size_t, const void *, size_t);
@ -396,28 +404,38 @@ static int decompress(struct archive_read *, const void **,
size_t *, const void *, size_t *); size_t *, const void *, size_t *);
static int decompression_cleanup(struct archive_read *); static int decompression_cleanup(struct archive_read *);
static void xmlattr_cleanup(struct xmlattr_list *); static void xmlattr_cleanup(struct xmlattr_list *);
static void file_new(struct xar *, struct xmlattr_list *); static int file_new(struct archive_read *,
struct xar *, struct xmlattr_list *);
static void file_free(struct xar_file *); static void file_free(struct xar_file *);
static void xattr_new(struct xar *, struct xmlattr_list *); static int xattr_new(struct archive_read *,
struct xar *, struct xmlattr_list *);
static void xattr_free(struct xattr *); static void xattr_free(struct xattr *);
static int getencoding(struct xmlattr_list *); static int getencoding(struct xmlattr_list *);
static int getsumalgorithm(struct xmlattr_list *); static int getsumalgorithm(struct xmlattr_list *);
static void unknowntag_start(struct xar *, const char *); static int unknowntag_start(struct archive_read *,
struct xar *, const char *);
static void unknowntag_end(struct xar *, const char *); static void unknowntag_end(struct xar *, const char *);
static void xml_start(void *, const char *, struct xmlattr_list *); static int xml_start(struct archive_read *,
const char *, struct xmlattr_list *);
static void xml_end(void *, const char *); static void xml_end(void *, const char *);
static void xml_data(void *, const char *, int); static void xml_data(void *, const char *, int);
static int xml_parse_file_flags(struct xar *, const char *); static int xml_parse_file_flags(struct xar *, const char *);
static int xml_parse_file_ext2(struct xar *, const char *); static int xml_parse_file_ext2(struct xar *, const char *);
#if defined(HAVE_LIBXML_XMLREADER_H) #if defined(HAVE_LIBXML_XMLREADER_H)
static int xml2_xmlattr_setup(struct xmlattr_list *, xmlTextReaderPtr); static int xml2_xmlattr_setup(struct archive_read *,
struct xmlattr_list *, xmlTextReaderPtr);
static int xml2_read_cb(void *, char *, int); static int xml2_read_cb(void *, char *, int);
static int xml2_close_cb(void *); static int xml2_close_cb(void *);
static void xml2_error_hdr(void *, const char *, xmlParserSeverities, static void xml2_error_hdr(void *, const char *, xmlParserSeverities,
xmlTextReaderLocatorPtr); xmlTextReaderLocatorPtr);
static int xml2_read_toc(struct archive_read *); static int xml2_read_toc(struct archive_read *);
#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) #elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
static void expat_xmlattr_setup(struct xmlattr_list *, const XML_Char **); struct expat_userData {
int state;
struct archive_read *archive;
};
static int expat_xmlattr_setup(struct archive_read *,
struct xmlattr_list *, const XML_Char **);
static void expat_start_cb(void *, const XML_Char *, const XML_Char **); static void expat_start_cb(void *, const XML_Char *, const XML_Char **);
static void expat_end_cb(void *, const XML_Char *); static void expat_end_cb(void *, const XML_Char *);
static void expat_data_cb(void *, const XML_Char *, int); static void expat_data_cb(void *, const XML_Char *, int);
@ -431,6 +449,9 @@ archive_read_support_format_xar(struct archive *_a)
struct archive_read *a = (struct archive_read *)_a; struct archive_read *a = (struct archive_read *)_a;
int r; int r;
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_xar");
xar = (struct xar *)calloc(1, sizeof(*xar)); xar = (struct xar *)calloc(1, sizeof(*xar));
if (xar == NULL) { if (xar == NULL) {
archive_set_error(&a->archive, ENOMEM, archive_set_error(&a->archive, ENOMEM,
@ -453,11 +474,13 @@ archive_read_support_format_xar(struct archive *_a)
} }
static int static int
xar_bid(struct archive_read *a) xar_bid(struct archive_read *a, int best_bid)
{ {
const unsigned char *b; const unsigned char *b;
int bid; int bid;
(void)best_bid; /* UNUSED */
b = __archive_read_ahead(a, HEADER_SIZE, NULL); b = __archive_read_ahead(a, HEADER_SIZE, NULL);
if (b == NULL) if (b == NULL)
return (-1); return (-1);
@ -638,8 +661,17 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
int r; int r;
xar = (struct xar *)(a->format->data); xar = (struct xar *)(a->format->data);
r = ARCHIVE_OK;
if (xar->offset == 0) { if (xar->offset == 0) {
/* Create a character conversion object. */
if (xar->sconv == NULL) {
xar->sconv = archive_string_conversion_from_charset(
&(a->archive), "UTF-8", 1);
if (xar->sconv == NULL)
return (ARCHIVE_FATAL);
}
/* Read TOC. */ /* Read TOC. */
r = read_toc(a); r = read_toc(a);
if (r != ARCHIVE_OK) if (r != ARCHIVE_OK)
@ -666,15 +698,65 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
archive_entry_set_ctime(entry, file->ctime, 0); archive_entry_set_ctime(entry, file->ctime, 0);
archive_entry_set_mtime(entry, file->mtime, 0); archive_entry_set_mtime(entry, file->mtime, 0);
archive_entry_set_gid(entry, file->gid); archive_entry_set_gid(entry, file->gid);
if (file->gname.length > 0) if (file->gname.length > 0 &&
archive_entry_update_gname_utf8(entry, file->gname.s); archive_entry_copy_gname_l(entry, file->gname.s,
archive_strlen(&(file->gname)), xar->sconv) != 0) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Gname");
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Gname cannot be converted from %s to current locale.",
archive_string_conversion_charset_name(xar->sconv));
r = ARCHIVE_WARN;
}
archive_entry_set_uid(entry, file->uid); archive_entry_set_uid(entry, file->uid);
if (file->uname.length > 0) if (file->uname.length > 0 &&
archive_entry_update_uname_utf8(entry, file->uname.s); archive_entry_copy_uname_l(entry, file->uname.s,
archive_strlen(&(file->uname)), xar->sconv) != 0) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Uname");
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Uname cannot be converted from %s to current locale.",
archive_string_conversion_charset_name(xar->sconv));
r = ARCHIVE_WARN;
}
archive_entry_set_mode(entry, file->mode); archive_entry_set_mode(entry, file->mode);
archive_entry_update_pathname_utf8(entry, file->pathname.s); if (archive_entry_copy_pathname_l(entry, file->pathname.s,
if (file->symlink.length > 0) archive_strlen(&(file->pathname)), xar->sconv) != 0) {
archive_entry_update_symlink_utf8(entry, file->symlink.s); if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Pathname");
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Pathname cannot be converted from %s to current locale.",
archive_string_conversion_charset_name(xar->sconv));
r = ARCHIVE_WARN;
}
if (file->symlink.length > 0 &&
archive_entry_copy_symlink_l(entry, file->symlink.s,
archive_strlen(&(file->symlink)), xar->sconv) != 0) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Linkname");
return (ARCHIVE_FATAL);
}
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Linkname cannot be converted from %s to current locale.",
archive_string_conversion_charset_name(xar->sconv));
r = ARCHIVE_WARN;
}
/* Set proper nlink. */ /* Set proper nlink. */
if ((file->mode & AE_IFMT) == AE_IFDIR) if ((file->mode & AE_IFMT) == AE_IFDIR)
archive_entry_set_nlink(entry, file->subdirs + 2); archive_entry_set_nlink(entry, file->subdirs + 2);
@ -682,8 +764,7 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
archive_entry_set_nlink(entry, file->nlink); archive_entry_set_nlink(entry, file->nlink);
archive_entry_set_size(entry, file->size); archive_entry_set_size(entry, file->size);
if (archive_strlen(&(file->hardlink)) > 0) if (archive_strlen(&(file->hardlink)) > 0)
archive_entry_update_hardlink_utf8(entry, archive_entry_set_hardlink(entry, file->hardlink.s);
file->hardlink.s);
archive_entry_set_ino64(entry, file->ino64); archive_entry_set_ino64(entry, file->ino64);
if (file->has & HAS_DEV) if (file->has & HAS_DEV)
archive_entry_set_dev(entry, file->dev); archive_entry_set_dev(entry, file->dev);
@ -704,7 +785,6 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
/* /*
* Read extended attributes. * Read extended attributes.
*/ */
r = ARCHIVE_OK;
xattr = file->xattr_list; xattr = file->xattr_list;
while (xattr != NULL) { while (xattr != NULL) {
const void *d; const void *d;
@ -754,13 +834,19 @@ xar_read_header(struct archive_read *a, struct archive_entry *entry)
static int static int
xar_read_data(struct archive_read *a, xar_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset) const void **buff, size_t *size, int64_t *offset)
{ {
struct xar *xar; struct xar *xar;
size_t used; size_t used;
int r; int r;
xar = (struct xar *)(a->format->data); xar = (struct xar *)(a->format->data);
if (xar->entry_unconsumed) {
__archive_read_consume(a, xar->entry_unconsumed);
xar->entry_unconsumed = 0;
}
if (xar->end_of_file || xar->entry_remaining <= 0) { if (xar->end_of_file || xar->entry_remaining <= 0) {
r = ARCHIVE_EOF; r = ARCHIVE_EOF;
goto abort_read_data; goto abort_read_data;
@ -786,7 +872,7 @@ xar_read_data(struct archive_read *a,
xar->total += *size; xar->total += *size;
xar->offset += used; xar->offset += used;
xar->entry_remaining -= used; xar->entry_remaining -= used;
__archive_read_consume(a, used); xar->entry_unconsumed = used;
if (xar->entry_remaining == 0) { if (xar->entry_remaining == 0) {
if (xar->entry_total != xar->entry_size) { if (xar->entry_total != xar->entry_size) {
@ -819,10 +905,12 @@ xar_read_data_skip(struct archive_read *a)
xar = (struct xar *)(a->format->data); xar = (struct xar *)(a->format->data);
if (xar->end_of_file) if (xar->end_of_file)
return (ARCHIVE_EOF); return (ARCHIVE_EOF);
bytes_skipped = __archive_read_skip(a, xar->entry_remaining); bytes_skipped = __archive_read_consume(a, xar->entry_remaining +
xar->entry_unconsumed);
if (bytes_skipped < 0) if (bytes_skipped < 0)
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
xar->offset += bytes_skipped; xar->offset += bytes_skipped;
xar->entry_unconsumed = 0;
return (ARCHIVE_OK); return (ARCHIVE_OK);
} }
@ -853,6 +941,7 @@ xar_cleanup(struct archive_read *a)
archive_string_free(&(tag->name)); archive_string_free(&(tag->name));
free(tag); free(tag);
} }
free(xar->outbuff);
free(xar); free(xar);
a->format->data = NULL; a->format->data = NULL;
return (r); return (r);
@ -870,7 +959,7 @@ move_reading_point(struct archive_read *a, uint64_t offset)
step = offset - (xar->offset - xar->h_base); step = offset - (xar->offset - xar->h_base);
if (step > 0) { if (step > 0) {
step = __archive_read_skip(a, step); step = __archive_read_consume(a, step);
if (step < 0) if (step < 0)
return ((int)step); return ((int)step);
xar->offset += step; xar->offset += step;
@ -1011,6 +1100,8 @@ time_from_tm(struct tm *t)
#if HAVE_TIMEGM #if HAVE_TIMEGM
/* Use platform timegm() if available. */ /* Use platform timegm() if available. */
return (timegm(t)); return (timegm(t));
#elif HAVE__MKGMTIME64
return (_mkgmtime64(t));
#else #else
/* Else use direct calculation using POSIX assumptions. */ /* Else use direct calculation using POSIX assumptions. */
/* First, fix up tm_yday based on the year/month/day. */ /* First, fix up tm_yday based on the year/month/day. */
@ -1084,8 +1175,9 @@ parse_time(const char *p, size_t n)
return (t); return (t);
} }
static void static int
heap_add_entry(struct heap_queue *heap, struct xar_file *file) heap_add_entry(struct archive_read *a,
struct heap_queue *heap, struct xar_file *file)
{ {
uint64_t file_id, parent_id; uint64_t file_id, parent_id;
int hole, parent; int hole, parent;
@ -1098,12 +1190,18 @@ heap_add_entry(struct heap_queue *heap, struct xar_file *file)
if (heap->allocated < 1024) if (heap->allocated < 1024)
new_size = 1024; new_size = 1024;
/* Overflow might keep us from growing the list. */ /* Overflow might keep us from growing the list. */
if (new_size <= heap->allocated) if (new_size <= heap->allocated) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive,
ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
new_pending_files = (struct xar_file **) new_pending_files = (struct xar_file **)
malloc(new_size * sizeof(new_pending_files[0])); malloc(new_size * sizeof(new_pending_files[0]));
if (new_pending_files == NULL) if (new_pending_files == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive,
ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
memcpy(new_pending_files, heap->files, memcpy(new_pending_files, heap->files,
heap->allocated * sizeof(new_pending_files[0])); heap->allocated * sizeof(new_pending_files[0]));
if (heap->files != NULL) if (heap->files != NULL)
@ -1123,13 +1221,15 @@ heap_add_entry(struct heap_queue *heap, struct xar_file *file)
parent_id = heap->files[parent]->id; parent_id = heap->files[parent]->id;
if (file_id >= parent_id) { if (file_id >= parent_id) {
heap->files[hole] = file; heap->files[hole] = file;
return; return (ARCHIVE_OK);
} }
// Move parent into hole <==> move hole up tree. /* Move parent into hole <==> move hole up tree. */
heap->files[hole] = heap->files[parent]; heap->files[hole] = heap->files[parent];
hole = parent; hole = parent;
} }
heap->files[0] = file; heap->files[0] = file;
return (ARCHIVE_OK);
} }
static struct xar_file * static struct xar_file *
@ -1155,14 +1255,14 @@ heap_get_entry(struct heap_queue *heap)
/* /*
* Rebalance the heap. * Rebalance the heap.
*/ */
a = 0; // Starting element and its heap key a = 0; /* Starting element and its heap key */
a_id = heap->files[a]->id; a_id = heap->files[a]->id;
for (;;) { for (;;) {
b = a + a + 1; // First child b = a + a + 1; /* First child */
if (b >= heap->used) if (b >= heap->used)
return (r); return (r);
b_id = heap->files[b]->id; b_id = heap->files[b]->id;
c = b + 1; // Use second child if it is smaller. c = b + 1; /* Use second child if it is smaller. */
if (c < heap->used) { if (c < heap->used) {
c_id = heap->files[c]->id; c_id = heap->files[c]->id;
if (c_id < b_id) { if (c_id < b_id) {
@ -1179,8 +1279,8 @@ heap_get_entry(struct heap_queue *heap)
} }
} }
static void static int
add_link(struct xar *xar, struct xar_file *file) add_link(struct archive_read *a, struct xar *xar, struct xar_file *file)
{ {
struct hdlink *hdlink; struct hdlink *hdlink;
@ -1189,18 +1289,21 @@ add_link(struct xar *xar, struct xar_file *file)
file->hdnext = hdlink->files; file->hdnext = hdlink->files;
hdlink->cnt++; hdlink->cnt++;
hdlink->files = file; hdlink->files = file;
return; return (ARCHIVE_OK);
} }
} }
hdlink = malloc(sizeof(*hdlink)); hdlink = malloc(sizeof(*hdlink));
if (hdlink == NULL) if (hdlink == NULL) {
__archive_errx(1, "No memory for add_link()"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
file->hdnext = NULL; file->hdnext = NULL;
hdlink->id = file->link; hdlink->id = file->link;
hdlink->cnt = 1; hdlink->cnt = 1;
hdlink->files = file; hdlink->files = file;
hdlink->next = xar->hdlink_list; hdlink->next = xar->hdlink_list;
xar->hdlink_list = hdlink; xar->hdlink_list = hdlink;
return (ARCHIVE_OK);
} }
static void static void
@ -1362,6 +1465,13 @@ decompression_init(struct archive_read *a, enum enctype encoding)
break; break;
#endif #endif
#if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA) #if defined(HAVE_LZMA_H) && defined(HAVE_LIBLZMA)
#if LZMA_VERSION_MAJOR >= 5
/* Effectively disable the limiter. */
#define LZMA_MEMLIMIT UINT64_MAX
#else
/* NOTE: This needs to check memory size which running system has. */
#define LZMA_MEMLIMIT (1U << 30)
#endif
case XZ: case XZ:
case LZMA: case LZMA:
if (xar->lzstream_valid) { if (xar->lzstream_valid) {
@ -1370,11 +1480,11 @@ decompression_init(struct archive_read *a, enum enctype encoding)
} }
if (xar->entry_encoding == XZ) if (xar->entry_encoding == XZ)
r = lzma_stream_decoder(&(xar->lzstream), r = lzma_stream_decoder(&(xar->lzstream),
(1U << 30),/* memlimit */ LZMA_MEMLIMIT,/* memlimit */
LZMA_CONCATENATED); LZMA_CONCATENATED);
else else
r = lzma_alone_decoder(&(xar->lzstream), r = lzma_alone_decoder(&(xar->lzstream),
(1U << 30));/* memlimit */ LZMA_MEMLIMIT);/* memlimit */
if (r != LZMA_OK) { if (r != LZMA_OK) {
switch (r) { switch (r) {
case LZMA_MEM_ERROR: case LZMA_MEM_ERROR:
@ -1473,9 +1583,17 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,
avail_in = *used; avail_in = *used;
outbuff = (void *)(uintptr_t)*buff; outbuff = (void *)(uintptr_t)*buff;
if (outbuff == NULL) { if (outbuff == NULL) {
outbuff = xar->buff; if (xar->outbuff == NULL) {
xar->outbuff = malloc(OUTBUFF_SIZE);
if (xar->outbuff == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Couldn't allocate memory for out buffer");
return (ARCHIVE_FATAL);
}
}
outbuff = xar->outbuff;
*buff = outbuff; *buff = outbuff;
avail_out = sizeof(xar->buff); avail_out = OUTBUFF_SIZE;
} else } else
avail_out = *outbytes; avail_out = *outbytes;
switch (xar->rd_encoding) { switch (xar->rd_encoding) {
@ -1599,7 +1717,7 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,
#endif #endif
case NONE: case NONE:
default: default:
if (outbuff == xar->buff) { if (outbuff == xar->outbuff) {
*buff = b; *buff = b;
*used = avail_in; *used = avail_in;
*outbytes = avail_in; *outbytes = avail_in;
@ -1674,15 +1792,17 @@ xmlattr_cleanup(struct xmlattr_list *list)
list->last = &(list->first); list->last = &(list->first);
} }
static void static int
file_new(struct xar *xar, struct xmlattr_list *list) file_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
{ {
struct xar_file *file; struct xar_file *file;
struct xmlattr *attr; struct xmlattr *attr;
file = calloc(1, sizeof(*file)); file = calloc(1, sizeof(*file));
if (file == NULL) if (file == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
file->parent = xar->file; file->parent = xar->file;
file->mode = 0777 | AE_IFREG; file->mode = 0777 | AE_IFREG;
file->atime = time(NULL); file->atime = time(NULL);
@ -1694,7 +1814,9 @@ file_new(struct xar *xar, struct xmlattr_list *list)
file->id = atol10(attr->value, strlen(attr->value)); file->id = atol10(attr->value, strlen(attr->value));
} }
file->nlink = 1; file->nlink = 1;
heap_add_entry(&(xar->file_queue), file); if (heap_add_entry(a, &(xar->file_queue), file) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
return (ARCHIVE_OK);
} }
static void static void
@ -1719,15 +1841,17 @@ file_free(struct xar_file *file)
free(file); free(file);
} }
static void static int
xattr_new(struct xar *xar, struct xmlattr_list *list) xattr_new(struct archive_read *a, struct xar *xar, struct xmlattr_list *list)
{ {
struct xattr *xattr, **nx; struct xattr *xattr, **nx;
struct xmlattr *attr; struct xmlattr *attr;
xattr = calloc(1, sizeof(*xattr)); xattr = calloc(1, sizeof(*xattr));
if (xattr == NULL) if (xattr == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
xar->xattr = xattr; xar->xattr = xattr;
for (attr = list->first; attr != NULL; attr = attr->next) { for (attr = list->first; attr != NULL; attr = attr->next) {
if (strcmp(attr->name, "id") == 0) if (strcmp(attr->name, "id") == 0)
@ -1741,6 +1865,8 @@ xattr_new(struct xar *xar, struct xmlattr_list *list)
} }
xattr->next = *nx; xattr->next = *nx;
*nx = xattr; *nx = xattr;
return (ARCHIVE_OK);
} }
static void static void
@ -1796,8 +1922,8 @@ getsumalgorithm(struct xmlattr_list *list)
return (alg); return (alg);
} }
static void static int
unknowntag_start(struct xar *xar, const char *name) unknowntag_start(struct archive_read *a, struct xar *xar, const char *name)
{ {
struct unknown_tag *tag; struct unknown_tag *tag;
@ -1805,8 +1931,10 @@ unknowntag_start(struct xar *xar, const char *name)
fprintf(stderr, "unknowntag_start:%s\n", name); fprintf(stderr, "unknowntag_start:%s\n", name);
#endif #endif
tag = malloc(sizeof(*tag)); tag = malloc(sizeof(*tag));
if (tag == NULL) if (tag == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
tag->next = xar->unknowntags; tag->next = xar->unknowntags;
archive_string_init(&(tag->name)); archive_string_init(&(tag->name));
archive_strcpy(&(tag->name), name); archive_strcpy(&(tag->name), name);
@ -1815,6 +1943,7 @@ unknowntag_start(struct xar *xar, const char *name)
xar->xmlsts = UNKNOWN; xar->xmlsts = UNKNOWN;
} }
xar->unknowntags = tag; xar->unknowntags = tag;
return (ARCHIVE_OK);
} }
static void static void
@ -1837,14 +1966,12 @@ unknowntag_end(struct xar *xar, const char *name)
} }
} }
static void static int
xml_start(void *userData, const char *name, struct xmlattr_list *list) xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
{ {
struct archive_read *a;
struct xar *xar; struct xar *xar;
struct xmlattr *attr; struct xmlattr *attr;
a = (struct archive_read *)userData;
xar = (struct xar *)(a->format->data); xar = (struct xar *)(a->format->data);
#if DEBUG #if DEBUG
@ -1859,13 +1986,15 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
if (strcmp(name, "xar") == 0) if (strcmp(name, "xar") == 0)
xar->xmlsts = XAR; xar->xmlsts = XAR;
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case XAR: case XAR:
if (strcmp(name, "toc") == 0) if (strcmp(name, "toc") == 0)
xar->xmlsts = TOC; xar->xmlsts = TOC;
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case TOC: case TOC:
if (strcmp(name, "creation-time") == 0) if (strcmp(name, "creation-time") == 0)
@ -1873,11 +2002,13 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
else if (strcmp(name, "checksum") == 0) else if (strcmp(name, "checksum") == 0)
xar->xmlsts = TOC_CHECKSUM; xar->xmlsts = TOC_CHECKSUM;
else if (strcmp(name, "file") == 0) { else if (strcmp(name, "file") == 0) {
file_new(xar, list); if (file_new(a, xar, list) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
xar->xmlsts = TOC_FILE; xar->xmlsts = TOC_FILE;
} }
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case TOC_CHECKSUM: case TOC_CHECKSUM:
if (strcmp(name, "offset") == 0) if (strcmp(name, "offset") == 0)
@ -1885,16 +2016,19 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
else if (strcmp(name, "size") == 0) else if (strcmp(name, "size") == 0)
xar->xmlsts = TOC_CHECKSUM_SIZE; xar->xmlsts = TOC_CHECKSUM_SIZE;
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case TOC_FILE: case TOC_FILE:
if (strcmp(name, "file") == 0) { if (strcmp(name, "file") == 0) {
file_new(xar, list); if (file_new(a, xar, list) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
} }
else if (strcmp(name, "data") == 0) else if (strcmp(name, "data") == 0)
xar->xmlsts = FILE_DATA; xar->xmlsts = FILE_DATA;
else if (strcmp(name, "ea") == 0) { else if (strcmp(name, "ea") == 0) {
xattr_new(xar, list); if (xattr_new(a, xar, list) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
xar->xmlsts = FILE_EA; xar->xmlsts = FILE_EA;
} }
else if (strcmp(name, "ctime") == 0) else if (strcmp(name, "ctime") == 0)
@ -1934,7 +2068,9 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
xar->file->link = atol10(attr->value, xar->file->link = atol10(attr->value,
strlen(attr->value)); strlen(attr->value));
if (xar->file->link > 0) if (xar->file->link > 0)
add_link(xar, xar->file); if (add_link(a, xar, xar->file) != ARCHIVE_OK) {
return (ARCHIVE_FATAL);
};
} }
} }
} }
@ -1954,7 +2090,8 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
else if (strcmp(name, "ext2") == 0) else if (strcmp(name, "ext2") == 0)
xar->xmlsts = FILE_EXT2; xar->xmlsts = FILE_EXT2;
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case FILE_DATA: case FILE_DATA:
if (strcmp(name, "length") == 0) if (strcmp(name, "length") == 0)
@ -1978,7 +2115,8 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
else if (strcmp(name, "content") == 0) else if (strcmp(name, "content") == 0)
xar->xmlsts = FILE_DATA_CONTENT; xar->xmlsts = FILE_DATA_CONTENT;
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case FILE_DEVICE: case FILE_DEVICE:
if (strcmp(name, "major") == 0) if (strcmp(name, "major") == 0)
@ -1986,10 +2124,12 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
else if (strcmp(name, "minor") == 0) else if (strcmp(name, "minor") == 0)
xar->xmlsts = FILE_DEVICE_MINOR; xar->xmlsts = FILE_DEVICE_MINOR;
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case FILE_DATA_CONTENT: case FILE_DATA_CONTENT:
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case FILE_EA: case FILE_EA:
if (strcmp(name, "length") == 0) if (strcmp(name, "length") == 0)
@ -2010,7 +2150,8 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
else if (strcmp(name, "fstype") == 0) else if (strcmp(name, "fstype") == 0)
xar->xmlsts = FILE_EA_FSTYPE; xar->xmlsts = FILE_EA_FSTYPE;
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case FILE_ACL: case FILE_ACL:
if (strcmp(name, "appleextended") == 0) if (strcmp(name, "appleextended") == 0)
@ -2020,15 +2161,18 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
else if (strcmp(name, "access") == 0) else if (strcmp(name, "access") == 0)
xar->xmlsts = FILE_ACL_ACCESS; xar->xmlsts = FILE_ACL_ACCESS;
else else
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case FILE_FLAGS: case FILE_FLAGS:
if (!xml_parse_file_flags(xar, name)) if (!xml_parse_file_flags(xar, name))
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case FILE_EXT2: case FILE_EXT2:
if (!xml_parse_file_ext2(xar, name)) if (!xml_parse_file_ext2(xar, name))
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
case TOC_CREATION_TIME: case TOC_CREATION_TIME:
case TOC_CHECKSUM_OFFSET: case TOC_CHECKSUM_OFFSET:
@ -2096,9 +2240,11 @@ xml_start(void *userData, const char *name, struct xmlattr_list *list)
case FILE_EXT2_TopDir: case FILE_EXT2_TopDir:
case FILE_EXT2_Reserved: case FILE_EXT2_Reserved:
case UNKNOWN: case UNKNOWN:
unknowntag_start(xar, name); if (unknowntag_start(a, xar, name) != ARCHIVE_OK)
return (ARCHIVE_FATAL);
break; break;
} }
return (ARCHIVE_OK);
} }
static void static void
@ -2470,13 +2616,15 @@ static const int base64[256] = {
}; };
static void static void
strappend_base64(struct archive_string *as, const char *s, size_t l) strappend_base64(struct xar *xar,
struct archive_string *as, const char *s, size_t l)
{ {
unsigned char buff[256]; unsigned char buff[256];
unsigned char *out; unsigned char *out;
const unsigned char *b; const unsigned char *b;
size_t len; size_t len;
(void)xar; /* UNUSED */
len = 0; len = 0;
out = buff; out = buff;
b = (const unsigned char *)s; b = (const unsigned char *)s;
@ -2530,8 +2678,8 @@ xml_data(void *userData, const char *s, int len)
#if DEBUG #if DEBUG
{ {
char buff[1024]; char buff[1024];
if (len > (int)sizeof(buff)-1) if (len > sizeof(buff)-1)
len = (int)sizeof(buff)-1; len = sizeof(buff)-1;
memcpy(buff, s, len); memcpy(buff, s, len);
buff[len] = 0; buff[len] = 0;
fprintf(stderr, "\tlen=%d:\"%s\"\n", len, buff); fprintf(stderr, "\tlen=%d:\"%s\"\n", len, buff);
@ -2558,9 +2706,10 @@ xml_data(void *userData, const char *s, int len)
archive_strappend_char(&(xar->file->pathname), '/'); archive_strappend_char(&(xar->file->pathname), '/');
} }
xar->file->has |= HAS_PATHNAME; xar->file->has |= HAS_PATHNAME;
if (xar->base64text) if (xar->base64text) {
strappend_base64(&(xar->file->pathname), s, len); strappend_base64(xar,
else &(xar->file->pathname), s, len);
} else
archive_strncat(&(xar->file->pathname), s, len); archive_strncat(&(xar->file->pathname), s, len);
break; break;
case FILE_LINK: case FILE_LINK:
@ -2909,7 +3058,8 @@ xml_parse_file_ext2(struct xar *xar, const char *name)
#ifdef HAVE_LIBXML_XMLREADER_H #ifdef HAVE_LIBXML_XMLREADER_H
static int static int
xml2_xmlattr_setup(struct xmlattr_list *list, xmlTextReaderPtr reader) xml2_xmlattr_setup(struct archive_read *a,
struct xmlattr_list *list, xmlTextReaderPtr reader)
{ {
struct xmlattr *attr; struct xmlattr *attr;
int r; int r;
@ -2919,16 +3069,22 @@ xml2_xmlattr_setup(struct xmlattr_list *list, xmlTextReaderPtr reader)
r = xmlTextReaderMoveToFirstAttribute(reader); r = xmlTextReaderMoveToFirstAttribute(reader);
while (r == 1) { while (r == 1) {
attr = malloc(sizeof*(attr)); attr = malloc(sizeof*(attr));
if (attr == NULL) if (attr == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
attr->name = strdup( attr->name = strdup(
(const char *)xmlTextReaderConstLocalName(reader)); (const char *)xmlTextReaderConstLocalName(reader));
if (attr->name == NULL) if (attr->name == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
attr->value = strdup( attr->value = strdup(
(const char *)xmlTextReaderConstValue(reader)); (const char *)xmlTextReaderConstValue(reader));
if (attr->value == NULL) if (attr->value == NULL) {
__archive_errx(1, "Out of memory"); archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
attr->next = NULL; attr->next = NULL;
*list->last = attr; *list->last = attr;
list->last = &(attr->next); list->last = &(attr->next);
@ -3020,13 +3176,15 @@ xml2_read_toc(struct archive_read *a)
switch (type) { switch (type) {
case XML_READER_TYPE_ELEMENT: case XML_READER_TYPE_ELEMENT:
empty = xmlTextReaderIsEmptyElement(reader); empty = xmlTextReaderIsEmptyElement(reader);
r = xml2_xmlattr_setup(&list, reader); r = xml2_xmlattr_setup(a, &list, reader);
if (r == 0) { if (r != ARCHIVE_OK)
xml_start(a, name, &list); return (r);
xmlattr_cleanup(&list); r = xml_start(a, name, &list);
if (empty) xmlattr_cleanup(&list);
xml_end(a, name); if (r != ARCHIVE_OK)
} return (r);
if (empty)
xml_end(a, name);
break; break;
case XML_READER_TYPE_END_ELEMENT: case XML_READER_TYPE_END_ELEMENT:
xml_end(a, name); xml_end(a, name);
@ -3050,52 +3208,64 @@ xml2_read_toc(struct archive_read *a)
#elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) #elif defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H)
static void static int
expat_xmlattr_setup(struct xmlattr_list *list, const XML_Char **atts) expat_xmlattr_setup(struct archive_read *a,
struct xmlattr_list *list, const XML_Char **atts)
{ {
struct xmlattr *attr; struct xmlattr *attr;
char *name, *value;
list->first = NULL; list->first = NULL;
list->last = &(list->first); list->last = &(list->first);
if (atts == NULL) if (atts == NULL)
return; return (ARCHIVE_OK);
while (atts[0] != NULL && atts[1] != NULL) { while (atts[0] != NULL && atts[1] != NULL) {
attr = malloc(sizeof*(attr)); attr = malloc(sizeof*(attr));
if (attr == NULL) name = strdup(atts[0]);
__archive_errx(1, "Out of memory"); value = strdup(atts[1]);
attr->name = strdup(atts[0]); if (attr == NULL || name == NULL || value == NULL) {
if (attr->name == NULL) archive_set_error(&a->archive, ENOMEM, "Out of memory");
__archive_errx(1, "Out of memory"); return (ARCHIVE_FATAL);
attr->value = strdup(atts[1]); }
if (attr->value == NULL) attr->name = name;
__archive_errx(1, "Out of memory"); attr->value = value;
attr->next = NULL; attr->next = NULL;
*list->last = attr; *list->last = attr;
list->last = &(attr->next); list->last = &(attr->next);
atts += 2; atts += 2;
} }
return (ARCHIVE_OK);
} }
static void static void
expat_start_cb(void *userData, const XML_Char *name, const XML_Char **atts) expat_start_cb(void *userData, const XML_Char *name, const XML_Char **atts)
{ {
struct expat_userData *ud = (struct expat_userData *)userData;
struct archive_read *a = ud->archive;
struct xmlattr_list list; struct xmlattr_list list;
int r;
expat_xmlattr_setup(&list, atts); r = expat_xmlattr_setup(a, &list, atts);
xml_start(userData, (const char *)name, &list); if (r == ARCHIVE_OK)
r = xml_start(a, (const char *)name, &list);
xmlattr_cleanup(&list); xmlattr_cleanup(&list);
ud->state = r;
} }
static void static void
expat_end_cb(void *userData, const XML_Char *name) expat_end_cb(void *userData, const XML_Char *name)
{ {
xml_end(userData, (const char *)name); struct expat_userData *ud = (struct expat_userData *)userData;
xml_end(ud->archive, (const char *)name);
} }
static void static void
expat_data_cb(void *userData, const XML_Char *s, int len) expat_data_cb(void *userData, const XML_Char *s, int len)
{ {
xml_data(userData, s, len); struct expat_userData *ud = (struct expat_userData *)userData;
xml_data(ud->archive, s, len);
} }
static int static int
@ -3103,6 +3273,10 @@ expat_read_toc(struct archive_read *a)
{ {
struct xar *xar; struct xar *xar;
XML_Parser parser; XML_Parser parser;
struct expat_userData ud;
ud.state = ARCHIVE_OK;
ud.archive = a;
xar = (struct xar *)(a->format->data); xar = (struct xar *)(a->format->data);
@ -3113,12 +3287,12 @@ expat_read_toc(struct archive_read *a)
"Couldn't allocate memory for xml parser"); "Couldn't allocate memory for xml parser");
return (ARCHIVE_FATAL); return (ARCHIVE_FATAL);
} }
XML_SetUserData(parser, a); XML_SetUserData(parser, &ud);
XML_SetElementHandler(parser, expat_start_cb, expat_end_cb); XML_SetElementHandler(parser, expat_start_cb, expat_end_cb);
XML_SetCharacterDataHandler(parser, expat_data_cb); XML_SetCharacterDataHandler(parser, expat_data_cb);
xar->xmlsts = INIT; xar->xmlsts = INIT;
while (xar->toc_remaining) { while (xar->toc_remaining && ud.state == ARCHIVE_OK) {
enum XML_Status xr; enum XML_Status xr;
const void *d; const void *d;
size_t outbytes; size_t outbytes;
@ -3129,13 +3303,13 @@ expat_read_toc(struct archive_read *a)
r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining); r = rd_contents(a, &d, &outbytes, &used, xar->toc_remaining);
if (r != ARCHIVE_OK) if (r != ARCHIVE_OK)
return (r); return (r);
__archive_read_consume(a, used);
xar->toc_remaining -= used; xar->toc_remaining -= used;
xar->offset += used; xar->offset += used;
xar->toc_total += outbytes; xar->toc_total += outbytes;
PRINT_TOC(d, outbytes); PRINT_TOC(d, outbytes);
xr = XML_Parse(parser, d, outbytes, xar->toc_remaining == 0); xr = XML_Parse(parser, d, outbytes, xar->toc_remaining == 0);
__archive_read_consume(a, used);
if (xr == XML_STATUS_ERROR) { if (xr == XML_STATUS_ERROR) {
XML_ParserFree(parser); XML_ParserFree(parser);
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@ -3144,7 +3318,7 @@ expat_read_toc(struct archive_read *a)
} }
} }
XML_ParserFree(parser); XML_ParserFree(parser);
return (ARCHIVE_OK); return (ud.state);
} }
#endif /* defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) */ #endif /* defined(HAVE_BSDXML_H) || defined(HAVE_EXPAT_H) */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More