Update libarchive, tar and cpio to version 2.8.5
The following additional vendor revisions are applied: Revision 3740: Use archive_clear_error() to clear the error markers. Obtained from: http://code.google.com/p/libarchive MFC after: 2 weeks
This commit is contained in:
parent
3e7916ec1c
commit
de78128d73
@ -52,7 +52,7 @@
|
|||||||
/* 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)
|
# 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)
|
||||||
# define __LA_SSIZE_T __int64
|
# define __LA_SSIZE_T __int64
|
||||||
@ -98,6 +98,13 @@
|
|||||||
# define __LA_DECL
|
# define __LA_DECL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
#define __LA_PRINTF(fmtarg, firstvararg) \
|
||||||
|
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
||||||
|
#else
|
||||||
|
#define __LA_PRINTF(fmtarg, firstvararg) /* nothing */
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@ -129,13 +136,13 @@ extern "C" {
|
|||||||
* (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
|
* (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000)
|
||||||
* #endif
|
* #endif
|
||||||
*/
|
*/
|
||||||
#define ARCHIVE_VERSION_NUMBER 2008004
|
#define ARCHIVE_VERSION_NUMBER 2008005
|
||||||
__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.4"
|
#define ARCHIVE_VERSION_STRING "libarchive 2.8.5"
|
||||||
__LA_DECL const char * archive_version_string(void);
|
__LA_DECL const char * archive_version_string(void);
|
||||||
|
|
||||||
#if ARCHIVE_VERSION_NUMBER < 3000000
|
#if ARCHIVE_VERSION_NUMBER < 3000000
|
||||||
@ -717,7 +724,7 @@ __LA_DECL const char *archive_format_name(struct archive *);
|
|||||||
__LA_DECL int archive_format(struct archive *);
|
__LA_DECL int archive_format(struct archive *);
|
||||||
__LA_DECL void archive_clear_error(struct archive *);
|
__LA_DECL void archive_clear_error(struct archive *);
|
||||||
__LA_DECL void archive_set_error(struct archive *, int _err,
|
__LA_DECL void archive_set_error(struct archive *, int _err,
|
||||||
const char *fmt, ...);
|
const char *fmt, ...) __LA_PRINTF(3, 4);
|
||||||
__LA_DECL void archive_copy_error(struct archive *dest,
|
__LA_DECL void archive_copy_error(struct archive *dest,
|
||||||
struct archive *src);
|
struct archive *src);
|
||||||
__LA_DECL int archive_file_count(struct archive *);
|
__LA_DECL int archive_file_count(struct archive *);
|
||||||
|
@ -715,7 +715,7 @@ archive_read_data_block(struct archive *_a,
|
|||||||
/*
|
/*
|
||||||
* Close the file and release most resources.
|
* Close the file and release most resources.
|
||||||
*
|
*
|
||||||
* Be careful: client might just call read_new and then read_finish.
|
* Be careful: client might just call read_new and then read_free.
|
||||||
* Don't assume we actually read anything or performed any non-trivial
|
* Don't assume we actually read anything or performed any non-trivial
|
||||||
* initialization.
|
* initialization.
|
||||||
*/
|
*/
|
||||||
|
@ -350,4 +350,4 @@ bzip2_filter_close(struct archive_read_filter *self)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* HAVE_BZLIB_H */
|
#endif /* HAVE_BZLIB_H && BZ_CONFIG_ERROR */
|
||||||
|
@ -488,9 +488,9 @@ read_more:
|
|||||||
switch (uudecode->state) {
|
switch (uudecode->state) {
|
||||||
default:
|
default:
|
||||||
case ST_FIND_HEAD:
|
case ST_FIND_HEAD:
|
||||||
if (len - nl > 13 && 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 &&
|
||||||
memcmp(b, "begin-base64 ", 13) == 0)
|
memcmp(b, "begin-base64 ", 13) == 0)
|
||||||
l = 13;
|
l = 13;
|
||||||
else
|
else
|
||||||
|
@ -264,9 +264,9 @@ archive_read_format_cpio_read_header(struct archive_read *a,
|
|||||||
|
|
||||||
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
|
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
|
||||||
if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) {
|
if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) {
|
||||||
/* TODO: Store file location of start of block. */
|
/* TODO: Store file location of start of block. */
|
||||||
archive_set_error(&a->archive, 0, NULL);
|
archive_clear_error(&a->archive);
|
||||||
return (ARCHIVE_EOF);
|
return (ARCHIVE_EOF);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detect and record hardlinks to previously-extracted entries. */
|
/* Detect and record hardlinks to previously-extracted entries. */
|
||||||
|
@ -934,14 +934,14 @@ read_children(struct archive_read *a, struct file_info *parent)
|
|||||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
"Ignoring out-of-order directory (%s) %jd > %jd",
|
"Ignoring out-of-order directory (%s) %jd > %jd",
|
||||||
parent->name.s,
|
parent->name.s,
|
||||||
iso9660->current_position,
|
(intmax_t)iso9660->current_position,
|
||||||
parent->offset);
|
(intmax_t)parent->offset);
|
||||||
return (ARCHIVE_WARN);
|
return (ARCHIVE_WARN);
|
||||||
}
|
}
|
||||||
if (parent->offset + parent->size > iso9660->volume_size) {
|
if (parent->offset + parent->size > iso9660->volume_size) {
|
||||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
"Directory is beyond end-of-media: %s",
|
"Directory is beyond end-of-media: %s",
|
||||||
parent->name);
|
parent->name.s);
|
||||||
return (ARCHIVE_WARN);
|
return (ARCHIVE_WARN);
|
||||||
}
|
}
|
||||||
if (iso9660->current_position < parent->offset) {
|
if (iso9660->current_position < parent->offset) {
|
||||||
@ -1139,7 +1139,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
|
|||||||
|
|
||||||
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);
|
"File is beyond end-of-media: %s", file->name.s);
|
||||||
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);
|
||||||
@ -1198,10 +1198,10 @@ 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 @%x (%s) %jd < %jd",
|
"Ignoring out-of-order file (%s) %jd < %jd",
|
||||||
file,
|
|
||||||
iso9660->pathname.s,
|
iso9660->pathname.s,
|
||||||
file->offset, iso9660->current_position);
|
(intmax_t)file->offset,
|
||||||
|
(intmax_t)iso9660->current_position);
|
||||||
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);
|
||||||
@ -1524,8 +1524,8 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
|
|||||||
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 (%s) %jd < %jd",
|
||||||
iso9660->pathname.s,
|
iso9660->pathname.s,
|
||||||
iso9660->entry_content->offset,
|
(intmax_t)iso9660->entry_content->offset,
|
||||||
iso9660->current_position);
|
(intmax_t)iso9660->current_position);
|
||||||
*buff = NULL;
|
*buff = NULL;
|
||||||
*size = 0;
|
*size = 0;
|
||||||
*offset = iso9660->entry_sparse_offset;
|
*offset = iso9660->entry_sparse_offset;
|
||||||
@ -1626,8 +1626,8 @@ 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))
|
||||||
(unsigned int)iso9660->volume_block) {
|
> (uint32_t)iso9660->volume_block) {
|
||||||
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);
|
||||||
|
@ -576,7 +576,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
|
|||||||
h = __archive_read_ahead(a, 512, NULL);
|
h = __archive_read_ahead(a, 512, NULL);
|
||||||
if (h != NULL)
|
if (h != NULL)
|
||||||
__archive_read_consume(a, 512);
|
__archive_read_consume(a, 512);
|
||||||
archive_set_error(&a->archive, 0, NULL);
|
archive_clear_error(&a->archive);
|
||||||
if (a->archive.archive_format_name == NULL) {
|
if (a->archive.archive_format_name == NULL) {
|
||||||
a->archive.archive_format = ARCHIVE_FORMAT_TAR;
|
a->archive.archive_format = ARCHIVE_FORMAT_TAR;
|
||||||
a->archive.archive_format_name = "tar";
|
a->archive.archive_format_name = "tar";
|
||||||
|
@ -211,7 +211,7 @@ archive_read_format_zip_bid(struct archive_read *a)
|
|||||||
/* Get 4k of data beyond where we stopped. */
|
/* Get 4k of data beyond where we stopped. */
|
||||||
buff = __archive_read_ahead(a, offset + 4096,
|
buff = __archive_read_ahead(a, offset + 4096,
|
||||||
&bytes_avail);
|
&bytes_avail);
|
||||||
if (bytes_avail < offset + 1)
|
if (buff == NULL)
|
||||||
break;
|
break;
|
||||||
p = (const char *)buff + offset;
|
p = (const char *)buff + offset;
|
||||||
while (p + 9 < (const char *)buff + bytes_avail) {
|
while (p + 9 < (const char *)buff + bytes_avail) {
|
||||||
|
@ -44,6 +44,8 @@
|
|||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "archive.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic resizable/reusable string support a la Java's "StringBuffer."
|
* Basic resizable/reusable string support a la Java's "StringBuffer."
|
||||||
*
|
*
|
||||||
@ -134,10 +136,11 @@ void __archive_string_free(struct archive_string *);
|
|||||||
|
|
||||||
/* Like 'vsprintf', but resizes the underlying string as necessary. */
|
/* Like 'vsprintf', but resizes the underlying string as necessary. */
|
||||||
void __archive_string_vsprintf(struct archive_string *, const char *,
|
void __archive_string_vsprintf(struct archive_string *, const char *,
|
||||||
va_list);
|
va_list) __LA_PRINTF(2, 0);
|
||||||
#define archive_string_vsprintf __archive_string_vsprintf
|
#define archive_string_vsprintf __archive_string_vsprintf
|
||||||
|
|
||||||
void __archive_string_sprintf(struct archive_string *, const char *, ...);
|
void __archive_string_sprintf(struct archive_string *, const char *, ...)
|
||||||
|
__LA_PRINTF(2, 3);
|
||||||
#define archive_string_sprintf __archive_string_sprintf
|
#define archive_string_sprintf __archive_string_sprintf
|
||||||
|
|
||||||
/* Allocates a fresh buffer and converts as (assumed to be UTF-8) into it.
|
/* Allocates a fresh buffer and converts as (assumed to be UTF-8) into it.
|
||||||
|
@ -1730,7 +1730,7 @@ create_dir(struct archive_write_disk *a, char *path)
|
|||||||
if (unlink(path) != 0) {
|
if (unlink(path) != 0) {
|
||||||
archive_set_error(&a->archive, errno,
|
archive_set_error(&a->archive, errno,
|
||||||
"Can't create directory '%s': "
|
"Can't create directory '%s': "
|
||||||
"Conflicting file cannot be removed");
|
"Conflicting file cannot be removed", path);
|
||||||
return (ARCHIVE_FAILED);
|
return (ARCHIVE_FAILED);
|
||||||
}
|
}
|
||||||
} else if (errno != ENOENT && errno != ENOTDIR) {
|
} else if (errno != ENOENT && errno != ENOTDIR) {
|
||||||
|
@ -132,9 +132,10 @@ static int
|
|||||||
archive_compressor_xz_init_stream(struct archive_write *a,
|
archive_compressor_xz_init_stream(struct archive_write *a,
|
||||||
struct private_data *state)
|
struct private_data *state)
|
||||||
{
|
{
|
||||||
|
static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
state->stream = (lzma_stream)LZMA_STREAM_INIT;
|
state->stream = lzma_stream_init_data;
|
||||||
state->stream.next_out = state->compressed;
|
state->stream.next_out = state->compressed;
|
||||||
state->stream.avail_out = state->compressed_buffer_size;
|
state->stream.avail_out = state->compressed_buffer_size;
|
||||||
if (a->archive.compression_code == ARCHIVE_COMPRESSION_XZ)
|
if (a->archive.compression_code == ARCHIVE_COMPRESSION_XZ)
|
||||||
|
@ -440,7 +440,7 @@ archive_write_ar_finish_entry(struct archive_write *a)
|
|||||||
if (ar->entry_padding != 1) {
|
if (ar->entry_padding != 1) {
|
||||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||||
"Padding wrong size: %d should be 1 or 0",
|
"Padding wrong size: %d should be 1 or 0",
|
||||||
ar->entry_padding);
|
(int)ar->entry_padding);
|
||||||
return (ARCHIVE_WARN);
|
return (ARCHIVE_WARN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,8 +537,7 @@ archive_write_shar_finish_entry(struct archive_write *a)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {
|
if ((p = archive_entry_fflags_text(shar->entry)) != NULL) {
|
||||||
archive_string_sprintf(&shar->work, "chflags %s ",
|
archive_string_sprintf(&shar->work, "chflags %s ", p);
|
||||||
p, archive_entry_pathname(shar->entry));
|
|
||||||
shar_quote(&shar->work,
|
shar_quote(&shar->work,
|
||||||
archive_entry_pathname(shar->entry), 1);
|
archive_entry_pathname(shar->entry), 1);
|
||||||
archive_strcat(&shar->work, "\n");
|
archive_strcat(&shar->work, "\n");
|
||||||
|
@ -168,7 +168,7 @@ archive_write_set_format_ustar(struct archive *_a)
|
|||||||
|
|
||||||
/* Basic internal sanity test. */
|
/* Basic internal sanity test. */
|
||||||
if (sizeof(template_header) != 512) {
|
if (sizeof(template_header) != 512) {
|
||||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", sizeof(template_header));
|
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", (int)sizeof(template_header));
|
||||||
return (ARCHIVE_FATAL);
|
return (ARCHIVE_FATAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define HAVE_BSDXML_H 1
|
#define HAVE_BSDXML_H 1
|
||||||
|
#define HAVE_BZLIB_H 1
|
||||||
#define HAVE_CHFLAGS 1
|
#define HAVE_CHFLAGS 1
|
||||||
#define HAVE_CHOWN 1
|
#define HAVE_CHOWN 1
|
||||||
#define HAVE_DECL_EXTATTR_NAMESPACE_USER 1
|
#define HAVE_DECL_EXTATTR_NAMESPACE_USER 1
|
||||||
|
@ -65,6 +65,7 @@ Later variants have extended this by either appropriating undefined
|
|||||||
areas of the header record, extending the header to multiple records,
|
areas of the header record, extending the header to multiple records,
|
||||||
or by storing special entries that modify the interpretation of
|
or by storing special entries that modify the interpretation of
|
||||||
subsequent entries.
|
subsequent entries.
|
||||||
|
.Pp
|
||||||
.Bl -tag -width indent
|
.Bl -tag -width indent
|
||||||
.It Cm gnutar
|
.It Cm gnutar
|
||||||
The
|
The
|
||||||
|
@ -177,6 +177,8 @@ which provides a slightly more efficient interface.
|
|||||||
You may prefer to use the higher-level
|
You may prefer to use the higher-level
|
||||||
.Fn archive_read_data_skip ,
|
.Fn archive_read_data_skip ,
|
||||||
which reads and discards the data for this entry,
|
which reads and discards the data for this entry,
|
||||||
|
.Fn archive_read_data_to_buffer ,
|
||||||
|
which reads the data into an in-memory buffer,
|
||||||
.Fn archive_read_data_to_file ,
|
.Fn archive_read_data_to_file ,
|
||||||
which copies the data to the provided file descriptor, or
|
which copies the data to the provided file descriptor, or
|
||||||
.Fn archive_read_extract ,
|
.Fn archive_read_extract ,
|
||||||
|
@ -52,7 +52,7 @@ TESTS= \
|
|||||||
test_read_format_gtar_gz.c \
|
test_read_format_gtar_gz.c \
|
||||||
test_read_format_gtar_lzma.c \
|
test_read_format_gtar_lzma.c \
|
||||||
test_read_format_gtar_sparse.c \
|
test_read_format_gtar_sparse.c \
|
||||||
test_read_format_iso_gz.c \
|
test_read_format_iso_Z.c \
|
||||||
test_read_format_iso_multi_extent.c \
|
test_read_format_iso_multi_extent.c \
|
||||||
test_read_format_isorr_rr_moved.c \
|
test_read_format_isorr_rr_moved.c \
|
||||||
test_read_format_isojoliet_bz2.c \
|
test_read_format_isojoliet_bz2.c \
|
||||||
|
@ -67,7 +67,7 @@ finish:
|
|||||||
#if ARCHIVE_VERSION_NUMBER < 2000000
|
#if ARCHIVE_VERSION_NUMBER < 2000000
|
||||||
archive_read_finish(a);
|
archive_read_finish(a);
|
||||||
#else
|
#else
|
||||||
assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
|
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ test1(void)
|
|||||||
ARCHIVE_COMPRESSION_COMPRESS);
|
ARCHIVE_COMPRESSION_COMPRESS);
|
||||||
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_ISO9660);
|
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_ISO9660);
|
||||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||||
assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
|
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@ -87,10 +87,10 @@ void test2(void)
|
|||||||
ARCHIVE_COMPRESSION_COMPRESS);
|
ARCHIVE_COMPRESSION_COMPRESS);
|
||||||
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_ISO9660);
|
assertEqualInt(archive_format(a), ARCHIVE_FORMAT_ISO9660);
|
||||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||||
assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
|
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TEST(test_read_format_iso_gz)
|
DEFINE_TEST(test_read_format_iso_Z)
|
||||||
{
|
{
|
||||||
test1();
|
test1();
|
||||||
test2();
|
test2();
|
@ -3,7 +3,7 @@
|
|||||||
.include <bsd.own.mk>
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
PROG= bsdcpio
|
PROG= bsdcpio
|
||||||
BSDCPIO_VERSION_STRING=2.8.4
|
BSDCPIO_VERSION_STRING=2.8.5
|
||||||
|
|
||||||
SRCS= cpio.c cmdline.c
|
SRCS= cpio.c cmdline.c
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
.include <bsd.own.mk>
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
PROG= bsdtar
|
PROG= bsdtar
|
||||||
BSDTAR_VERSION_STRING=2.8.4
|
BSDTAR_VERSION_STRING=2.8.5
|
||||||
SRCS= bsdtar.c \
|
SRCS= bsdtar.c \
|
||||||
cmdline.c \
|
cmdline.c \
|
||||||
getdate.c \
|
getdate.c \
|
||||||
|
@ -48,6 +48,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
#ifdef HAVE_SYS_STAT_H
|
#ifdef HAVE_SYS_STAT_H
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_DIRECT_H
|
||||||
|
#include <direct.h>
|
||||||
|
#endif
|
||||||
#ifdef HAVE_DIRENT_H
|
#ifdef HAVE_DIRENT_H
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
@ -66,6 +69,9 @@ __FBSDID("$FreeBSD$");
|
|||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(HAVE_WINDOWS_H) && !defined(__CYGWIN__)
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
|
||||||
@ -76,27 +82,38 @@ __FBSDID("$FreeBSD$");
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct tree_entry {
|
struct tree_entry {
|
||||||
|
int depth;
|
||||||
struct tree_entry *next;
|
struct tree_entry *next;
|
||||||
struct tree_entry *parent;
|
struct tree_entry *parent;
|
||||||
char *name;
|
char *name;
|
||||||
size_t dirname_length;
|
size_t dirname_length;
|
||||||
dev_t dev;
|
dev_t dev;
|
||||||
ino_t ino;
|
ino_t ino;
|
||||||
|
int flags;
|
||||||
|
/* How to return back to the parent of a symlink. */
|
||||||
#ifdef HAVE_FCHDIR
|
#ifdef HAVE_FCHDIR
|
||||||
int fd;
|
int symlink_parent_fd;
|
||||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
char *fullpath;
|
char *symlink_parent_path;
|
||||||
#else
|
#else
|
||||||
#error fchdir function required.
|
#error fchdir function required.
|
||||||
#endif
|
#endif
|
||||||
int flags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Definitions for tree_entry.flags bitmap. */
|
/* Definitions for tree_entry.flags bitmap. */
|
||||||
#define isDir 1 /* This entry is a regular directory. */
|
#define isDir 1 /* This entry is a regular directory. */
|
||||||
#define isDirLink 2 /* This entry is a symbolic link to a directory. */
|
#define isDirLink 2 /* This entry is a symbolic link to a directory. */
|
||||||
#define needsPreVisit 4 /* This entry needs to be previsited. */
|
#define needsFirstVisit 4 /* This is an initial entry. */
|
||||||
#define needsPostVisit 8 /* This entry needs to be postvisited. */
|
#define needsDescent 8 /* This entry needs to be previsited. */
|
||||||
|
#define needsOpen 16 /* This is a directory that needs to be opened. */
|
||||||
|
#define needsAscent 32 /* This entry needs to be postvisited. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On Windows, "first visit" is handled as a pattern to be handed to
|
||||||
|
* _findfirst(). This is consistent with Windows conventions that
|
||||||
|
* file patterns are handled within the application. On Posix,
|
||||||
|
* "first visit" is just returned to the client.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Local data for this package.
|
* Local data for this package.
|
||||||
@ -104,21 +121,28 @@ struct tree_entry {
|
|||||||
struct tree {
|
struct tree {
|
||||||
struct tree_entry *stack;
|
struct tree_entry *stack;
|
||||||
struct tree_entry *current;
|
struct tree_entry *current;
|
||||||
|
#if defined(HAVE_WINDOWS_H) && !defined(__CYGWIN__)
|
||||||
|
HANDLE d;
|
||||||
|
BY_HANDLE_FILE_INFORMATION fileInfo;
|
||||||
|
#define INVALID_DIR_HANDLE INVALID_HANDLE_VALUE
|
||||||
|
WIN32_FIND_DATA _findData;
|
||||||
|
WIN32_FIND_DATA *findData;
|
||||||
|
#else
|
||||||
DIR *d;
|
DIR *d;
|
||||||
#ifdef HAVE_FCHDIR
|
#define INVALID_DIR_HANDLE NULL
|
||||||
int initialDirFd;
|
struct dirent *de;
|
||||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
|
||||||
char *initialDir;
|
|
||||||
#endif
|
#endif
|
||||||
int flags;
|
int flags;
|
||||||
int visit_type;
|
int visit_type;
|
||||||
int tree_errno; /* Error code from last failed operation. */
|
int tree_errno; /* Error code from last failed operation. */
|
||||||
|
|
||||||
|
/* Dynamically-sized buffer for holding path */
|
||||||
char *buff;
|
char *buff;
|
||||||
const char *basename;
|
|
||||||
size_t buff_length;
|
size_t buff_length;
|
||||||
size_t path_length;
|
|
||||||
size_t dirname_length;
|
const char *basename; /* Last path element */
|
||||||
|
size_t dirname_length; /* Leading dir length */
|
||||||
|
size_t path_length; /* Total path length */
|
||||||
|
|
||||||
int depth;
|
int depth;
|
||||||
int openCount;
|
int openCount;
|
||||||
@ -129,10 +153,17 @@ struct tree {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Definitions for tree.flags bitmap. */
|
/* Definitions for tree.flags bitmap. */
|
||||||
#define needsReturn 8 /* Marks first entry as not having been returned yet. */
|
#define hasStat 16 /* The st entry is valid. */
|
||||||
#define hasStat 16 /* The st entry is set. */
|
#define hasLstat 32 /* The lst entry is valid. */
|
||||||
#define hasLstat 32 /* The lst entry is set. */
|
#define hasFileInfo 64 /* The Windows fileInfo entry is valid. */
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
static int
|
||||||
|
tree_dir_next_windows(struct tree *t, const char *pattern);
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
tree_dir_next_posix(struct tree *t);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_DIRENT_D_NAMLEN
|
#ifdef HAVE_DIRENT_D_NAMLEN
|
||||||
/* BSD extension; avoids need for a strlen() call. */
|
/* BSD extension; avoids need for a strlen() call. */
|
||||||
@ -141,25 +172,32 @@ struct tree {
|
|||||||
#define D_NAMELEN(dp) (strlen((dp)->d_name))
|
#define D_NAMELEN(dp) (strlen((dp)->d_name))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
void
|
void
|
||||||
tree_dump(struct tree *t, FILE *out)
|
tree_dump(struct tree *t, FILE *out)
|
||||||
{
|
{
|
||||||
|
char buff[300];
|
||||||
struct tree_entry *te;
|
struct tree_entry *te;
|
||||||
|
|
||||||
fprintf(out, "\tdepth: %d\n", t->depth);
|
fprintf(out, "\tdepth: %d\n", t->depth);
|
||||||
fprintf(out, "\tbuff: %s\n", t->buff);
|
fprintf(out, "\tbuff: %s\n", t->buff);
|
||||||
fprintf(out, "\tpwd: "); fflush(stdout); system("pwd");
|
fprintf(out, "\tpwd: %s\n", getcwd(buff, sizeof(buff)));
|
||||||
fprintf(out, "\taccess: %s\n", t->basename);
|
fprintf(out, "\tbasename: %s\n", t->basename);
|
||||||
fprintf(out, "\tstack:\n");
|
fprintf(out, "\tstack:\n");
|
||||||
for (te = t->stack; te != NULL; te = te->next) {
|
for (te = t->stack; te != NULL; te = te->next) {
|
||||||
fprintf(out, "\t\tte->name: %s%s%s\n", te->name,
|
fprintf(out, "\t\t%s%d:\"%s\" %s%s%s%s%s%s\n",
|
||||||
te->flags & needsPreVisit ? "" : " *",
|
t->current == te ? "*" : " ",
|
||||||
t->current == te ? " (current)" : "");
|
te->depth,
|
||||||
|
te->name,
|
||||||
|
te->flags & needsFirstVisit ? "V" : "",
|
||||||
|
te->flags & needsDescent ? "D" : "",
|
||||||
|
te->flags & needsOpen ? "O" : "",
|
||||||
|
te->flags & needsAscent ? "A" : "",
|
||||||
|
te->flags & isDirLink ? "L" : "",
|
||||||
|
(t->current == te && t->d) ? "+" : ""
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a directory path to the current stack.
|
* Add a directory path to the current stack.
|
||||||
@ -172,24 +210,29 @@ tree_push(struct tree *t, const char *path)
|
|||||||
te = malloc(sizeof(*te));
|
te = malloc(sizeof(*te));
|
||||||
memset(te, 0, sizeof(*te));
|
memset(te, 0, sizeof(*te));
|
||||||
te->next = t->stack;
|
te->next = t->stack;
|
||||||
|
te->parent = t->current;
|
||||||
|
if (te->parent)
|
||||||
|
te->depth = te->parent->depth + 1;
|
||||||
t->stack = te;
|
t->stack = te;
|
||||||
#ifdef HAVE_FCHDIR
|
#ifdef HAVE_FCHDIR
|
||||||
te->fd = -1;
|
te->symlink_parent_fd = -1;
|
||||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
|
||||||
te->fullpath = NULL;
|
|
||||||
#endif
|
|
||||||
te->name = strdup(path);
|
te->name = strdup(path);
|
||||||
te->flags = needsPreVisit | needsPostVisit;
|
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
te->symlink_parent_path = NULL;
|
||||||
|
te->name = strdup(path);
|
||||||
|
#endif
|
||||||
|
te->flags = needsDescent | needsOpen | needsAscent;
|
||||||
te->dirname_length = t->dirname_length;
|
te->dirname_length = t->dirname_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Append a name to the current path.
|
* Append a name to the current dir path.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
tree_append(struct tree *t, const char *name, size_t name_length)
|
tree_append(struct tree *t, const char *name, size_t name_length)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
size_t size_needed;
|
||||||
|
|
||||||
if (t->buff != NULL)
|
if (t->buff != NULL)
|
||||||
t->buff[t->dirname_length] = '\0';
|
t->buff[t->dirname_length] = '\0';
|
||||||
@ -198,12 +241,16 @@ tree_append(struct tree *t, const char *name, size_t name_length)
|
|||||||
name_length--;
|
name_length--;
|
||||||
|
|
||||||
/* Resize pathname buffer as needed. */
|
/* Resize pathname buffer as needed. */
|
||||||
while (name_length + 1 + t->dirname_length >= t->buff_length) {
|
size_needed = name_length + 1 + t->dirname_length;
|
||||||
t->buff_length *= 2;
|
if (t->buff_length < size_needed) {
|
||||||
if (t->buff_length < 1024)
|
if (t->buff_length < 1024)
|
||||||
t->buff_length = 1024;
|
t->buff_length = 1024;
|
||||||
|
while (t->buff_length < size_needed)
|
||||||
|
t->buff_length *= 2;
|
||||||
t->buff = realloc(t->buff, t->buff_length);
|
t->buff = realloc(t->buff, t->buff_length);
|
||||||
}
|
}
|
||||||
|
if (t->buff == NULL)
|
||||||
|
abort();
|
||||||
p = t->buff + t->dirname_length;
|
p = t->buff + t->dirname_length;
|
||||||
t->path_length = t->dirname_length + name_length;
|
t->path_length = t->dirname_length + name_length;
|
||||||
/* Add a separating '/' if it's needed. */
|
/* Add a separating '/' if it's needed. */
|
||||||
@ -211,7 +258,11 @@ tree_append(struct tree *t, const char *name, size_t name_length)
|
|||||||
*p++ = '/';
|
*p++ = '/';
|
||||||
t->path_length ++;
|
t->path_length ++;
|
||||||
}
|
}
|
||||||
|
#if HAVE_STRNCPY_S
|
||||||
|
strncpy_s(p, t->buff_length - (p - t->buff), name, name_length);
|
||||||
|
#else
|
||||||
strncpy(p, name, name_length);
|
strncpy(p, name, name_length);
|
||||||
|
#endif
|
||||||
p[name_length] = '\0';
|
p[name_length] = '\0';
|
||||||
t->basename = p;
|
t->basename = p;
|
||||||
}
|
}
|
||||||
@ -222,24 +273,55 @@ tree_append(struct tree *t, const char *name, size_t name_length)
|
|||||||
struct tree *
|
struct tree *
|
||||||
tree_open(const char *path)
|
tree_open(const char *path)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_FCHDIR
|
||||||
struct tree *t;
|
struct tree *t;
|
||||||
|
|
||||||
t = malloc(sizeof(*t));
|
t = malloc(sizeof(*t));
|
||||||
memset(t, 0, sizeof(*t));
|
memset(t, 0, sizeof(*t));
|
||||||
tree_append(t, path, strlen(path));
|
/* First item is set up a lot like a symlink traversal. */
|
||||||
#ifdef HAVE_FCHDIR
|
tree_push(t, path);
|
||||||
t->initialDirFd = open(".", O_RDONLY);
|
t->stack->flags = needsFirstVisit | isDirLink | needsAscent;
|
||||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
t->stack->symlink_parent_fd = open(".", O_RDONLY);
|
||||||
t->initialDir = getcwd(NULL, 0);
|
t->openCount++;
|
||||||
#endif
|
t->d = INVALID_DIR_HANDLE;
|
||||||
/*
|
|
||||||
* During most of the traversal, items are set up and then
|
|
||||||
* returned immediately from tree_next(). That doesn't work
|
|
||||||
* for the very first entry, so we set a flag for this special
|
|
||||||
* case.
|
|
||||||
*/
|
|
||||||
t->flags = needsReturn;
|
|
||||||
return (t);
|
return (t);
|
||||||
|
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
struct tree *t;
|
||||||
|
char *cwd = _getcwd(NULL, 0);
|
||||||
|
char *pathname = strdup(path), *p, *base;
|
||||||
|
|
||||||
|
if (pathname == NULL)
|
||||||
|
abort();
|
||||||
|
for (p = pathname; *p != '\0'; ++p) {
|
||||||
|
if (*p == '\\')
|
||||||
|
*p = '/';
|
||||||
|
}
|
||||||
|
base = pathname;
|
||||||
|
|
||||||
|
t = malloc(sizeof(*t));
|
||||||
|
memset(t, 0, sizeof(*t));
|
||||||
|
/* First item is set up a lot like a symlink traversal. */
|
||||||
|
/* printf("Looking for wildcard in %s\n", path); */
|
||||||
|
/* TODO: wildcard detection here screws up on \\?\c:\ UNC names */
|
||||||
|
if (strchr(base, '*') || strchr(base, '?')) {
|
||||||
|
// It has a wildcard in it...
|
||||||
|
// Separate the last element.
|
||||||
|
p = strrchr(base, '/');
|
||||||
|
if (p != NULL) {
|
||||||
|
*p = '\0';
|
||||||
|
chdir(base);
|
||||||
|
tree_append(t, base, p - base);
|
||||||
|
t->dirname_length = t->path_length;
|
||||||
|
base = p + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tree_push(t, base);
|
||||||
|
free(pathname);
|
||||||
|
t->stack->flags = needsFirstVisit | isDirLink | needsAscent;
|
||||||
|
t->stack->symlink_parent_path = cwd;
|
||||||
|
t->d = INVALID_DIR_HANDLE;
|
||||||
|
return (t);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -255,22 +337,26 @@ tree_ascend(struct tree *t)
|
|||||||
t->depth--;
|
t->depth--;
|
||||||
if (te->flags & isDirLink) {
|
if (te->flags & isDirLink) {
|
||||||
#ifdef HAVE_FCHDIR
|
#ifdef HAVE_FCHDIR
|
||||||
if (fchdir(te->fd) != 0) {
|
if (fchdir(te->symlink_parent_fd) != 0) {
|
||||||
t->tree_errno = errno;
|
t->tree_errno = errno;
|
||||||
r = TREE_ERROR_FATAL;
|
r = TREE_ERROR_FATAL;
|
||||||
}
|
}
|
||||||
close(te->fd);
|
close(te->symlink_parent_fd);
|
||||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
if (chdir(te->fullpath) != 0) {
|
if (SetCurrentDirectory(te->symlink_parent_path) == 0) {
|
||||||
t->tree_errno = errno;
|
t->tree_errno = errno;
|
||||||
r = TREE_ERROR_FATAL;
|
r = TREE_ERROR_FATAL;
|
||||||
}
|
}
|
||||||
free(te->fullpath);
|
free(te->symlink_parent_path);
|
||||||
te->fullpath = NULL;
|
te->symlink_parent_path = NULL;
|
||||||
#endif
|
#endif
|
||||||
t->openCount--;
|
t->openCount--;
|
||||||
} else {
|
} else {
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
if (SetCurrentDirectory("..") == 0) {
|
||||||
|
#else
|
||||||
if (chdir("..") != 0) {
|
if (chdir("..") != 0) {
|
||||||
|
#endif
|
||||||
t->tree_errno = errno;
|
t->tree_errno = errno;
|
||||||
r = TREE_ERROR_FATAL;
|
r = TREE_ERROR_FATAL;
|
||||||
}
|
}
|
||||||
@ -286,16 +372,18 @@ tree_pop(struct tree *t)
|
|||||||
{
|
{
|
||||||
struct tree_entry *te;
|
struct tree_entry *te;
|
||||||
|
|
||||||
t->buff[t->dirname_length] = '\0';
|
if (t->buff)
|
||||||
|
t->buff[t->dirname_length] = '\0';
|
||||||
if (t->stack == t->current && t->current != NULL)
|
if (t->stack == t->current && t->current != NULL)
|
||||||
t->current = t->current->parent;
|
t->current = t->current->parent;
|
||||||
te = t->stack;
|
te = t->stack;
|
||||||
t->stack = te->next;
|
t->stack = te->next;
|
||||||
t->dirname_length = te->dirname_length;
|
t->dirname_length = te->dirname_length;
|
||||||
t->basename = t->buff + t->dirname_length;
|
if (t->buff) {
|
||||||
/* Special case: starting dir doesn't skip leading '/'. */
|
t->basename = t->buff + t->dirname_length;
|
||||||
if (t->dirname_length > 0)
|
while (t->basename[0] == '/')
|
||||||
t->basename++;
|
t->basename++;
|
||||||
|
}
|
||||||
free(te->name);
|
free(te->name);
|
||||||
free(te);
|
free(te);
|
||||||
}
|
}
|
||||||
@ -306,101 +394,179 @@ tree_pop(struct tree *t)
|
|||||||
int
|
int
|
||||||
tree_next(struct tree *t)
|
tree_next(struct tree *t)
|
||||||
{
|
{
|
||||||
struct dirent *de = NULL;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* If we're called again after a fatal error, that's an API
|
/* If we're called again after a fatal error, that's an API
|
||||||
* violation. Just crash now. */
|
* violation. Just crash now. */
|
||||||
if (t->visit_type == TREE_ERROR_FATAL) {
|
if (t->visit_type == TREE_ERROR_FATAL) {
|
||||||
const char *msg = "Unable to continue traversing"
|
fprintf(stderr, "Unable to continue traversing"
|
||||||
" directory hierarchy after a fatal error.";
|
" directory hierarchy after a fatal error.");
|
||||||
write(2, msg, strlen(msg));
|
abort();
|
||||||
*(volatile int *)0 = 1; /* Deliberate SEGV; NULL pointer dereference. */
|
|
||||||
exit(1); /* In case the SEGV didn't work. */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle the startup case by returning the initial entry. */
|
|
||||||
if (t->flags & needsReturn) {
|
|
||||||
t->flags &= ~needsReturn;
|
|
||||||
return (t->visit_type = TREE_REGULAR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (t->stack != NULL) {
|
while (t->stack != NULL) {
|
||||||
/* If there's an open dir, get the next entry from there. */
|
/* If there's an open dir, get the next entry from there. */
|
||||||
while (t->d != NULL) {
|
if (t->d != INVALID_DIR_HANDLE) {
|
||||||
de = readdir(t->d);
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
if (de == NULL) {
|
r = tree_dir_next_windows(t, NULL);
|
||||||
closedir(t->d);
|
#else
|
||||||
t->d = NULL;
|
r = tree_dir_next_posix(t);
|
||||||
} else if (de->d_name[0] == '.'
|
#endif
|
||||||
&& de->d_name[1] == '\0') {
|
if (r == 0)
|
||||||
/* Skip '.' */
|
continue;
|
||||||
} else if (de->d_name[0] == '.'
|
return (r);
|
||||||
&& de->d_name[1] == '.'
|
|
||||||
&& de->d_name[2] == '\0') {
|
|
||||||
/* Skip '..' */
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Append the path to the current path
|
|
||||||
* and return it.
|
|
||||||
*/
|
|
||||||
tree_append(t, de->d_name, D_NAMELEN(de));
|
|
||||||
t->flags &= ~hasLstat;
|
|
||||||
t->flags &= ~hasStat;
|
|
||||||
return (t->visit_type = TREE_REGULAR);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the current dir needs to be visited, set it up. */
|
if (t->stack->flags & needsFirstVisit) {
|
||||||
if (t->stack->flags & needsPreVisit) {
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
char *d = t->stack->name;
|
||||||
|
t->stack->flags &= ~needsFirstVisit;
|
||||||
|
if (strchr(d, '*') || strchr(d, '?')) {
|
||||||
|
r = tree_dir_next_windows(t, d);
|
||||||
|
if (r == 0)
|
||||||
|
continue;
|
||||||
|
return (r);
|
||||||
|
}
|
||||||
|
// Not a pattern, handle it as-is...
|
||||||
|
#endif
|
||||||
|
/* Top stack item needs a regular visit. */
|
||||||
t->current = t->stack;
|
t->current = t->stack;
|
||||||
tree_append(t, t->stack->name, strlen(t->stack->name));
|
tree_append(t, t->stack->name, strlen(t->stack->name));
|
||||||
t->stack->flags &= ~needsPreVisit;
|
//t->dirname_length = t->path_length;
|
||||||
|
//tree_pop(t);
|
||||||
|
t->stack->flags &= ~needsFirstVisit;
|
||||||
|
return (t->visit_type = TREE_REGULAR);
|
||||||
|
} else if (t->stack->flags & needsDescent) {
|
||||||
|
/* Top stack item is dir to descend into. */
|
||||||
|
t->current = t->stack;
|
||||||
|
tree_append(t, t->stack->name, strlen(t->stack->name));
|
||||||
|
t->stack->flags &= ~needsDescent;
|
||||||
/* If it is a link, set up fd for the ascent. */
|
/* If it is a link, set up fd for the ascent. */
|
||||||
if (t->stack->flags & isDirLink) {
|
if (t->stack->flags & isDirLink) {
|
||||||
#ifdef HAVE_FCHDIR
|
#ifdef HAVE_FCHDIR
|
||||||
t->stack->fd = open(".", O_RDONLY);
|
t->stack->symlink_parent_fd = open(".", O_RDONLY);
|
||||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
|
||||||
t->stack->fullpath = getcwd(NULL, 0);
|
|
||||||
#endif
|
|
||||||
t->openCount++;
|
t->openCount++;
|
||||||
if (t->openCount > t->maxOpenCount)
|
if (t->openCount > t->maxOpenCount)
|
||||||
t->maxOpenCount = t->openCount;
|
t->maxOpenCount = t->openCount;
|
||||||
|
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
t->stack->symlink_parent_path = _getcwd(NULL, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
t->dirname_length = t->path_length;
|
t->dirname_length = t->path_length;
|
||||||
if (chdir(t->stack->name) != 0) {
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
if (t->path_length == 259 || !SetCurrentDirectory(t->stack->name) != 0)
|
||||||
|
#else
|
||||||
|
if (chdir(t->stack->name) != 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
/* chdir() failed; return error */
|
/* chdir() failed; return error */
|
||||||
tree_pop(t);
|
tree_pop(t);
|
||||||
t->tree_errno = errno;
|
t->tree_errno = errno;
|
||||||
return (t->visit_type = TREE_ERROR_DIR);
|
return (t->visit_type = TREE_ERROR_DIR);
|
||||||
}
|
}
|
||||||
t->depth++;
|
t->depth++;
|
||||||
t->d = opendir(".");
|
return (t->visit_type = TREE_POSTDESCENT);
|
||||||
if (t->d == NULL) {
|
} else if (t->stack->flags & needsOpen) {
|
||||||
|
t->stack->flags &= ~needsOpen;
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
r = tree_dir_next_windows(t, "*");
|
||||||
|
#else
|
||||||
|
r = tree_dir_next_posix(t);
|
||||||
|
#endif
|
||||||
|
if (r == 0)
|
||||||
|
continue;
|
||||||
|
return (r);
|
||||||
|
} else if (t->stack->flags & needsAscent) {
|
||||||
|
/* Top stack item is dir and we're done with it. */
|
||||||
|
r = tree_ascend(t);
|
||||||
|
tree_pop(t);
|
||||||
|
t->visit_type = r != 0 ? r : TREE_POSTASCENT;
|
||||||
|
return (t->visit_type);
|
||||||
|
} else {
|
||||||
|
/* Top item on stack is dead. */
|
||||||
|
tree_pop(t);
|
||||||
|
t->flags &= ~hasLstat;
|
||||||
|
t->flags &= ~hasStat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (t->visit_type = 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
static int
|
||||||
|
tree_dir_next_windows(struct tree *t, const char *pattern)
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
size_t namelen;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (pattern != NULL) {
|
||||||
|
t->d = FindFirstFile(pattern, &t->_findData);
|
||||||
|
if (t->d == INVALID_DIR_HANDLE) {
|
||||||
r = tree_ascend(t); /* Undo "chdir" */
|
r = tree_ascend(t); /* Undo "chdir" */
|
||||||
tree_pop(t);
|
tree_pop(t);
|
||||||
t->tree_errno = errno;
|
t->tree_errno = errno;
|
||||||
t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
|
t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
|
||||||
return (t->visit_type);
|
return (t->visit_type);
|
||||||
}
|
}
|
||||||
t->flags &= ~hasLstat;
|
t->findData = &t->_findData;
|
||||||
t->flags &= ~hasStat;
|
pattern = NULL;
|
||||||
t->basename = ".";
|
} else if (!FindNextFile(t->d, &t->_findData)) {
|
||||||
return (t->visit_type = TREE_POSTDESCENT);
|
FindClose(t->d);
|
||||||
|
t->d = INVALID_DIR_HANDLE;
|
||||||
|
t->findData = NULL;
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
name = t->findData->cFileName;
|
||||||
|
namelen = strlen(name);
|
||||||
|
t->flags &= ~hasLstat;
|
||||||
|
t->flags &= ~hasStat;
|
||||||
|
if (name[0] == '.' && name[1] == '\0')
|
||||||
|
continue;
|
||||||
|
if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
|
||||||
|
continue;
|
||||||
|
tree_append(t, name, namelen);
|
||||||
|
return (t->visit_type = TREE_REGULAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
tree_dir_next_posix(struct tree *t)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
const char *name;
|
||||||
|
size_t namelen;
|
||||||
|
|
||||||
/* We've done everything necessary for the top stack entry. */
|
if (t->d == NULL) {
|
||||||
if (t->stack->flags & needsPostVisit) {
|
if ((t->d = opendir(".")) == NULL) {
|
||||||
r = tree_ascend(t);
|
r = tree_ascend(t); /* Undo "chdir" */
|
||||||
tree_pop(t);
|
tree_pop(t);
|
||||||
t->flags &= ~hasLstat;
|
t->tree_errno = errno;
|
||||||
t->flags &= ~hasStat;
|
t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
|
||||||
t->visit_type = r != 0 ? r : TREE_POSTASCENT;
|
|
||||||
return (t->visit_type);
|
return (t->visit_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (t->visit_type = 0);
|
for (;;) {
|
||||||
|
t->de = readdir(t->d);
|
||||||
|
if (t->de == NULL) {
|
||||||
|
closedir(t->d);
|
||||||
|
t->d = INVALID_DIR_HANDLE;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
name = t->de->d_name;
|
||||||
|
namelen = D_NAMELEN(t->de);
|
||||||
|
t->flags &= ~hasLstat;
|
||||||
|
t->flags &= ~hasStat;
|
||||||
|
if (name[0] == '.' && name[1] == '\0')
|
||||||
|
continue;
|
||||||
|
if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
|
||||||
|
continue;
|
||||||
|
tree_append(t, name, namelen);
|
||||||
|
return (t->visit_type = TREE_REGULAR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return error code.
|
* Return error code.
|
||||||
@ -437,25 +603,51 @@ const struct stat *
|
|||||||
tree_current_stat(struct tree *t)
|
tree_current_stat(struct tree *t)
|
||||||
{
|
{
|
||||||
if (!(t->flags & hasStat)) {
|
if (!(t->flags & hasStat)) {
|
||||||
if (stat(t->basename, &t->st) != 0)
|
if (stat(tree_current_access_path(t), &t->st) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
t->flags |= hasStat;
|
t->flags |= hasStat;
|
||||||
}
|
}
|
||||||
return (&t->st);
|
return (&t->st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_WINDOWS_H) && !defined(__CYGWIN__)
|
||||||
|
const BY_HANDLE_FILE_INFORMATION *
|
||||||
|
tree_current_file_information(struct tree *t)
|
||||||
|
{
|
||||||
|
if (!(t->flags & hasFileInfo)) {
|
||||||
|
HANDLE h = CreateFile(tree_current_access_path(t),
|
||||||
|
0, 0, NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
|
||||||
|
NULL);
|
||||||
|
if (h == INVALID_HANDLE_VALUE)
|
||||||
|
return NULL;
|
||||||
|
if (!GetFileInformationByHandle(h, &t->fileInfo)) {
|
||||||
|
CloseHandle(h);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
CloseHandle(h);
|
||||||
|
t->flags |= hasFileInfo;
|
||||||
|
}
|
||||||
|
return (&t->fileInfo);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
* Get the lstat() data for the entry just returned from tree_next().
|
* Get the lstat() data for the entry just returned from tree_next().
|
||||||
*/
|
*/
|
||||||
const struct stat *
|
const struct stat *
|
||||||
tree_current_lstat(struct tree *t)
|
tree_current_lstat(struct tree *t)
|
||||||
{
|
{
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
return (tree_current_stat(t));
|
||||||
|
#else
|
||||||
if (!(t->flags & hasLstat)) {
|
if (!(t->flags & hasLstat)) {
|
||||||
if (lstat(t->basename, &t->lst) != 0)
|
if (lstat(tree_current_access_path(t), &t->lst) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
t->flags |= hasLstat;
|
t->flags |= hasLstat;
|
||||||
}
|
}
|
||||||
return (&t->lst);
|
return (&t->lst);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -464,8 +656,14 @@ tree_current_lstat(struct tree *t)
|
|||||||
int
|
int
|
||||||
tree_current_is_dir(struct tree *t)
|
tree_current_is_dir(struct tree *t)
|
||||||
{
|
{
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
if (t->findData)
|
||||||
|
return (t->findData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
if (tree_current_file_information(t))
|
||||||
|
return (t->fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
return (0);
|
||||||
|
#else
|
||||||
const struct stat *st;
|
const struct stat *st;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we already have lstat() info, then try some
|
* If we already have lstat() info, then try some
|
||||||
* cheap tests to determine if this is a dir.
|
* cheap tests to determine if this is a dir.
|
||||||
@ -490,6 +688,7 @@ tree_current_is_dir(struct tree *t)
|
|||||||
return 0;
|
return 0;
|
||||||
/* Use the definitive test. Hopefully this is cached. */
|
/* Use the definitive test. Hopefully this is cached. */
|
||||||
return (S_ISDIR(st->st_mode));
|
return (S_ISDIR(st->st_mode));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -500,6 +699,11 @@ tree_current_is_dir(struct tree *t)
|
|||||||
int
|
int
|
||||||
tree_current_is_physical_dir(struct tree *t)
|
tree_current_is_physical_dir(struct tree *t)
|
||||||
{
|
{
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
if (tree_current_is_physical_link(t))
|
||||||
|
return (0);
|
||||||
|
return (tree_current_is_dir(t));
|
||||||
|
#else
|
||||||
const struct stat *st;
|
const struct stat *st;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -523,6 +727,7 @@ tree_current_is_physical_dir(struct tree *t)
|
|||||||
return 0;
|
return 0;
|
||||||
/* Use the definitive test. Hopefully this is cached. */
|
/* Use the definitive test. Hopefully this is cached. */
|
||||||
return (S_ISDIR(st->st_mode));
|
return (S_ISDIR(st->st_mode));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -531,10 +736,21 @@ tree_current_is_physical_dir(struct tree *t)
|
|||||||
int
|
int
|
||||||
tree_current_is_physical_link(struct tree *t)
|
tree_current_is_physical_link(struct tree *t)
|
||||||
{
|
{
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
#ifndef IO_REPARSE_TAG_SYMLINK
|
||||||
|
/* Old SDKs do not provide IO_REPARSE_TAG_SYMLINK */
|
||||||
|
#define IO_REPARSE_TAG_SYMLINK 0xA000000CL
|
||||||
|
#endif
|
||||||
|
if (t->findData)
|
||||||
|
return ((t->findData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
&& (t->findData->dwReserved0 == IO_REPARSE_TAG_SYMLINK));
|
||||||
|
return (0);
|
||||||
|
#else
|
||||||
const struct stat *st = tree_current_lstat(t);
|
const struct stat *st = tree_current_lstat(t);
|
||||||
if (st == NULL)
|
if (st == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
return (S_ISLNK(st->st_mode));
|
return (S_ISLNK(st->st_mode));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -582,21 +798,23 @@ tree_close(struct tree *t)
|
|||||||
/* Release anything remaining in the stack. */
|
/* Release anything remaining in the stack. */
|
||||||
while (t->stack != NULL)
|
while (t->stack != NULL)
|
||||||
tree_pop(t);
|
tree_pop(t);
|
||||||
if (t->buff)
|
free(t->buff);
|
||||||
free(t->buff);
|
/* TODO: Ensure that premature close() resets cwd */
|
||||||
/* chdir() back to where we started. */
|
#if 0
|
||||||
#ifdef HAVE_FCHDIR
|
#ifdef HAVE_FCHDIR
|
||||||
if (t->initialDirFd >= 0) {
|
if (t->initialDirFd >= 0) {
|
||||||
fchdir(t->initialDirFd);
|
int s = fchdir(t->initialDirFd);
|
||||||
|
(void)s; /* UNUSED */
|
||||||
close(t->initialDirFd);
|
close(t->initialDirFd);
|
||||||
t->initialDirFd = -1;
|
t->initialDirFd = -1;
|
||||||
}
|
}
|
||||||
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
#elif defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
if (t->initialDir != NULL) {
|
if (t->initialDir != NULL) {
|
||||||
chdir(t->initialDir);
|
SetCurrentDir(t->initialDir);
|
||||||
free(t->initialDir);
|
free(t->initialDir);
|
||||||
t->initialDir = NULL;
|
t->initialDir = NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user