mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-07 06:09:52 -06:00
Merge branch 'upstream-LibArchive' into update-libarchive
* upstream-LibArchive: LibArchive 2022-02-08 (673c1eae)
This commit is contained in:
@@ -81,7 +81,7 @@ math(EXPR INTERFACE_VERSION "13 + ${_minor}")
|
||||
# ?? Should there be more here ??
|
||||
SET(SOVERSION "${INTERFACE_VERSION}")
|
||||
|
||||
# Enalbe CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros
|
||||
# Enable CMAKE_PUSH_CHECK_STATE() and CMAKE_POP_CHECK_STATE() macros
|
||||
# saving and restoring the state of the variables.
|
||||
INCLUDE(${CMake_SOURCE_DIR}/Modules/CMakePushCheckState.cmake)
|
||||
|
||||
@@ -405,7 +405,7 @@ IF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN)
|
||||
SET(__GNUWIN32PATH "C:/Program Files/GnuWin32")
|
||||
ENDIF(WIN32 AND NOT CMAKE_CL_64 AND NOT CYGWIN)
|
||||
IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
|
||||
# You have to add a path availabel DLL file into PATH environment variable.
|
||||
# You have to add a path available DLL file into PATH environment variable.
|
||||
# Maybe DLL path is "C:/Program Files/GnuWin32/bin".
|
||||
# The zlib and the bzip2 Setup program have installed programs and DLLs into
|
||||
# "C:/Program Files/GnuWin32" by default.
|
||||
@@ -1042,7 +1042,7 @@ MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
|
||||
CMAKE_C_COMPILER_ID MATCHES "^Clang$")
|
||||
#
|
||||
# During checking iconv proto type, we should use -Werror to avoid the
|
||||
# success of iconv detection with a warnig which success is a miss
|
||||
# success of iconv detection with a warning which success is a miss
|
||||
# detection. So this needs for all build mode(even it's a release mode).
|
||||
#
|
||||
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
|
||||
@@ -1378,6 +1378,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(lchflags HAVE_LCHFLAGS)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(lchmod HAVE_LCHMOD)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(lchown HAVE_LCHOWN)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(link HAVE_LINK)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(linkat HAVE_LINKAT)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(localtime_r HAVE_LOCALTIME_R)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(lstat HAVE_LSTAT)
|
||||
CHECK_FUNCTION_EXISTS_GLIBC(lutimes HAVE_LUTIMES)
|
||||
@@ -1447,6 +1448,10 @@ CHECK_C_SOURCE_COMPILES(
|
||||
"#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct xvfsconf v; return sizeof(v);}"
|
||||
HAVE_STRUCT_XVFSCONF)
|
||||
|
||||
CHECK_C_SOURCE_COMPILES(
|
||||
"#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct statfs s; return sizeof(s);}"
|
||||
HAVE_STRUCT_STATFS)
|
||||
|
||||
# Make sure we have the POSIX version of readdir_r, not the
|
||||
# older 2-argument version.
|
||||
CHECK_C_SOURCE_COMPILES(
|
||||
@@ -1510,9 +1515,14 @@ CHECK_STRUCT_HAS_MEMBER("struct tm" tm_gmtoff
|
||||
CHECK_STRUCT_HAS_MEMBER("struct tm" __tm_gmtoff
|
||||
"time.h" HAVE_STRUCT_TM___TM_GMTOFF)
|
||||
|
||||
IF(HAVE_STRUCT_STATFS)
|
||||
# Check for f_namemax in struct statfs
|
||||
CHECK_STRUCT_HAS_MEMBER("struct statfs" f_namemax
|
||||
"sys/param.h;sys/mount.h" HAVE_STRUCT_STATFS_F_NAMEMAX)
|
||||
# Check for f_iosize in struct statfs
|
||||
CHECK_STRUCT_HAS_MEMBER("struct statfs" f_iosize
|
||||
"sys/param.h;sys/mount.h" HAVE_STRUCT_STATFS_F_IOSIZE)
|
||||
ENDIF(HAVE_STRUCT_STATFS)
|
||||
|
||||
# Check for birthtime in struct stat
|
||||
CHECK_STRUCT_HAS_MEMBER("struct stat" st_birthtime
|
||||
|
||||
@@ -528,6 +528,9 @@
|
||||
/* Define to 1 if you have the `link' function. */
|
||||
#cmakedefine HAVE_LINK 1
|
||||
|
||||
/* Define to 1 if you have the `linkat' function. */
|
||||
#cmakedefine HAVE_LINKAT 1
|
||||
|
||||
/* Define to 1 if you have the <linux/types.h> header file. */
|
||||
#cmakedefine HAVE_LINUX_TYPES_H 1
|
||||
|
||||
|
||||
@@ -246,7 +246,7 @@ function hextoi(hex)
|
||||
# Exclusion code points specified by
|
||||
# http://unicode.org/Public/6.0.0/ucd/CompositionExclusions.txt
|
||||
##
|
||||
# 1. Script Specifices
|
||||
# 1. Script Specifics
|
||||
##
|
||||
\$1 ~/^095[89ABCDEF]\$/ {
|
||||
next
|
||||
|
||||
@@ -1 +1 @@
|
||||
3005001
|
||||
3005003
|
||||
|
||||
@@ -144,7 +144,9 @@ SET(libarchive_SOURCES
|
||||
archive_write_set_format_ar.c
|
||||
archive_write_set_format_by_name.c
|
||||
archive_write_set_format_cpio.c
|
||||
archive_write_set_format_cpio_binary.c
|
||||
archive_write_set_format_cpio_newc.c
|
||||
archive_write_set_format_cpio_odc.c
|
||||
archive_write_set_format_filter_by_ext.c
|
||||
archive_write_set_format_gnutar.c
|
||||
archive_write_set_format_iso9660.c
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
|
||||
*/
|
||||
/* Note: Compiler will complain if this does not match archive_entry.h! */
|
||||
#define ARCHIVE_VERSION_NUMBER 3005001
|
||||
#define ARCHIVE_VERSION_NUMBER 3005003
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stddef.h> /* for wchar_t */
|
||||
@@ -152,7 +152,7 @@ __LA_DECL int archive_version_number(void);
|
||||
/*
|
||||
* Textual name/version of the library, useful for version displays.
|
||||
*/
|
||||
#define ARCHIVE_VERSION_ONLY_STRING "3.5.1"
|
||||
#define ARCHIVE_VERSION_ONLY_STRING "3.5.3"
|
||||
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
|
||||
__LA_DECL const char * archive_version_string(void);
|
||||
|
||||
@@ -316,6 +316,7 @@ typedef const char *archive_passphrase_callback(struct archive *,
|
||||
#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4)
|
||||
#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5)
|
||||
#define ARCHIVE_FORMAT_CPIO_AFIO_LARGE (ARCHIVE_FORMAT_CPIO | 6)
|
||||
#define ARCHIVE_FORMAT_CPIO_PWB (ARCHIVE_FORMAT_CPIO | 7)
|
||||
#define ARCHIVE_FORMAT_SHAR 0x20000
|
||||
#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1)
|
||||
#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2)
|
||||
@@ -797,7 +798,10 @@ __LA_DECL int archive_write_set_format_7zip(struct archive *);
|
||||
__LA_DECL int archive_write_set_format_ar_bsd(struct archive *);
|
||||
__LA_DECL int archive_write_set_format_ar_svr4(struct archive *);
|
||||
__LA_DECL int archive_write_set_format_cpio(struct archive *);
|
||||
__LA_DECL int archive_write_set_format_cpio_bin(struct archive *);
|
||||
__LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
|
||||
__LA_DECL int archive_write_set_format_cpio_odc(struct archive *);
|
||||
__LA_DECL int archive_write_set_format_cpio_pwb(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 *);
|
||||
|
||||
@@ -319,7 +319,7 @@ translate_acl(struct archive_read_disk *a,
|
||||
|
||||
static int
|
||||
set_acl(struct archive *a, int fd, const char *name,
|
||||
struct archive_acl *abstract_acl,
|
||||
struct archive_acl *abstract_acl, __LA_MODE_T mode,
|
||||
int ae_requested_type, const char *tname)
|
||||
{
|
||||
int acl_type = 0;
|
||||
@@ -364,6 +364,13 @@ set_acl(struct archive *a, int fd, const char *name,
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
|
||||
errno = EINVAL;
|
||||
archive_set_error(a, errno,
|
||||
"Cannot set default ACL on non-directory");
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
acl = acl_init(entries);
|
||||
if (acl == (acl_t)NULL) {
|
||||
archive_set_error(a, errno,
|
||||
@@ -542,7 +549,10 @@ set_acl(struct archive *a, int fd, const char *name,
|
||||
else if (acl_set_link_np(name, acl_type, acl) != 0)
|
||||
#else
|
||||
/* FreeBSD older than 8.0 */
|
||||
else if (acl_set_file(name, acl_type, acl) != 0)
|
||||
else if (S_ISLNK(mode)) {
|
||||
/* acl_set_file() follows symbolic links, skip */
|
||||
ret = ARCHIVE_OK;
|
||||
} else if (acl_set_file(name, acl_type, acl) != 0)
|
||||
#endif
|
||||
{
|
||||
if (errno == EOPNOTSUPP) {
|
||||
@@ -677,14 +687,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
|
||||
& ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
|
||||
if ((archive_acl_types(abstract_acl)
|
||||
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
ret = set_acl(a, fd, name, abstract_acl,
|
||||
ret = set_acl(a, fd, name, abstract_acl, mode,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
if ((archive_acl_types(abstract_acl)
|
||||
& ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
|
||||
ret = set_acl(a, fd, name, abstract_acl,
|
||||
ret = set_acl(a, fd, name, abstract_acl, mode,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
|
||||
|
||||
/* Simultaneous POSIX.1e and NFSv4 is not supported */
|
||||
@@ -693,7 +703,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
|
||||
#if ARCHIVE_ACL_FREEBSD_NFS4
|
||||
else if ((archive_acl_types(abstract_acl) &
|
||||
ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
|
||||
ret = set_acl(a, fd, name, abstract_acl,
|
||||
ret = set_acl(a, fd, name, abstract_acl, mode,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -343,6 +343,11 @@ set_richacl(struct archive *a, int fd, const char *name,
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (S_ISLNK(mode)) {
|
||||
/* Linux does not support RichACLs on symbolic links */
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
richacl = richacl_alloc(entries);
|
||||
if (richacl == NULL) {
|
||||
archive_set_error(a, errno,
|
||||
@@ -455,7 +460,7 @@ exit_free:
|
||||
#if ARCHIVE_ACL_LIBACL
|
||||
static int
|
||||
set_acl(struct archive *a, int fd, const char *name,
|
||||
struct archive_acl *abstract_acl,
|
||||
struct archive_acl *abstract_acl, __LA_MODE_T mode,
|
||||
int ae_requested_type, const char *tname)
|
||||
{
|
||||
int acl_type = 0;
|
||||
@@ -488,6 +493,18 @@ set_acl(struct archive *a, int fd, const char *name,
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (S_ISLNK(mode)) {
|
||||
/* Linux does not support ACLs on symbolic links */
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
if (acl_type == ACL_TYPE_DEFAULT && !S_ISDIR(mode)) {
|
||||
errno = EINVAL;
|
||||
archive_set_error(a, errno,
|
||||
"Cannot set default ACL on non-directory");
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
acl = acl_init(entries);
|
||||
if (acl == (acl_t)NULL) {
|
||||
archive_set_error(a, errno,
|
||||
@@ -727,14 +744,14 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
|
||||
& ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
|
||||
if ((archive_acl_types(abstract_acl)
|
||||
& ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
ret = set_acl(a, fd, name, abstract_acl,
|
||||
ret = set_acl(a, fd, name, abstract_acl, mode,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
}
|
||||
if ((archive_acl_types(abstract_acl)
|
||||
& ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
|
||||
ret = set_acl(a, fd, name, abstract_acl,
|
||||
ret = set_acl(a, fd, name, abstract_acl, mode,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
|
||||
}
|
||||
#endif /* ARCHIVE_ACL_LIBACL */
|
||||
|
||||
@@ -443,7 +443,7 @@ translate_acl(struct archive_read_disk *a,
|
||||
|
||||
static int
|
||||
set_acl(struct archive *a, int fd, const char *name,
|
||||
struct archive_acl *abstract_acl,
|
||||
struct archive_acl *abstract_acl, __LA_MODE_T mode,
|
||||
int ae_requested_type, const char *tname)
|
||||
{
|
||||
aclent_t *aclent;
|
||||
@@ -467,7 +467,6 @@ set_acl(struct archive *a, int fd, const char *name,
|
||||
if (entries == 0)
|
||||
return (ARCHIVE_OK);
|
||||
|
||||
|
||||
switch (ae_requested_type) {
|
||||
case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
|
||||
cmd = SETACL;
|
||||
@@ -492,6 +491,12 @@ set_acl(struct archive *a, int fd, const char *name,
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (S_ISLNK(mode)) {
|
||||
/* Skip ACLs on symbolic links */
|
||||
ret = ARCHIVE_OK;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
e = 0;
|
||||
|
||||
while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
|
||||
@@ -801,7 +806,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
|
||||
if ((archive_acl_types(abstract_acl)
|
||||
& ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
|
||||
/* Solaris writes POSIX.1e access and default ACLs together */
|
||||
ret = set_acl(a, fd, name, abstract_acl,
|
||||
ret = set_acl(a, fd, name, abstract_acl, mode,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
|
||||
|
||||
/* Simultaneous POSIX.1e and NFSv4 is not supported */
|
||||
@@ -810,7 +815,7 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
|
||||
#if ARCHIVE_ACL_SUNOS_NFS4
|
||||
else if ((archive_acl_types(abstract_acl) &
|
||||
ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
|
||||
ret = set_acl(a, fd, name, abstract_acl,
|
||||
ret = set_acl(a, fd, name, abstract_acl, mode,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#define ARCHIVE_ENTRY_H_INCLUDED
|
||||
|
||||
/* Note: Compiler will complain if this does not match archive.h! */
|
||||
#define ARCHIVE_VERSION_NUMBER 3005001
|
||||
#define ARCHIVE_VERSION_NUMBER 3005003
|
||||
|
||||
/*
|
||||
* Note: archive_entry.h is for use outside of libarchive; the
|
||||
|
||||
@@ -384,6 +384,8 @@ __archive_pathmatch(const char *p, const char *s, int flags)
|
||||
/* Empty pattern only matches the empty string. */
|
||||
if (p == NULL || *p == '\0')
|
||||
return (s == NULL || *s == '\0');
|
||||
else if (s == NULL)
|
||||
return (0);
|
||||
|
||||
/* Leading '^' anchors the start of the pattern. */
|
||||
if (*p == '^') {
|
||||
@@ -424,6 +426,8 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
|
||||
/* Empty pattern only matches the empty string. */
|
||||
if (p == NULL || *p == L'\0')
|
||||
return (s == NULL || *s == L'\0');
|
||||
else if (s == NULL)
|
||||
return (0);
|
||||
|
||||
/* Leading '^' anchors the start of the pattern. */
|
||||
if (*p == L'^') {
|
||||
|
||||
@@ -46,6 +46,13 @@
|
||||
#define __LA_DEAD
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2 || \
|
||||
(__GNUC__ == 2 && __GNUC_MINOR__ >= 7))
|
||||
#define __LA_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define __LA_UNUSED
|
||||
#endif
|
||||
|
||||
#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU)
|
||||
#define ARCHIVE_READ_MAGIC (0xdeb0c5U)
|
||||
#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
|
||||
|
||||
@@ -1522,8 +1522,40 @@ get_xfer_size(struct tree *t, int fd, const char *path)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_STATFS) && defined(HAVE_FSTATFS) && defined(MNT_LOCAL) \
|
||||
&& !defined(ST_LOCAL)
|
||||
#if defined(HAVE_STATVFS)
|
||||
static inline __LA_UNUSED void
|
||||
set_statvfs_transfer_size(struct filesystem *fs, const struct statvfs *sfs)
|
||||
{
|
||||
fs->xfer_align = sfs->f_frsize > 0 ? (long)sfs->f_frsize : -1;
|
||||
fs->max_xfer_size = -1;
|
||||
#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)
|
||||
fs->min_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;
|
||||
fs->incr_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;
|
||||
#else
|
||||
fs->min_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
|
||||
fs->incr_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_STRUCT_STATFS)
|
||||
static inline __LA_UNUSED void
|
||||
set_statfs_transfer_size(struct filesystem *fs, const struct statfs *sfs)
|
||||
{
|
||||
fs->xfer_align = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
|
||||
fs->max_xfer_size = -1;
|
||||
#if defined(HAVE_STRUCT_STATFS_F_IOSIZE)
|
||||
fs->min_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;
|
||||
fs->incr_xfer_size = sfs->f_iosize > 0 ? (long)sfs->f_iosize : -1;
|
||||
#else
|
||||
fs->min_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
|
||||
fs->incr_xfer_size = sfs->f_bsize > 0 ? (long)sfs->f_bsize : -1;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_STRUCT_STATFS) && defined(HAVE_STATFS) && \
|
||||
defined(HAVE_FSTATFS) && defined(MNT_LOCAL) && !defined(ST_LOCAL)
|
||||
|
||||
/*
|
||||
* Gather current filesystem properties on FreeBSD, OpenBSD and Mac OS X.
|
||||
@@ -1593,10 +1625,7 @@ setup_current_filesystem(struct archive_read_disk *a)
|
||||
return (ARCHIVE_FAILED);
|
||||
} else if (xr == 1) {
|
||||
/* pathconf(_PC_REX_*) operations are not supported. */
|
||||
t->current_filesystem->xfer_align = sfs.f_bsize;
|
||||
t->current_filesystem->max_xfer_size = -1;
|
||||
t->current_filesystem->min_xfer_size = sfs.f_iosize;
|
||||
t->current_filesystem->incr_xfer_size = sfs.f_iosize;
|
||||
set_statfs_transfer_size(t->current_filesystem, &sfs);
|
||||
}
|
||||
if (sfs.f_flags & MNT_LOCAL)
|
||||
t->current_filesystem->remote = 0;
|
||||
@@ -1688,15 +1717,7 @@ setup_current_filesystem(struct archive_read_disk *a)
|
||||
} else if (xr == 1) {
|
||||
/* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN
|
||||
* for pathconf() function. */
|
||||
t->current_filesystem->xfer_align = svfs.f_frsize;
|
||||
t->current_filesystem->max_xfer_size = -1;
|
||||
#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)
|
||||
t->current_filesystem->min_xfer_size = svfs.f_iosize;
|
||||
t->current_filesystem->incr_xfer_size = svfs.f_iosize;
|
||||
#else
|
||||
t->current_filesystem->min_xfer_size = svfs.f_bsize;
|
||||
t->current_filesystem->incr_xfer_size = svfs.f_bsize;
|
||||
#endif
|
||||
set_statvfs_transfer_size(t->current_filesystem, &svfs);
|
||||
}
|
||||
if (svfs.f_flag & ST_LOCAL)
|
||||
t->current_filesystem->remote = 0;
|
||||
@@ -1803,15 +1824,9 @@ setup_current_filesystem(struct archive_read_disk *a)
|
||||
} else if (xr == 1) {
|
||||
/* pathconf(_PC_REX_*) operations are not supported. */
|
||||
#if defined(HAVE_STATVFS)
|
||||
t->current_filesystem->xfer_align = svfs.f_frsize;
|
||||
t->current_filesystem->max_xfer_size = -1;
|
||||
t->current_filesystem->min_xfer_size = svfs.f_bsize;
|
||||
t->current_filesystem->incr_xfer_size = svfs.f_bsize;
|
||||
set_statvfs_transfer_size(t->current_filesystem, &svfs);
|
||||
#else
|
||||
t->current_filesystem->xfer_align = sfs.f_frsize;
|
||||
t->current_filesystem->max_xfer_size = -1;
|
||||
t->current_filesystem->min_xfer_size = sfs.f_bsize;
|
||||
t->current_filesystem->incr_xfer_size = sfs.f_bsize;
|
||||
set_statfs_transfer_size(t->current_filesystem, &sfs);
|
||||
#endif
|
||||
}
|
||||
switch (sfs.f_type) {
|
||||
@@ -1918,10 +1933,7 @@ setup_current_filesystem(struct archive_read_disk *a)
|
||||
return (ARCHIVE_FAILED);
|
||||
} else if (xr == 1) {
|
||||
/* pathconf(_PC_REX_*) operations are not supported. */
|
||||
t->current_filesystem->xfer_align = svfs.f_frsize;
|
||||
t->current_filesystem->max_xfer_size = -1;
|
||||
t->current_filesystem->min_xfer_size = svfs.f_bsize;
|
||||
t->current_filesystem->incr_xfer_size = svfs.f_bsize;
|
||||
set_statvfs_transfer_size(t->current_filesystem, &svfs);
|
||||
}
|
||||
|
||||
#if defined(ST_NOATIME)
|
||||
|
||||
@@ -1844,7 +1844,7 @@ tree_next(struct tree *t)
|
||||
continue;
|
||||
return (r);
|
||||
} else {
|
||||
HANDLE h = FindFirstFileW(d, &t->_findData);
|
||||
HANDLE h = FindFirstFileW(t->stack->full_path.s, &t->_findData);
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
la_dosmaperr(GetLastError());
|
||||
t->tree_errno = errno;
|
||||
|
||||
@@ -188,9 +188,18 @@ used when translating file names.
|
||||
.El
|
||||
.It Format cpio
|
||||
.Bl -tag -compact -width indent
|
||||
.It Cm compat-2x
|
||||
Libarchive 2.x incorrectly encoded Unicode filenames on
|
||||
some platforms.
|
||||
This option mimics the libarchive 2.x filename handling
|
||||
so that such archives can be read correctly.
|
||||
.It Cm hdrcharset
|
||||
The value is used as a character set name that will be
|
||||
used when translating file names.
|
||||
.It Cm pwb
|
||||
When reading a binary CPIO archive, assume that it is
|
||||
in the original PWB cpio format, and handle file mode
|
||||
bits accordingly. The default is to assume v7 format.
|
||||
.El
|
||||
.It Format iso9660
|
||||
.Bl -tag -compact -width indent
|
||||
|
||||
@@ -216,7 +216,7 @@ rpm_filter_read(struct archive_read_filter *self, const void **buff)
|
||||
archive_set_error(
|
||||
&self->archive->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Unrecoginized rpm header");
|
||||
"Unrecognized rpm header");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
rpm->state = ST_ARCHIVE;
|
||||
|
||||
@@ -248,7 +248,7 @@ bid_get_line(struct archive_read_filter *filter,
|
||||
*ravail = *avail;
|
||||
*b += diff;
|
||||
*avail -= diff;
|
||||
tested = len;/* Skip some bytes we already determinated. */
|
||||
tested = len;/* Skip some bytes we already determined. */
|
||||
len = get_line(*b + tested, *avail - tested, nl);
|
||||
if (len >= 0)
|
||||
len += tested;
|
||||
|
||||
@@ -808,8 +808,12 @@ archive_read_format_7zip_read_data(struct archive_read *a,
|
||||
if (zip->end_of_entry)
|
||||
return (ARCHIVE_EOF);
|
||||
|
||||
bytes = read_stream(a, buff,
|
||||
(size_t)zip->entry_bytes_remaining, 0);
|
||||
const uint64_t max_read_size = 16 * 1024 * 1024; // Don't try to read more than 16 MB at a time
|
||||
size_t bytes_to_read = max_read_size;
|
||||
if ((uint64_t)bytes_to_read > zip->entry_bytes_remaining) {
|
||||
bytes_to_read = zip->entry_bytes_remaining;
|
||||
}
|
||||
bytes = read_stream(a, buff, bytes_to_read, 0);
|
||||
if (bytes < 0)
|
||||
return ((int)bytes);
|
||||
if (bytes == 0) {
|
||||
@@ -1493,7 +1497,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
|
||||
zip->ppmd7_stat = -1;
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_MISC,
|
||||
"Failed to initialize PPMd range decorder");
|
||||
"Failed to initialize PPMd range decoder");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
if (zip->ppstream.overconsumed) {
|
||||
@@ -3031,10 +3035,10 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
|
||||
"Truncated 7-Zip file body");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining)
|
||||
if ((uint64_t)bytes_avail > zip->pack_stream_inbytes_remaining)
|
||||
bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;
|
||||
zip->pack_stream_inbytes_remaining -= bytes_avail;
|
||||
if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining)
|
||||
if ((uint64_t)bytes_avail > zip->folder_outbytes_remaining)
|
||||
bytes_avail = (ssize_t)zip->folder_outbytes_remaining;
|
||||
zip->folder_outbytes_remaining -= bytes_avail;
|
||||
zip->uncompressed_buffer_bytes_remaining = bytes_avail;
|
||||
|
||||
@@ -2110,7 +2110,6 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
|
||||
ds->pos_tbl = malloc(sizeof(ds->pos_tbl[0]) * w_slot);
|
||||
if (ds->pos_tbl == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
lzx_huffman_free(&(ds->mt));
|
||||
}
|
||||
|
||||
for (footer = 0; footer < 18; footer++)
|
||||
|
||||
@@ -185,6 +185,8 @@ struct cpio {
|
||||
struct archive_string_conv *opt_sconv;
|
||||
struct archive_string_conv *sconv_default;
|
||||
int init_default_conversion;
|
||||
|
||||
int option_pwb;
|
||||
};
|
||||
|
||||
static int64_t atol16(const char *, unsigned);
|
||||
@@ -343,6 +345,10 @@ archive_read_format_cpio_options(struct archive_read *a,
|
||||
ret = ARCHIVE_FATAL;
|
||||
}
|
||||
return (ret);
|
||||
} else if (strcmp(key, "pwb") == 0) {
|
||||
if (val != NULL && val[0] != 0)
|
||||
cpio->option_pwb = 1;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/* Note: The "warn" return is just to inform the options
|
||||
@@ -891,6 +897,12 @@ header_bin_le(struct archive_read *a, struct cpio *cpio,
|
||||
archive_entry_set_dev(entry, header[bin_dev_offset] + header[bin_dev_offset + 1] * 256);
|
||||
archive_entry_set_ino(entry, header[bin_ino_offset] + header[bin_ino_offset + 1] * 256);
|
||||
archive_entry_set_mode(entry, header[bin_mode_offset] + header[bin_mode_offset + 1] * 256);
|
||||
if (cpio->option_pwb) {
|
||||
/* turn off random bits left over from V6 inode */
|
||||
archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
|
||||
if ((archive_entry_mode(entry) & AE_IFMT) == 0)
|
||||
archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
|
||||
}
|
||||
archive_entry_set_uid(entry, header[bin_uid_offset] + header[bin_uid_offset + 1] * 256);
|
||||
archive_entry_set_gid(entry, header[bin_gid_offset] + header[bin_gid_offset + 1] * 256);
|
||||
archive_entry_set_nlink(entry, header[bin_nlink_offset] + header[bin_nlink_offset + 1] * 256);
|
||||
@@ -930,6 +942,12 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
|
||||
archive_entry_set_dev(entry, header[bin_dev_offset] * 256 + header[bin_dev_offset + 1]);
|
||||
archive_entry_set_ino(entry, header[bin_ino_offset] * 256 + header[bin_ino_offset + 1]);
|
||||
archive_entry_set_mode(entry, header[bin_mode_offset] * 256 + header[bin_mode_offset + 1]);
|
||||
if (cpio->option_pwb) {
|
||||
/* turn off random bits left over from V6 inode */
|
||||
archive_entry_set_mode(entry, archive_entry_mode(entry) & 067777);
|
||||
if ((archive_entry_mode(entry) & AE_IFMT) == 0)
|
||||
archive_entry_set_mode(entry, archive_entry_mode(entry) | AE_IFREG);
|
||||
}
|
||||
archive_entry_set_uid(entry, header[bin_uid_offset] * 256 + header[bin_uid_offset + 1]);
|
||||
archive_entry_set_gid(entry, header[bin_gid_offset] * 256 + header[bin_gid_offset + 1]);
|
||||
archive_entry_set_nlink(entry, header[bin_nlink_offset] * 256 + header[bin_nlink_offset + 1]);
|
||||
|
||||
@@ -408,7 +408,7 @@ next_line(struct archive_read *a,
|
||||
*ravail = *avail;
|
||||
*b += diff;
|
||||
*avail -= diff;
|
||||
tested = len;/* Skip some bytes we already determinated. */
|
||||
tested = len;/* Skip some bytes we already determined. */
|
||||
len = get_line_size(*b + len, *avail - len, nl);
|
||||
if (len >= 0)
|
||||
len += tested;
|
||||
@@ -1074,7 +1074,7 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
|
||||
continue;
|
||||
/* Non-printable characters are not allowed */
|
||||
for (s = p;s < p + len - 1; s++) {
|
||||
if (!isprint(*s)) {
|
||||
if (!isprint((unsigned char)*s)) {
|
||||
r = ARCHIVE_FATAL;
|
||||
break;
|
||||
}
|
||||
@@ -2035,13 +2035,13 @@ mtree_atol(char **p, int base)
|
||||
|
||||
if (**p == '-') {
|
||||
limit = INT64_MIN / base;
|
||||
last_digit_limit = INT64_MIN % base;
|
||||
last_digit_limit = -(INT64_MIN % base);
|
||||
++(*p);
|
||||
|
||||
l = 0;
|
||||
digit = parsedigit(**p);
|
||||
while (digit >= 0 && digit < base) {
|
||||
if (l < limit || (l == limit && digit > last_digit_limit))
|
||||
if (l < limit || (l == limit && digit >= last_digit_limit))
|
||||
return INT64_MIN;
|
||||
l = (l * base) - digit;
|
||||
digit = parsedigit(*++(*p));
|
||||
|
||||
@@ -958,17 +958,17 @@ archive_read_format_rar_read_header(struct archive_read *a,
|
||||
crc32_val = 0;
|
||||
while (skip > 0) {
|
||||
size_t to_read = skip;
|
||||
ssize_t did_read;
|
||||
if (to_read > 32 * 1024) {
|
||||
if (to_read > 32 * 1024)
|
||||
to_read = 32 * 1024;
|
||||
}
|
||||
if ((h = __archive_read_ahead(a, to_read, &did_read)) == NULL) {
|
||||
if ((h = __archive_read_ahead(a, to_read, NULL)) == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Bad RAR file");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
p = h;
|
||||
crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned)did_read);
|
||||
__archive_read_consume(a, did_read);
|
||||
skip -= did_read;
|
||||
crc32_val = crc32(crc32_val, (const unsigned char *)p, to_read);
|
||||
__archive_read_consume(a, to_read);
|
||||
skip -= to_read;
|
||||
}
|
||||
if ((crc32_val & 0xffff) != crc32_expected) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
|
||||
@@ -1012,7 +1012,16 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) {
|
||||
static int read_bits_32(struct archive_read* a, struct rar5* rar,
|
||||
const uint8_t* p, uint32_t* value)
|
||||
{
|
||||
if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Premature end of stream during extraction of data (#1)");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
uint32_t bits = ((uint32_t) p[rar->bits.in_addr]) << 24;
|
||||
bits |= p[rar->bits.in_addr + 1] << 16;
|
||||
bits |= p[rar->bits.in_addr + 2] << 8;
|
||||
@@ -1023,7 +1032,16 @@ static int read_bits_32(struct rar5* rar, const uint8_t* p, uint32_t* value) {
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int read_bits_16(struct rar5* rar, const uint8_t* p, uint16_t* value) {
|
||||
static int read_bits_16(struct archive_read* a, struct rar5* rar,
|
||||
const uint8_t* p, uint16_t* value)
|
||||
{
|
||||
if(rar->bits.in_addr >= rar->cstate.cur_block_size) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Premature end of stream during extraction of data (#2)");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
int bits = (int) ((uint32_t) p[rar->bits.in_addr]) << 16;
|
||||
bits |= (int) p[rar->bits.in_addr + 1] << 8;
|
||||
bits |= (int) p[rar->bits.in_addr + 2];
|
||||
@@ -1039,8 +1057,8 @@ static void skip_bits(struct rar5* rar, int bits) {
|
||||
}
|
||||
|
||||
/* n = up to 16 */
|
||||
static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n,
|
||||
int* value)
|
||||
static int read_consume_bits(struct archive_read* a, struct rar5* rar,
|
||||
const uint8_t* p, int n, int* value)
|
||||
{
|
||||
uint16_t v;
|
||||
int ret, num;
|
||||
@@ -1051,7 +1069,7 @@ static int read_consume_bits(struct rar5* rar, const uint8_t* p, int n,
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
ret = read_bits_16(rar, p, &v);
|
||||
ret = read_bits_16(a, rar, p, &v);
|
||||
if(ret != ARCHIVE_OK)
|
||||
return ret;
|
||||
|
||||
@@ -1712,14 +1730,29 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're currently switching volumes, ignore the new definition of
|
||||
* window_size. */
|
||||
if(rar->cstate.switch_multivolume == 0) {
|
||||
/* Values up to 64M should fit into ssize_t on every
|
||||
* architecture. */
|
||||
rar->cstate.window_size = (ssize_t) window_size;
|
||||
if(rar->cstate.window_size < (ssize_t) window_size &&
|
||||
rar->cstate.window_buf)
|
||||
{
|
||||
/* If window_buf has been allocated before, reallocate it, so
|
||||
* that its size will match new window_size. */
|
||||
|
||||
uint8_t* new_window_buf =
|
||||
realloc(rar->cstate.window_buf, window_size);
|
||||
|
||||
if(!new_window_buf) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
|
||||
"Not enough memory when trying to realloc the window "
|
||||
"buffer.");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar->cstate.window_buf = new_window_buf;
|
||||
}
|
||||
|
||||
/* Values up to 64M should fit into ssize_t on every
|
||||
* architecture. */
|
||||
rar->cstate.window_size = (ssize_t) window_size;
|
||||
|
||||
if(rar->file.solid > 0 && rar->file.solid_window_size == 0) {
|
||||
/* Solid files have to have the same window_size across
|
||||
whole archive. Remember the window_size parameter
|
||||
@@ -2425,13 +2458,13 @@ static int create_decode_tables(uint8_t* bit_length,
|
||||
static int decode_number(struct archive_read* a, struct decode_table* table,
|
||||
const uint8_t* p, uint16_t* num)
|
||||
{
|
||||
int i, bits, dist;
|
||||
int i, bits, dist, ret;
|
||||
uint16_t bitfield;
|
||||
uint32_t pos;
|
||||
struct rar5* rar = get_context(a);
|
||||
|
||||
if(ARCHIVE_OK != read_bits_16(rar, p, &bitfield)) {
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &bitfield))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
bitfield &= 0xfffe;
|
||||
@@ -2537,14 +2570,6 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
for(i = 0; i < HUFF_TABLE_SIZE;) {
|
||||
uint16_t num;
|
||||
|
||||
if((rar->bits.in_addr + 6) >= rar->cstate.cur_block_size) {
|
||||
/* Truncated data, can't continue. */
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Truncated data in huffman tables (#2)");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
ret = decode_number(a, &rar->cstate.bd, p, &num);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive,
|
||||
@@ -2561,8 +2586,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
/* 16..17: repeat previous code */
|
||||
uint16_t n;
|
||||
|
||||
if(ARCHIVE_OK != read_bits_16(rar, p, &n))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
|
||||
return ret;
|
||||
|
||||
if(num == 16) {
|
||||
n >>= 13;
|
||||
@@ -2590,8 +2615,8 @@ static int parse_tables(struct archive_read* a, struct rar5* rar,
|
||||
/* other codes: fill with zeroes `n` times */
|
||||
uint16_t n;
|
||||
|
||||
if(ARCHIVE_OK != read_bits_16(rar, p, &n))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &n)))
|
||||
return ret;
|
||||
|
||||
if(num == 18) {
|
||||
n >>= 13;
|
||||
@@ -2707,22 +2732,22 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
|
||||
}
|
||||
|
||||
/* Convenience function used during filter processing. */
|
||||
static int parse_filter_data(struct rar5* rar, const uint8_t* p,
|
||||
uint32_t* filter_data)
|
||||
static int parse_filter_data(struct archive_read* a, struct rar5* rar,
|
||||
const uint8_t* p, uint32_t* filter_data)
|
||||
{
|
||||
int i, bytes;
|
||||
int i, bytes, ret;
|
||||
uint32_t data = 0;
|
||||
|
||||
if(ARCHIVE_OK != read_consume_bits(rar, p, 2, &bytes))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar, p, 2, &bytes)))
|
||||
return ret;
|
||||
|
||||
bytes++;
|
||||
|
||||
for(i = 0; i < bytes; i++) {
|
||||
uint16_t byte;
|
||||
|
||||
if(ARCHIVE_OK != read_bits_16(rar, p, &byte)) {
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(a, rar, p, &byte))) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Cast to uint32_t will ensure the shift operation will not
|
||||
@@ -2765,16 +2790,17 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
|
||||
uint16_t filter_type;
|
||||
struct filter_info* filt = NULL;
|
||||
struct rar5* rar = get_context(ar);
|
||||
int ret;
|
||||
|
||||
/* Read the parameters from the input stream. */
|
||||
if(ARCHIVE_OK != parse_filter_data(rar, p, &block_start))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_start)))
|
||||
return ret;
|
||||
|
||||
if(ARCHIVE_OK != parse_filter_data(rar, p, &block_length))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = parse_filter_data(ar, rar, p, &block_length)))
|
||||
return ret;
|
||||
|
||||
if(ARCHIVE_OK != read_bits_16(rar, p, &filter_type))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = read_bits_16(ar, rar, p, &filter_type)))
|
||||
return ret;
|
||||
|
||||
filter_type >>= 13;
|
||||
skip_bits(rar, 3);
|
||||
@@ -2814,8 +2840,8 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
|
||||
if(filter_type == FILTER_DELTA) {
|
||||
int channels;
|
||||
|
||||
if(ARCHIVE_OK != read_consume_bits(rar, p, 5, &channels))
|
||||
return ARCHIVE_EOF;
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(ar, rar, p, 5, &channels)))
|
||||
return ret;
|
||||
|
||||
filt->channels = channels + 1;
|
||||
}
|
||||
@@ -2823,10 +2849,11 @@ static int parse_filter(struct archive_read* ar, const uint8_t* p) {
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
static int decode_code_length(struct rar5* rar, const uint8_t* p,
|
||||
uint16_t code)
|
||||
static int decode_code_length(struct archive_read* a, struct rar5* rar,
|
||||
const uint8_t* p, uint16_t code)
|
||||
{
|
||||
int lbits, length = 2;
|
||||
|
||||
if(code < 8) {
|
||||
lbits = 0;
|
||||
length += code;
|
||||
@@ -2838,7 +2865,7 @@ static int decode_code_length(struct rar5* rar, const uint8_t* p,
|
||||
if(lbits > 0) {
|
||||
int add;
|
||||
|
||||
if(ARCHIVE_OK != read_consume_bits(rar, p, lbits, &add))
|
||||
if(ARCHIVE_OK != read_consume_bits(a, rar, p, lbits, &add))
|
||||
return -1;
|
||||
|
||||
length += add;
|
||||
@@ -2933,7 +2960,7 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
continue;
|
||||
} else if(num >= 262) {
|
||||
uint16_t dist_slot;
|
||||
int len = decode_code_length(rar, p, num - 262),
|
||||
int len = decode_code_length(a, rar, p, num - 262),
|
||||
dbits,
|
||||
dist = 1;
|
||||
|
||||
@@ -2975,12 +3002,12 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
uint16_t low_dist;
|
||||
|
||||
if(dbits > 4) {
|
||||
if(ARCHIVE_OK != read_bits_32(
|
||||
rar, p, &add)) {
|
||||
if(ARCHIVE_OK != (ret = read_bits_32(
|
||||
a, rar, p, &add))) {
|
||||
/* Return EOF if we
|
||||
* can't read more
|
||||
* data. */
|
||||
return ARCHIVE_EOF;
|
||||
return ret;
|
||||
}
|
||||
|
||||
skip_bits(rar, dbits - 4);
|
||||
@@ -3015,11 +3042,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
/* dbits is one of [0,1,2,3] */
|
||||
int add;
|
||||
|
||||
if(ARCHIVE_OK != read_consume_bits(rar,
|
||||
p, dbits, &add)) {
|
||||
if(ARCHIVE_OK != (ret = read_consume_bits(a, rar,
|
||||
p, dbits, &add))) {
|
||||
/* Return EOF if we can't read
|
||||
* more data. */
|
||||
return ARCHIVE_EOF;
|
||||
return ret;
|
||||
}
|
||||
|
||||
dist += add;
|
||||
@@ -3076,7 +3103,11 @@ static int do_uncompress_block(struct archive_read* a, const uint8_t* p) {
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
len = decode_code_length(rar, p, len_slot);
|
||||
len = decode_code_length(a, rar, p, len_slot);
|
||||
if (len == -1) {
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
rar->cstate.last_len = len;
|
||||
|
||||
if(ARCHIVE_OK != copy_string(a, len, dist))
|
||||
@@ -3600,6 +3631,16 @@ static int do_uncompress_file(struct archive_read* a) {
|
||||
rar->cstate.initialized = 1;
|
||||
}
|
||||
|
||||
/* Don't allow extraction if window_size is invalid. */
|
||||
if(rar->cstate.window_size == 0) {
|
||||
archive_set_error(&a->archive,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Invalid window size declaration in this file");
|
||||
|
||||
/* This should never happen in valid files. */
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if(rar->cstate.all_filters_applied == 1) {
|
||||
/* We use while(1) here, but standard case allows for just 1
|
||||
* iteration. The loop will iterate if process_block() didn't
|
||||
@@ -4076,6 +4117,7 @@ int archive_read_support_format_rar5(struct archive *_a) {
|
||||
if(ARCHIVE_OK != rar5_init(rar)) {
|
||||
archive_set_error(&ar->archive, ENOMEM,
|
||||
"Can't allocate rar5 filter buffer");
|
||||
free(rar);
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -1906,7 +1906,7 @@ pax_attribute(struct archive_read *a, struct tar *tar,
|
||||
}
|
||||
if (strcmp(key, "GNU.sparse.numbytes") == 0) {
|
||||
tar->sparse_numbytes = tar_atol10(value, strlen(value));
|
||||
if (tar->sparse_numbytes != -1) {
|
||||
if (tar->sparse_offset != -1) {
|
||||
if (gnu_add_sparse_entry(a, tar,
|
||||
tar->sparse_offset, tar->sparse_numbytes)
|
||||
!= ARCHIVE_OK)
|
||||
@@ -2643,14 +2643,14 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
|
||||
|
||||
maxval = INT64_MIN;
|
||||
limit = -(INT64_MIN / base);
|
||||
last_digit_limit = INT64_MIN % base;
|
||||
last_digit_limit = -(INT64_MIN % base);
|
||||
}
|
||||
|
||||
l = 0;
|
||||
if (char_cnt != 0) {
|
||||
digit = *p - '0';
|
||||
while (digit >= 0 && digit < base && char_cnt != 0) {
|
||||
if (l>limit || (l == limit && digit > last_digit_limit)) {
|
||||
if (l>limit || (l == limit && digit >= last_digit_limit)) {
|
||||
return maxval; /* Truncate on overflow. */
|
||||
}
|
||||
l = (l * base) + digit;
|
||||
|
||||
@@ -142,6 +142,7 @@ struct zip {
|
||||
/* Structural information about the archive. */
|
||||
struct archive_string format_name;
|
||||
int64_t central_directory_offset;
|
||||
int64_t central_directory_offset_adjusted;
|
||||
size_t central_directory_entries_total;
|
||||
size_t central_directory_entries_on_this_disk;
|
||||
int has_encrypted_entries;
|
||||
@@ -246,6 +247,17 @@ struct zip {
|
||||
/* Many systems define min or MIN, but not all. */
|
||||
#define zipmin(a,b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#ifdef HAVE_ZLIB_H
|
||||
static int
|
||||
zip_read_data_deflate(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset);
|
||||
#endif
|
||||
#if HAVE_LZMA_H && HAVE_LIBLZMA
|
||||
static int
|
||||
zip_read_data_zipx_lzma_alone(struct archive_read *a, const void **buff,
|
||||
size_t *size, int64_t *offset);
|
||||
#endif
|
||||
|
||||
/* This function is used by Ppmd8_DecodeSymbol during decompression of Ppmd8
|
||||
* streams inside ZIP files. It has 2 purposes: one is to fetch the next
|
||||
* compressed byte from the stream, second one is to increase the counter how
|
||||
@@ -899,81 +911,6 @@ process_extra(struct archive_read *a, struct archive_entry *entry,
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
#if HAVE_LZMA_H && HAVE_LIBLZMA
|
||||
/*
|
||||
* Auxiliary function to uncompress data chunk from zipx archive
|
||||
* (zip with lzma compression).
|
||||
*/
|
||||
static int
|
||||
zipx_lzma_uncompress_buffer(const char *compressed_buffer,
|
||||
size_t compressed_buffer_size,
|
||||
char *uncompressed_buffer,
|
||||
size_t uncompressed_buffer_size)
|
||||
{
|
||||
int status = ARCHIVE_FATAL;
|
||||
// length of 'lzma properties data' in lzma compressed
|
||||
// data segment (stream) inside zip archive
|
||||
const size_t lzma_params_length = 5;
|
||||
// offset of 'lzma properties data' from the beginning of lzma stream
|
||||
const size_t lzma_params_offset = 4;
|
||||
// end position of 'lzma properties data' in lzma stream
|
||||
const size_t lzma_params_end = lzma_params_offset + lzma_params_length;
|
||||
if (compressed_buffer == NULL ||
|
||||
compressed_buffer_size < lzma_params_end ||
|
||||
uncompressed_buffer == NULL)
|
||||
return status;
|
||||
|
||||
// prepare header for lzma_alone_decoder to replace zipx header
|
||||
// (see comments in 'zipx_lzma_alone_init' for justification)
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
struct _alone_header
|
||||
{
|
||||
uint8_t bytes[5]; // lzma_params_length
|
||||
uint64_t uncompressed_size;
|
||||
} alone_header;
|
||||
#pragma pack(pop)
|
||||
// copy 'lzma properties data' blob
|
||||
memcpy(&alone_header.bytes[0], compressed_buffer + lzma_params_offset,
|
||||
lzma_params_length);
|
||||
alone_header.uncompressed_size = UINT64_MAX;
|
||||
|
||||
// prepare new compressed buffer, see 'zipx_lzma_alone_init' for details
|
||||
const size_t lzma_alone_buffer_size =
|
||||
compressed_buffer_size - lzma_params_end + sizeof(alone_header);
|
||||
unsigned char *lzma_alone_compressed_buffer =
|
||||
(unsigned char*) malloc(lzma_alone_buffer_size);
|
||||
if (lzma_alone_compressed_buffer == NULL)
|
||||
return status;
|
||||
// copy lzma_alone header into new buffer
|
||||
memcpy(lzma_alone_compressed_buffer, (void*) &alone_header,
|
||||
sizeof(alone_header));
|
||||
// copy compressed data into new buffer
|
||||
memcpy(lzma_alone_compressed_buffer + sizeof(alone_header),
|
||||
compressed_buffer + lzma_params_end,
|
||||
compressed_buffer_size - lzma_params_end);
|
||||
|
||||
// create and fill in lzma_alone_decoder stream
|
||||
lzma_stream stream = LZMA_STREAM_INIT;
|
||||
lzma_ret ret = lzma_alone_decoder(&stream, UINT64_MAX);
|
||||
if (ret == LZMA_OK)
|
||||
{
|
||||
stream.next_in = lzma_alone_compressed_buffer;
|
||||
stream.avail_in = lzma_alone_buffer_size;
|
||||
stream.total_in = 0;
|
||||
stream.next_out = (unsigned char*)uncompressed_buffer;
|
||||
stream.avail_out = uncompressed_buffer_size;
|
||||
stream.total_out = 0;
|
||||
ret = lzma_code(&stream, LZMA_RUN);
|
||||
if (ret == LZMA_OK || ret == LZMA_STREAM_END)
|
||||
status = ARCHIVE_OK;
|
||||
}
|
||||
lzma_end(&stream);
|
||||
free(lzma_alone_compressed_buffer);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Assumes file pointer is at beginning of local file header.
|
||||
*/
|
||||
@@ -1242,36 +1179,30 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
||||
linkname_length = (size_t)zip_entry->compressed_size;
|
||||
|
||||
archive_entry_set_size(entry, 0);
|
||||
p = __archive_read_ahead(a, linkname_length, NULL);
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Truncated Zip file");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
// take into account link compression if any
|
||||
size_t linkname_full_length = linkname_length;
|
||||
if (zip->entry->compression != 0)
|
||||
{
|
||||
// symlink target string appeared to be compressed
|
||||
int status = ARCHIVE_FATAL;
|
||||
char *uncompressed_buffer =
|
||||
(char*) malloc(zip_entry->uncompressed_size);
|
||||
if (uncompressed_buffer == NULL)
|
||||
{
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"No memory for lzma decompression");
|
||||
return status;
|
||||
}
|
||||
const void *uncompressed_buffer;
|
||||
|
||||
switch (zip->entry->compression)
|
||||
{
|
||||
#if HAVE_ZLIB_H
|
||||
case 8: /* Deflate compression. */
|
||||
zip->entry_bytes_remaining = zip_entry->compressed_size;
|
||||
status = zip_read_data_deflate(a, &uncompressed_buffer,
|
||||
&linkname_full_length, NULL);
|
||||
break;
|
||||
#endif
|
||||
#if HAVE_LZMA_H && HAVE_LIBLZMA
|
||||
case 14: /* ZIPx LZMA compression. */
|
||||
/*(see zip file format specification, section 4.4.5)*/
|
||||
status = zipx_lzma_uncompress_buffer(p,
|
||||
linkname_length,
|
||||
uncompressed_buffer,
|
||||
(size_t)zip_entry->uncompressed_size);
|
||||
zip->entry_bytes_remaining = zip_entry->compressed_size;
|
||||
status = zip_read_data_zipx_lzma_alone(a, &uncompressed_buffer,
|
||||
&linkname_full_length, NULL);
|
||||
break;
|
||||
#endif
|
||||
default: /* Unsupported compression. */
|
||||
@@ -1280,8 +1211,6 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
||||
if (status == ARCHIVE_OK)
|
||||
{
|
||||
p = uncompressed_buffer;
|
||||
linkname_full_length =
|
||||
(size_t)zip_entry->uncompressed_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1294,6 +1223,16 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
|
||||
return ARCHIVE_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
p = __archive_read_ahead(a, linkname_length, NULL);
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Truncated Zip file");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
sconv = zip->sconv;
|
||||
if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME))
|
||||
@@ -1663,7 +1602,8 @@ zipx_lzma_alone_init(struct archive_read *a, struct zip *zip)
|
||||
/* To unpack ZIPX's "LZMA" (id 14) stream we can use standard liblzma
|
||||
* that is a part of XZ Utils. The stream format stored inside ZIPX
|
||||
* file is a modified "lzma alone" file format, that was used by the
|
||||
* `lzma` utility which was later deprecated in favour of `xz` utility. * Since those formats are nearly the same, we can use a standard
|
||||
* `lzma` utility which was later deprecated in favour of `xz` utility.
|
||||
* Since those formats are nearly the same, we can use a standard
|
||||
* "lzma alone" decoder from XZ Utils. */
|
||||
|
||||
memset(&zip->zipx_lzma_stream, 0, sizeof(zip->zipx_lzma_stream));
|
||||
@@ -3415,24 +3355,31 @@ archive_read_support_format_zip_capabilities_seekable(struct archive_read * a)
|
||||
static int
|
||||
read_eocd(struct zip *zip, const char *p, int64_t current_offset)
|
||||
{
|
||||
uint16_t disk_num;
|
||||
uint32_t cd_size, cd_offset;
|
||||
|
||||
disk_num = archive_le16dec(p + 4);
|
||||
cd_size = archive_le32dec(p + 12);
|
||||
cd_offset = archive_le32dec(p + 16);
|
||||
|
||||
/* Sanity-check the EOCD we've found. */
|
||||
|
||||
/* This must be the first volume. */
|
||||
if (archive_le16dec(p + 4) != 0)
|
||||
if (disk_num != 0)
|
||||
return 0;
|
||||
/* Central directory must be on this volume. */
|
||||
if (archive_le16dec(p + 4) != archive_le16dec(p + 6))
|
||||
if (disk_num != archive_le16dec(p + 6))
|
||||
return 0;
|
||||
/* All central directory entries must be on this volume. */
|
||||
if (archive_le16dec(p + 10) != archive_le16dec(p + 8))
|
||||
return 0;
|
||||
/* Central directory can't extend beyond start of EOCD record. */
|
||||
if (archive_le32dec(p + 16) + archive_le32dec(p + 12)
|
||||
> current_offset)
|
||||
if (cd_offset + cd_size > current_offset)
|
||||
return 0;
|
||||
|
||||
/* Save the central directory location for later use. */
|
||||
zip->central_directory_offset = archive_le32dec(p + 16);
|
||||
zip->central_directory_offset = cd_offset;
|
||||
zip->central_directory_offset_adjusted = current_offset - cd_size;
|
||||
|
||||
/* This is just a tiny bit higher than the maximum
|
||||
returned by the streaming Zip bidder. This ensures
|
||||
@@ -3484,6 +3431,8 @@ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)
|
||||
|
||||
/* Save the central directory offset for later use. */
|
||||
zip->central_directory_offset = archive_le64dec(p + 48);
|
||||
/* TODO: Needs scanning backwards to find the eocd64 instead of assuming */
|
||||
zip->central_directory_offset_adjusted = zip->central_directory_offset;
|
||||
|
||||
return 32;
|
||||
}
|
||||
@@ -3655,7 +3604,8 @@ slurp_central_directory(struct archive_read *a, struct archive_entry* entry,
|
||||
* know the correction we need to apply to account for leading
|
||||
* padding.
|
||||
*/
|
||||
if (__archive_read_seek(a, zip->central_directory_offset, SEEK_SET) < 0)
|
||||
if (__archive_read_seek(a, zip->central_directory_offset_adjusted, SEEK_SET)
|
||||
< 0)
|
||||
return ARCHIVE_FATAL;
|
||||
|
||||
found = 0;
|
||||
|
||||
@@ -482,6 +482,8 @@ archive_write_client_close(struct archive_write_filter *f)
|
||||
ssize_t block_length;
|
||||
ssize_t target_block_length;
|
||||
ssize_t bytes_written;
|
||||
size_t to_write;
|
||||
char *p;
|
||||
int ret = ARCHIVE_OK;
|
||||
|
||||
/* If there's pending data, pad and write the last block */
|
||||
@@ -504,9 +506,24 @@ archive_write_client_close(struct archive_write_filter *f)
|
||||
target_block_length - block_length);
|
||||
block_length = target_block_length;
|
||||
}
|
||||
bytes_written = (a->client_writer)(&a->archive,
|
||||
a->client_data, state->buffer, block_length);
|
||||
ret = bytes_written <= 0 ? ARCHIVE_FATAL : ARCHIVE_OK;
|
||||
p = state->buffer;
|
||||
to_write = block_length;
|
||||
while (to_write > 0) {
|
||||
bytes_written = (a->client_writer)(&a->archive,
|
||||
a->client_data, p, to_write);
|
||||
if (bytes_written <= 0) {
|
||||
ret = ARCHIVE_FATAL;
|
||||
break;
|
||||
}
|
||||
if ((size_t)bytes_written > to_write) {
|
||||
archive_set_error(&(a->archive),
|
||||
-1, "write overrun");
|
||||
ret = ARCHIVE_FATAL;
|
||||
break;
|
||||
}
|
||||
p += bytes_written;
|
||||
to_write -= bytes_written;
|
||||
}
|
||||
}
|
||||
if (a->client_closer)
|
||||
(*a->client_closer)(&a->archive, a->client_data);
|
||||
|
||||
@@ -173,6 +173,7 @@ struct fixup_entry {
|
||||
struct fixup_entry *next;
|
||||
struct archive_acl acl;
|
||||
mode_t mode;
|
||||
__LA_MODE_T filetype;
|
||||
int64_t atime;
|
||||
int64_t birthtime;
|
||||
int64_t mtime;
|
||||
@@ -357,10 +358,11 @@ struct archive_write_disk {
|
||||
|
||||
static int la_opendirat(int, const char *);
|
||||
static int la_mktemp(struct archive_write_disk *);
|
||||
static int la_verify_filetype(mode_t, __LA_MODE_T);
|
||||
static void fsobj_error(int *, struct archive_string *, int, const char *,
|
||||
const char *);
|
||||
static int check_symlinks_fsobj(char *, int *, struct archive_string *,
|
||||
int);
|
||||
int, int);
|
||||
static int check_symlinks(struct archive_write_disk *);
|
||||
static int create_filesystem_object(struct archive_write_disk *);
|
||||
static struct fixup_entry *current_fixup(struct archive_write_disk *,
|
||||
@@ -464,6 +466,39 @@ la_opendirat(int fd, const char *path) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
la_verify_filetype(mode_t mode, __LA_MODE_T filetype) {
|
||||
int ret = 0;
|
||||
|
||||
switch (filetype) {
|
||||
case AE_IFREG:
|
||||
ret = (S_ISREG(mode));
|
||||
break;
|
||||
case AE_IFDIR:
|
||||
ret = (S_ISDIR(mode));
|
||||
break;
|
||||
case AE_IFLNK:
|
||||
ret = (S_ISLNK(mode));
|
||||
break;
|
||||
case AE_IFSOCK:
|
||||
ret = (S_ISSOCK(mode));
|
||||
break;
|
||||
case AE_IFCHR:
|
||||
ret = (S_ISCHR(mode));
|
||||
break;
|
||||
case AE_IFBLK:
|
||||
ret = (S_ISBLK(mode));
|
||||
break;
|
||||
case AE_IFIFO:
|
||||
ret = (S_ISFIFO(mode));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
lazy_stat(struct archive_write_disk *a)
|
||||
{
|
||||
@@ -822,6 +857,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
|
||||
fe = current_fixup(a, archive_entry_pathname(entry));
|
||||
if (fe == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
fe->filetype = archive_entry_filetype(entry);
|
||||
fe->fixup |= TODO_MODE_BASE;
|
||||
fe->mode = a->mode;
|
||||
}
|
||||
@@ -832,6 +868,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
|
||||
fe = current_fixup(a, archive_entry_pathname(entry));
|
||||
if (fe == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
fe->filetype = archive_entry_filetype(entry);
|
||||
fe->mode = a->mode;
|
||||
fe->fixup |= TODO_TIMES;
|
||||
if (archive_entry_atime_is_set(entry)) {
|
||||
@@ -865,6 +902,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
|
||||
fe = current_fixup(a, archive_entry_pathname(entry));
|
||||
if (fe == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
fe->filetype = archive_entry_filetype(entry);
|
||||
fe->fixup |= TODO_ACLS;
|
||||
archive_acl_copy(&fe->acl, archive_entry_acl(entry));
|
||||
}
|
||||
@@ -877,6 +915,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
|
||||
fe = current_fixup(a, archive_entry_pathname(entry));
|
||||
if (fe == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
fe->filetype = archive_entry_filetype(entry);
|
||||
fe->mac_metadata = malloc(metadata_size);
|
||||
if (fe->mac_metadata != NULL) {
|
||||
memcpy(fe->mac_metadata, metadata,
|
||||
@@ -891,6 +930,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
|
||||
fe = current_fixup(a, archive_entry_pathname(entry));
|
||||
if (fe == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
fe->filetype = archive_entry_filetype(entry);
|
||||
fe->fixup |= TODO_FFLAGS;
|
||||
/* TODO: Complete this.. defer fflags from below. */
|
||||
}
|
||||
@@ -2263,7 +2303,7 @@ create_filesystem_object(struct archive_write_disk *a)
|
||||
return (EPERM);
|
||||
}
|
||||
r = check_symlinks_fsobj(linkname_copy, &error_number,
|
||||
&error_string, a->flags);
|
||||
&error_string, a->flags, 1);
|
||||
if (r != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, error_number, "%s",
|
||||
error_string.s);
|
||||
@@ -2284,7 +2324,12 @@ create_filesystem_object(struct archive_write_disk *a)
|
||||
*/
|
||||
if (a->flags & ARCHIVE_EXTRACT_SAFE_WRITES)
|
||||
unlink(a->name);
|
||||
#ifdef HAVE_LINKAT
|
||||
r = linkat(AT_FDCWD, linkname, AT_FDCWD, a->name,
|
||||
0) ? errno : 0;
|
||||
#else
|
||||
r = link(linkname, a->name) ? errno : 0;
|
||||
#endif
|
||||
/*
|
||||
* New cpio and pax formats allow hardlink entries
|
||||
* to carry data, so we may have to open the file
|
||||
@@ -2456,7 +2501,9 @@ _archive_write_disk_close(struct archive *_a)
|
||||
{
|
||||
struct archive_write_disk *a = (struct archive_write_disk *)_a;
|
||||
struct fixup_entry *next, *p;
|
||||
int fd, ret;
|
||||
struct stat st;
|
||||
char *c;
|
||||
int fd, ret, openflags;
|
||||
|
||||
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
|
||||
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
|
||||
@@ -2469,10 +2516,70 @@ _archive_write_disk_close(struct archive *_a)
|
||||
while (p != NULL) {
|
||||
fd = -1;
|
||||
a->pst = NULL; /* Mark stat cache as out-of-date. */
|
||||
if (p->fixup &
|
||||
(TODO_TIMES | TODO_MODE_BASE | TODO_ACLS | TODO_FFLAGS)) {
|
||||
fd = open(p->name,
|
||||
O_WRONLY | O_BINARY | O_NOFOLLOW | O_CLOEXEC);
|
||||
|
||||
/* We must strip trailing slashes from the path to avoid
|
||||
dereferencing symbolic links to directories */
|
||||
c = p->name;
|
||||
while (*c != '\0')
|
||||
c++;
|
||||
while (c != p->name && *(c - 1) == '/') {
|
||||
c--;
|
||||
*c = '\0';
|
||||
}
|
||||
|
||||
if (p->fixup == 0)
|
||||
goto skip_fixup_entry;
|
||||
else {
|
||||
/*
|
||||
* We need to verify if the type of the file
|
||||
* we are going to open matches the file type
|
||||
* of the fixup entry.
|
||||
*/
|
||||
openflags = O_BINARY | O_NOFOLLOW | O_RDONLY
|
||||
| O_CLOEXEC;
|
||||
#if defined(O_DIRECTORY)
|
||||
if (p->filetype == AE_IFDIR)
|
||||
openflags |= O_DIRECTORY;
|
||||
#endif
|
||||
fd = open(p->name, openflags);
|
||||
|
||||
#if defined(O_DIRECTORY)
|
||||
/*
|
||||
* If we support O_DIRECTORY and open was
|
||||
* successful we can skip the file type check
|
||||
* for directories. For other file types
|
||||
* we need to verify via fstat() or lstat()
|
||||
*/
|
||||
if (fd == -1 || p->filetype != AE_IFDIR) {
|
||||
#if HAVE_FSTAT
|
||||
if (fd > 0 && (
|
||||
fstat(fd, &st) != 0 ||
|
||||
la_verify_filetype(st.st_mode,
|
||||
p->filetype) == 0)) {
|
||||
goto skip_fixup_entry;
|
||||
} else
|
||||
#endif
|
||||
if (lstat(p->name, &st) != 0 ||
|
||||
la_verify_filetype(st.st_mode,
|
||||
p->filetype) == 0) {
|
||||
goto skip_fixup_entry;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#if HAVE_FSTAT
|
||||
if (fd > 0 && (
|
||||
fstat(fd, &st) != 0 ||
|
||||
la_verify_filetype(st.st_mode,
|
||||
p->filetype) == 0)) {
|
||||
goto skip_fixup_entry;
|
||||
} else
|
||||
#endif
|
||||
if (lstat(p->name, &st) != 0 ||
|
||||
la_verify_filetype(st.st_mode,
|
||||
p->filetype) == 0) {
|
||||
goto skip_fixup_entry;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (p->fixup & TODO_TIMES) {
|
||||
set_times(a, fd, p->mode, p->name,
|
||||
@@ -2484,10 +2591,14 @@ _archive_write_disk_close(struct archive *_a)
|
||||
if (p->fixup & TODO_MODE_BASE) {
|
||||
#ifdef HAVE_FCHMOD
|
||||
if (fd >= 0)
|
||||
fchmod(fd, p->mode);
|
||||
fchmod(fd, p->mode & 07777);
|
||||
else
|
||||
#endif
|
||||
chmod(p->name, p->mode);
|
||||
#ifdef HAVE_LCHMOD
|
||||
lchmod(p->name, p->mode & 07777);
|
||||
#else
|
||||
chmod(p->name, p->mode & 07777);
|
||||
#endif
|
||||
}
|
||||
if (p->fixup & TODO_ACLS)
|
||||
archive_write_disk_set_acls(&a->archive, fd,
|
||||
@@ -2498,6 +2609,7 @@ _archive_write_disk_close(struct archive *_a)
|
||||
if (p->fixup & TODO_MAC_METADATA)
|
||||
set_mac_metadata(a, p->name, p->mac_metadata,
|
||||
p->mac_metadata_size);
|
||||
skip_fixup_entry:
|
||||
next = p->next;
|
||||
archive_acl_clear(&p->acl);
|
||||
free(p->mac_metadata);
|
||||
@@ -2638,6 +2750,7 @@ new_fixup(struct archive_write_disk *a, const char *pathname)
|
||||
fe->next = a->fixup_list;
|
||||
a->fixup_list = fe;
|
||||
fe->fixup = 0;
|
||||
fe->filetype = 0;
|
||||
fe->name = strdup(pathname);
|
||||
return (fe);
|
||||
}
|
||||
@@ -2675,7 +2788,7 @@ fsobj_error(int *a_eno, struct archive_string *a_estr,
|
||||
*/
|
||||
static int
|
||||
check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
|
||||
int flags)
|
||||
int flags, int checking_linkname)
|
||||
{
|
||||
#if !defined(HAVE_LSTAT) && \
|
||||
!(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_UNLINKAT))
|
||||
@@ -2684,6 +2797,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
|
||||
(void)error_number; /* UNUSED */
|
||||
(void)error_string; /* UNUSED */
|
||||
(void)flags; /* UNUSED */
|
||||
(void)checking_linkname; /* UNUSED */
|
||||
return (ARCHIVE_OK);
|
||||
#else
|
||||
int res = ARCHIVE_OK;
|
||||
@@ -2805,6 +2919,28 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
|
||||
head = tail + 1;
|
||||
}
|
||||
} else if (S_ISLNK(st.st_mode)) {
|
||||
if (last && checking_linkname) {
|
||||
#ifdef HAVE_LINKAT
|
||||
/*
|
||||
* Hardlinks to symlinks are safe to write
|
||||
* if linkat() is supported as it does not
|
||||
* follow symlinks.
|
||||
*/
|
||||
res = ARCHIVE_OK;
|
||||
#else
|
||||
/*
|
||||
* We return ARCHIVE_FAILED here as we are
|
||||
* not able to safely write hardlinks
|
||||
* to symlinks.
|
||||
*/
|
||||
tail[0] = c;
|
||||
fsobj_error(a_eno, a_estr, errno,
|
||||
"Cannot write hardlink to symlink ",
|
||||
path);
|
||||
res = ARCHIVE_FAILED;
|
||||
#endif
|
||||
break;
|
||||
} else
|
||||
if (last) {
|
||||
/*
|
||||
* Last element is symlink; remove it
|
||||
@@ -2971,7 +3107,7 @@ check_symlinks(struct archive_write_disk *a)
|
||||
int rc;
|
||||
archive_string_init(&error_string);
|
||||
rc = check_symlinks_fsobj(a->name, &error_number, &error_string,
|
||||
a->flags);
|
||||
a->flags, 0);
|
||||
if (rc != ARCHIVE_OK) {
|
||||
archive_set_error(&a->archive, error_number, "%s",
|
||||
error_string.s);
|
||||
@@ -3737,6 +3873,7 @@ set_fflags(struct archive_write_disk *a)
|
||||
le = current_fixup(a, a->name);
|
||||
if (le == NULL)
|
||||
return (ARCHIVE_FATAL);
|
||||
le->filetype = archive_entry_filetype(a->entry);
|
||||
le->fixup |= TODO_FFLAGS;
|
||||
le->fflags_set = set;
|
||||
/* Store the mode if it's not already there. */
|
||||
@@ -3899,7 +4036,8 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
|
||||
|
||||
/* If we weren't given an fd, open it ourselves. */
|
||||
if (myfd < 0) {
|
||||
myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY | O_CLOEXEC);
|
||||
myfd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY |
|
||||
O_CLOEXEC | O_NOFOLLOW);
|
||||
__archive_ensure_cloexec_flag(myfd);
|
||||
}
|
||||
if (myfd < 0)
|
||||
|
||||
@@ -35,7 +35,10 @@
|
||||
.Nm archive_write_set_format_ar_svr4 ,
|
||||
.Nm archive_write_set_format_by_name ,
|
||||
.Nm archive_write_set_format_cpio ,
|
||||
.Nm archive_write_set_format_cpio_bin ,
|
||||
.Nm archive_write_set_format_cpio_newc ,
|
||||
.Nm archive_write_set_format_cpio_odc ,
|
||||
.Nm archive_write_set_format_cpio_pwb ,
|
||||
.Nm archive_write_set_format_filter_by_ext ,
|
||||
.Nm archive_write_set_format_filter_by_ext_def ,
|
||||
.Nm archive_write_set_format_gnutar ,
|
||||
@@ -73,8 +76,14 @@ Streaming Archive Library (libarchive, -larchive)
|
||||
.Ft int
|
||||
.Fn archive_write_set_format_cpio "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_write_set_format_cpio_bin "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_write_set_format_cpio_newc "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_write_set_format_cpio_odc "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_write_set_format_cpio_pwb "struct archive *"
|
||||
.Ft int
|
||||
.Fn archive_write_set_format_filter_by_ext "struct archive *" "const char *filename"
|
||||
.Ft int
|
||||
.Fn archive_write_set_format_filter_by_ext_def "struct archive *" "const char *filename" "const char *def_ext"
|
||||
@@ -119,17 +128,20 @@ to create a new archive with the same format as an existing archive.
|
||||
.It Fn archive_write_set_format_by_name
|
||||
Sets the corresponding format based on the common name.
|
||||
.It Xo
|
||||
.Fn archive_write_set_format_filter_by_ext ,
|
||||
.Fn archive_write_set_format_filter_by_ext
|
||||
.Fn archive_write_set_format_filter_by_ext_def
|
||||
.Xc
|
||||
Sets both filters and format based on the output filename.
|
||||
Supported extensions: .7z, .zip, .jar, .cpio, .iso, .a, .ar, .tar, .tgz, .tar.gz, .tar.bz2, .tar.xz
|
||||
.It Xo
|
||||
.Fn archive_write_set_format_7zip
|
||||
.Fn archive_write_set_format_ar_bsd ,
|
||||
.Fn archive_write_set_format_ar_svr4 ,
|
||||
.Fn archive_write_set_format_ar_bsd
|
||||
.Fn archive_write_set_format_ar_svr4
|
||||
.Fn archive_write_set_format_cpio
|
||||
.Fn archive_write_set_format_cpio_bin
|
||||
.Fn archive_write_set_format_cpio_newc
|
||||
.Fn archive_write_set_format_cpio_odc
|
||||
.Fn archive_write_set_format_cpio_pwb
|
||||
.Fn archive_write_set_format_gnutar
|
||||
.Fn archive_write_set_format_iso9660
|
||||
.Fn archive_write_set_format_mtree
|
||||
|
||||
@@ -44,7 +44,9 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
|
||||
{
|
||||
{ ARCHIVE_FORMAT_7ZIP, archive_write_set_format_7zip },
|
||||
{ ARCHIVE_FORMAT_CPIO, archive_write_set_format_cpio },
|
||||
{ ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio },
|
||||
{ ARCHIVE_FORMAT_CPIO_BIN_LE, archive_write_set_format_cpio_bin },
|
||||
{ ARCHIVE_FORMAT_CPIO_PWB, archive_write_set_format_cpio_pwb },
|
||||
{ ARCHIVE_FORMAT_CPIO_POSIX, archive_write_set_format_cpio_odc },
|
||||
{ ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, archive_write_set_format_cpio_newc },
|
||||
{ ARCHIVE_FORMAT_ISO9660, archive_write_set_format_iso9660 },
|
||||
{ ARCHIVE_FORMAT_MTREE, archive_write_set_format_mtree },
|
||||
|
||||
@@ -755,6 +755,10 @@ _7z_close(struct archive_write *a)
|
||||
*/
|
||||
#if HAVE_LZMA_H
|
||||
header_compression = _7Z_LZMA1;
|
||||
if(zip->opt_compression == _7Z_LZMA2 ||
|
||||
zip->opt_compression == _7Z_COPY)
|
||||
header_compression = zip->opt_compression;
|
||||
|
||||
/* If the stored file is only one, do not encode the header.
|
||||
* This is the same way 7z command does. */
|
||||
if (zip->total_number_entry == 1)
|
||||
@@ -762,7 +766,8 @@ _7z_close(struct archive_write *a)
|
||||
#else
|
||||
header_compression = _7Z_COPY;
|
||||
#endif
|
||||
r = _7z_compression_init_encoder(a, header_compression, 6);
|
||||
r = _7z_compression_init_encoder(a, header_compression,
|
||||
zip->opt_compression_level);
|
||||
if (r < 0)
|
||||
return (r);
|
||||
zip->crc32flg = PRECODE_CRC32;
|
||||
|
||||
@@ -49,6 +49,7 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
|
||||
{ "arbsd", archive_write_set_format_ar_bsd },
|
||||
{ "argnu", archive_write_set_format_ar_svr4 },
|
||||
{ "arsvr4", archive_write_set_format_ar_svr4 },
|
||||
{ "bin", archive_write_set_format_cpio_bin },
|
||||
{ "bsdtar", archive_write_set_format_pax_restricted },
|
||||
{ "cd9660", archive_write_set_format_iso9660 },
|
||||
{ "cpio", archive_write_set_format_cpio },
|
||||
@@ -58,11 +59,12 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
|
||||
{ "mtree", archive_write_set_format_mtree },
|
||||
{ "mtree-classic", archive_write_set_format_mtree_classic },
|
||||
{ "newc", archive_write_set_format_cpio_newc },
|
||||
{ "odc", archive_write_set_format_cpio },
|
||||
{ "odc", archive_write_set_format_cpio_odc },
|
||||
{ "oldtar", archive_write_set_format_v7tar },
|
||||
{ "pax", archive_write_set_format_pax },
|
||||
{ "paxr", archive_write_set_format_pax_restricted },
|
||||
{ "posix", archive_write_set_format_pax },
|
||||
{ "pwb", archive_write_set_format_cpio_pwb },
|
||||
{ "raw", archive_write_set_format_raw },
|
||||
{ "rpax", archive_write_set_format_pax_restricted },
|
||||
{ "shar", archive_write_set_format_shar },
|
||||
|
||||
@@ -1,500 +1,10 @@
|
||||
/*-
|
||||
* Copyright (c) 2003-2007 Tim Kientzle
|
||||
* Copyright (c) 2011-2012 Michihiro NAKAJIMA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "archive_platform.h"
|
||||
__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $");
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_write_private.h"
|
||||
#include "archive_write_set_format_private.h"
|
||||
|
||||
static ssize_t archive_write_cpio_data(struct archive_write *,
|
||||
const void *buff, size_t s);
|
||||
static int archive_write_cpio_close(struct archive_write *);
|
||||
static int archive_write_cpio_free(struct archive_write *);
|
||||
static int archive_write_cpio_finish_entry(struct archive_write *);
|
||||
static int archive_write_cpio_header(struct archive_write *,
|
||||
struct archive_entry *);
|
||||
static int archive_write_cpio_options(struct archive_write *,
|
||||
const char *, const char *);
|
||||
static int format_octal(int64_t, void *, int);
|
||||
static int64_t format_octal_recursive(int64_t, char *, int);
|
||||
static int write_header(struct archive_write *, struct archive_entry *);
|
||||
|
||||
struct cpio {
|
||||
uint64_t entry_bytes_remaining;
|
||||
|
||||
int64_t ino_next;
|
||||
|
||||
struct { int64_t old; int new;} *ino_list;
|
||||
size_t ino_list_size;
|
||||
size_t ino_list_next;
|
||||
|
||||
struct archive_string_conv *opt_sconv;
|
||||
struct archive_string_conv *sconv_default;
|
||||
int init_default_conversion;
|
||||
};
|
||||
|
||||
#define c_magic_offset 0
|
||||
#define c_magic_size 6
|
||||
#define c_dev_offset 6
|
||||
#define c_dev_size 6
|
||||
#define c_ino_offset 12
|
||||
#define c_ino_size 6
|
||||
#define c_mode_offset 18
|
||||
#define c_mode_size 6
|
||||
#define c_uid_offset 24
|
||||
#define c_uid_size 6
|
||||
#define c_gid_offset 30
|
||||
#define c_gid_size 6
|
||||
#define c_nlink_offset 36
|
||||
#define c_nlink_size 6
|
||||
#define c_rdev_offset 42
|
||||
#define c_rdev_size 6
|
||||
#define c_mtime_offset 48
|
||||
#define c_mtime_size 11
|
||||
#define c_namesize_offset 59
|
||||
#define c_namesize_size 6
|
||||
#define c_filesize_offset 65
|
||||
#define c_filesize_size 11
|
||||
|
||||
/*
|
||||
* Set output format to 'cpio' format.
|
||||
* Set output format to the default 'cpio' format.
|
||||
*/
|
||||
int
|
||||
archive_write_set_format_cpio(struct archive *_a)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct cpio *cpio;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_set_format_cpio");
|
||||
|
||||
/* If someone else was already registered, unregister them. */
|
||||
if (a->format_free != NULL)
|
||||
(a->format_free)(a);
|
||||
|
||||
cpio = (struct cpio *)calloc(1, sizeof(*cpio));
|
||||
if (cpio == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
a->format_data = cpio;
|
||||
a->format_name = "cpio";
|
||||
a->format_options = archive_write_cpio_options;
|
||||
a->format_write_header = archive_write_cpio_header;
|
||||
a->format_write_data = archive_write_cpio_data;
|
||||
a->format_finish_entry = archive_write_cpio_finish_entry;
|
||||
a->format_close = archive_write_cpio_close;
|
||||
a->format_free = archive_write_cpio_free;
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
|
||||
a->archive.archive_format_name = "POSIX cpio";
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_cpio_options(struct archive_write *a, const char *key,
|
||||
const char *val)
|
||||
{
|
||||
struct cpio *cpio = (struct cpio *)a->format_data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
if (strcmp(key, "hdrcharset") == 0) {
|
||||
if (val == NULL || val[0] == 0)
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"%s: hdrcharset option needs a character-set name",
|
||||
a->format_name);
|
||||
else {
|
||||
cpio->opt_sconv = archive_string_conversion_to_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ino values are as long as 64 bits on some systems; cpio format
|
||||
* only allows 18 bits and relies on the ino values to identify hardlinked
|
||||
* files. So, we can't merely "hash" the ino numbers since collisions
|
||||
* would corrupt the archive. Instead, we generate synthetic ino values
|
||||
* to store in the archive and maintain a map of original ino values to
|
||||
* synthetic ones so we can preserve hardlink information.
|
||||
*
|
||||
* TODO: Make this more efficient. It's not as bad as it looks (most
|
||||
* files don't have any hardlinks and we don't do any work here for those),
|
||||
* but it wouldn't be hard to do better.
|
||||
*
|
||||
* TODO: Work with dev/ino pairs here instead of just ino values.
|
||||
*/
|
||||
static int
|
||||
synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
|
||||
{
|
||||
int64_t ino = archive_entry_ino64(entry);
|
||||
int ino_new;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* If no index number was given, don't assign one. In
|
||||
* particular, this handles the end-of-archive marker
|
||||
* correctly by giving it a zero index value. (This is also
|
||||
* why we start our synthetic index numbers with one below.)
|
||||
*/
|
||||
if (ino == 0)
|
||||
return (0);
|
||||
|
||||
/* Don't store a mapping if we don't need to. */
|
||||
if (archive_entry_nlink(entry) < 2) {
|
||||
return (int)(++cpio->ino_next);
|
||||
}
|
||||
|
||||
/* Look up old ino; if we have it, this is a hardlink
|
||||
* and we reuse the same value. */
|
||||
for (i = 0; i < cpio->ino_list_next; ++i) {
|
||||
if (cpio->ino_list[i].old == ino)
|
||||
return (cpio->ino_list[i].new);
|
||||
}
|
||||
|
||||
/* Assign a new index number. */
|
||||
ino_new = (int)(++cpio->ino_next);
|
||||
|
||||
/* Ensure space for the new mapping. */
|
||||
if (cpio->ino_list_size <= cpio->ino_list_next) {
|
||||
size_t newsize = cpio->ino_list_size < 512
|
||||
? 512 : cpio->ino_list_size * 2;
|
||||
void *newlist = realloc(cpio->ino_list,
|
||||
sizeof(cpio->ino_list[0]) * newsize);
|
||||
if (newlist == NULL)
|
||||
return (-1);
|
||||
|
||||
cpio->ino_list_size = newsize;
|
||||
cpio->ino_list = newlist;
|
||||
}
|
||||
|
||||
/* Record and return the new value. */
|
||||
cpio->ino_list[cpio->ino_list_next].old = ino;
|
||||
cpio->ino_list[cpio->ino_list_next].new = ino_new;
|
||||
++cpio->ino_list_next;
|
||||
return (ino_new);
|
||||
}
|
||||
|
||||
|
||||
static struct archive_string_conv *
|
||||
get_sconv(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
struct archive_string_conv *sconv;
|
||||
|
||||
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_write(
|
||||
&(a->archive));
|
||||
cpio->init_default_conversion = 1;
|
||||
}
|
||||
sconv = cpio->sconv_default;
|
||||
}
|
||||
return (sconv);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
|
||||
{
|
||||
const char *path;
|
||||
size_t len;
|
||||
|
||||
if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
|
||||
archive_set_error(&a->archive, -1, "Filetype required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
|
||||
&& errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Pathname");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (len == 0 || path == NULL || path[0] == '\0') {
|
||||
archive_set_error(&a->archive, -1, "Pathname required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {
|
||||
archive_set_error(&a->archive, -1, "Size required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
return write_header(a, entry);
|
||||
}
|
||||
|
||||
static int
|
||||
write_header(struct archive_write *a, struct archive_entry *entry)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
const char *p, *path;
|
||||
int pathlength, ret, ret_final;
|
||||
int64_t ino;
|
||||
char h[76];
|
||||
struct archive_string_conv *sconv;
|
||||
struct archive_entry *entry_main;
|
||||
size_t len;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
ret_final = ARCHIVE_OK;
|
||||
sconv = get_sconv(a);
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (entry_main == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate ustar data");
|
||||
return(ARCHIVE_FATAL);
|
||||
}
|
||||
if (entry != entry_main)
|
||||
entry = entry_main;
|
||||
else
|
||||
entry_main = NULL;
|
||||
#else
|
||||
entry_main = NULL;
|
||||
#endif
|
||||
|
||||
ret = archive_entry_pathname_l(entry, &path, &len, sconv);
|
||||
if (ret != 0) {
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Pathname");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Can't translate pathname '%s' to %s",
|
||||
archive_entry_pathname(entry),
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
ret_final = ARCHIVE_WARN;
|
||||
}
|
||||
/* Include trailing null. */
|
||||
pathlength = (int)len + 1;
|
||||
|
||||
memset(h, 0, sizeof(h));
|
||||
format_octal(070707, h + c_magic_offset, c_magic_size);
|
||||
format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size);
|
||||
|
||||
ino = synthesize_ino_value(cpio, entry);
|
||||
if (ino < 0) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"No memory for ino translation table");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
} else if (ino > 0777777) {
|
||||
archive_set_error(&a->archive, ERANGE,
|
||||
"Too many files for this cpio format");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
format_octal(ino & 0777777, h + c_ino_offset, c_ino_size);
|
||||
|
||||
/* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */
|
||||
format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);
|
||||
format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);
|
||||
format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);
|
||||
format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
|
||||
if (archive_entry_filetype(entry) == AE_IFBLK
|
||||
|| archive_entry_filetype(entry) == AE_IFCHR)
|
||||
format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size);
|
||||
else
|
||||
format_octal(0, h + c_rdev_offset, c_rdev_size);
|
||||
format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
|
||||
format_octal(pathlength, h + c_namesize_offset, c_namesize_size);
|
||||
|
||||
/* Non-regular files don't store bodies. */
|
||||
if (archive_entry_filetype(entry) != AE_IFREG)
|
||||
archive_entry_set_size(entry, 0);
|
||||
|
||||
/* Symlinks get the link written as the body of the entry. */
|
||||
ret = archive_entry_symlink_l(entry, &p, &len, sconv);
|
||||
if (ret != 0) {
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Linkname");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Can't translate linkname '%s' to %s",
|
||||
archive_entry_symlink(entry),
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
ret_final = ARCHIVE_WARN;
|
||||
}
|
||||
if (len > 0 && p != NULL && *p != '\0')
|
||||
ret = format_octal(strlen(p), h + c_filesize_offset,
|
||||
c_filesize_size);
|
||||
else
|
||||
ret = format_octal(archive_entry_size(entry),
|
||||
h + c_filesize_offset, c_filesize_size);
|
||||
if (ret) {
|
||||
archive_set_error(&a->archive, ERANGE,
|
||||
"File is too large for cpio format.");
|
||||
ret_final = ARCHIVE_FAILED;
|
||||
goto exit_write_header;
|
||||
}
|
||||
|
||||
ret = __archive_write_output(a, h, sizeof(h));
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
|
||||
ret = __archive_write_output(a, path, pathlength);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
|
||||
cpio->entry_bytes_remaining = archive_entry_size(entry);
|
||||
|
||||
/* Write the symlink now. */
|
||||
if (p != NULL && *p != '\0') {
|
||||
ret = __archive_write_output(a, p, strlen(p));
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
}
|
||||
exit_write_header:
|
||||
archive_entry_free(entry_main);
|
||||
return (ret_final);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
int ret;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
if (s > cpio->entry_bytes_remaining)
|
||||
s = (size_t)cpio->entry_bytes_remaining;
|
||||
|
||||
ret = __archive_write_output(a, buff, s);
|
||||
cpio->entry_bytes_remaining -= s;
|
||||
if (ret >= 0)
|
||||
return (s);
|
||||
else
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Format a number into the specified field.
|
||||
*/
|
||||
static int
|
||||
format_octal(int64_t v, void *p, int digits)
|
||||
{
|
||||
int64_t max;
|
||||
int ret;
|
||||
|
||||
max = (((int64_t)1) << (digits * 3)) - 1;
|
||||
if (v >= 0 && v <= max) {
|
||||
format_octal_recursive(v, (char *)p, digits);
|
||||
ret = 0;
|
||||
} else {
|
||||
format_octal_recursive(max, (char *)p, digits);
|
||||
ret = -1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
format_octal_recursive(int64_t v, char *p, int s)
|
||||
{
|
||||
if (s == 0)
|
||||
return (v);
|
||||
v = format_octal_recursive(v, p+1, s-1);
|
||||
*p = '0' + ((char)v & 7);
|
||||
return (v >> 3);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_cpio_close(struct archive_write *a)
|
||||
{
|
||||
int er;
|
||||
struct archive_entry *trailer;
|
||||
|
||||
trailer = archive_entry_new2(NULL);
|
||||
/* nlink = 1 here for GNU cpio compat. */
|
||||
archive_entry_set_nlink(trailer, 1);
|
||||
archive_entry_set_size(trailer, 0);
|
||||
archive_entry_set_pathname(trailer, "TRAILER!!!");
|
||||
er = write_header(a, trailer);
|
||||
archive_entry_free(trailer);
|
||||
return (er);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_cpio_free(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
free(cpio->ino_list);
|
||||
free(cpio);
|
||||
a->format_data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_cpio_finish_entry(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
return (__archive_write_nulls(a,
|
||||
(size_t)cpio->entry_bytes_remaining));
|
||||
return archive_write_set_format_cpio_odc(_a);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,610 @@
|
||||
/*-
|
||||
* Copyright (c) 2003-2007 Tim Kientzle
|
||||
* Copyright (c) 2011-2012 Michihiro NAKAJIMA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "archive_platform.h"
|
||||
__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $");
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_write_private.h"
|
||||
#include "archive_write_set_format_private.h"
|
||||
|
||||
static ssize_t archive_write_binary_data(struct archive_write *,
|
||||
const void *buff, size_t s);
|
||||
static int archive_write_binary_close(struct archive_write *);
|
||||
static int archive_write_binary_free(struct archive_write *);
|
||||
static int archive_write_binary_finish_entry(struct archive_write *);
|
||||
static int archive_write_binary_header(struct archive_write *,
|
||||
struct archive_entry *);
|
||||
static int archive_write_binary_options(struct archive_write *,
|
||||
const char *, const char *);
|
||||
static int write_header(struct archive_write *, struct archive_entry *);
|
||||
|
||||
struct cpio {
|
||||
uint64_t entry_bytes_remaining;
|
||||
|
||||
int64_t ino_next;
|
||||
|
||||
struct { int64_t old; int new;} *ino_list;
|
||||
size_t ino_list_size;
|
||||
size_t ino_list_next;
|
||||
|
||||
struct archive_string_conv *opt_sconv;
|
||||
struct archive_string_conv *sconv_default;
|
||||
int init_default_conversion;
|
||||
};
|
||||
|
||||
/* This struct needs to be packed to get the header right */
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define PACKED(x) x __attribute__((packed))
|
||||
#elif defined(_MSC_VER)
|
||||
#define PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
|
||||
#else
|
||||
#define PACKED(x) x
|
||||
#endif
|
||||
|
||||
#define HSIZE 26
|
||||
|
||||
PACKED(struct cpio_binary_header {
|
||||
uint16_t h_magic;
|
||||
uint16_t h_dev;
|
||||
uint16_t h_ino;
|
||||
uint16_t h_mode;
|
||||
uint16_t h_uid;
|
||||
uint16_t h_gid;
|
||||
uint16_t h_nlink;
|
||||
uint16_t h_majmin;
|
||||
uint32_t h_mtime;
|
||||
uint16_t h_namesize;
|
||||
uint32_t h_filesize;
|
||||
});
|
||||
|
||||
/* Back in the day, the 7th Edition cpio.c had this, to
|
||||
* adapt to, as the comment said, "VAX, Interdata, ...":
|
||||
*
|
||||
* union { long l; short s[2]; char c[4]; } U;
|
||||
* #define MKSHORT(v,lv) {U.l=1L;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,v[0]=U.s[0],v[1]=U.s[1];}
|
||||
* long mklong(v)
|
||||
* short v[];
|
||||
* {
|
||||
* U.l = 1;
|
||||
* if(U.c[0])
|
||||
* U.s[0] = v[1], U.s[1] = v[0];
|
||||
* else
|
||||
* U.s[0] = v[0], U.s[1] = v[1];
|
||||
* return U.l;
|
||||
* }
|
||||
*
|
||||
* Of course, that assumes that all machines have little-endian shorts,
|
||||
* and just adapts the others to the special endianness of the PDP-11.
|
||||
*
|
||||
* Now, we could do this:
|
||||
*
|
||||
* union { uint32_t l; uint16_t s[2]; uint8_t c[4]; } U;
|
||||
* #define PUTI16(v,sv) {U.s[0]=1;if(U.c[0]) v=sv; else U.s[0]=sv,U.c[2]=U.c[1],U.c[3]=U.c[0],v=U.s[1];}
|
||||
* #define PUTI32(v,lv) {char_t Ut;U.l=1;if(U.c[0]) U.l=lv,v[0]=U.s[1],v[1]=U.s[0]; else U.l=lv,Ut=U.c[0],U.c[0]=U.c[1],U.c[1]=Ut,Ut=U.c[2],U.c[2]=U.c[3],U.c[3]=Ut,v[0]=U.s[0],v[1]=U.s[1];}
|
||||
*
|
||||
* ...but it feels a little better to do it like this:
|
||||
*/
|
||||
|
||||
static uint16_t swap16(uint16_t in) {
|
||||
union {
|
||||
uint16_t s[2];
|
||||
uint8_t c[4];
|
||||
} U;
|
||||
U.s[0] = 1;
|
||||
if (U.c[0])
|
||||
return in;
|
||||
else {
|
||||
U.s[0] = in;
|
||||
U.c[2] = U.c[1];
|
||||
U.c[3] = U.c[0];
|
||||
return U.s[1];
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static uint32_t swap32(uint32_t in) {
|
||||
union {
|
||||
uint32_t l;
|
||||
uint16_t s[2];
|
||||
uint8_t c[4];
|
||||
} U;
|
||||
U.l = 1;
|
||||
if (U.c[0]) { /* Little-endian */
|
||||
uint16_t t;
|
||||
U.l = in;
|
||||
t = U.s[0];
|
||||
U.s[0] = U.s[1];
|
||||
U.s[1] = t;
|
||||
} else if (U.c[3]) { /* Big-endian */
|
||||
U.l = in;
|
||||
U.s[0] = swap16(U.s[0]);
|
||||
U.s[1] = swap16(U.s[1]);
|
||||
} else { /* PDP-endian */
|
||||
U.l = in;
|
||||
}
|
||||
return U.l;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set output format to the selected binary variant
|
||||
*/
|
||||
static int
|
||||
archive_write_set_format_cpio_binary(struct archive *_a, int format)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct cpio *cpio;
|
||||
|
||||
if (sizeof(struct cpio_binary_header) != HSIZE) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Binary cpio format not supported on this platform");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_binary");
|
||||
|
||||
/* If someone else was already registered, unregister them. */
|
||||
if (a->format_free != NULL)
|
||||
(a->format_free)(a);
|
||||
|
||||
cpio = (struct cpio *)calloc(1, sizeof(*cpio));
|
||||
if (cpio == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
a->format_data = cpio;
|
||||
a->format_name = "cpio";
|
||||
a->format_options = archive_write_binary_options;
|
||||
a->format_write_header = archive_write_binary_header;
|
||||
a->format_write_data = archive_write_binary_data;
|
||||
a->format_finish_entry = archive_write_binary_finish_entry;
|
||||
a->format_close = archive_write_binary_close;
|
||||
a->format_free = archive_write_binary_free;
|
||||
a->archive.archive_format = format;
|
||||
switch (format) {
|
||||
case ARCHIVE_FORMAT_CPIO_PWB:
|
||||
a->archive.archive_format_name = "PWB cpio";
|
||||
break;
|
||||
case ARCHIVE_FORMAT_CPIO_BIN_LE:
|
||||
a->archive.archive_format_name = "7th Edition cpio";
|
||||
break;
|
||||
default:
|
||||
archive_set_error(&a->archive, EINVAL, "binary format must be 'pwb' or 'bin'");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set output format to PWB (6th Edition) binary format
|
||||
*/
|
||||
int
|
||||
archive_write_set_format_cpio_pwb(struct archive *_a)
|
||||
{
|
||||
return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_PWB);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set output format to 7th Edition binary format
|
||||
*/
|
||||
int
|
||||
archive_write_set_format_cpio_bin(struct archive *_a)
|
||||
{
|
||||
return archive_write_set_format_cpio_binary(_a, ARCHIVE_FORMAT_CPIO_BIN_LE);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_binary_options(struct archive_write *a, const char *key,
|
||||
const char *val)
|
||||
{
|
||||
struct cpio *cpio = (struct cpio *)a->format_data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
if (strcmp(key, "hdrcharset") == 0) {
|
||||
if (val == NULL || val[0] == 0)
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"%s: hdrcharset option needs a character-set name",
|
||||
a->format_name);
|
||||
else {
|
||||
cpio->opt_sconv = archive_string_conversion_to_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ino values are as long as 64 bits on some systems; cpio format
|
||||
* only allows 16 bits and relies on the ino values to identify hardlinked
|
||||
* files. So, we can't merely "hash" the ino numbers since collisions
|
||||
* would corrupt the archive. Instead, we generate synthetic ino values
|
||||
* to store in the archive and maintain a map of original ino values to
|
||||
* synthetic ones so we can preserve hardlink information.
|
||||
*
|
||||
* TODO: Make this more efficient. It's not as bad as it looks (most
|
||||
* files don't have any hardlinks and we don't do any work here for those),
|
||||
* but it wouldn't be hard to do better.
|
||||
*
|
||||
* TODO: Work with dev/ino pairs here instead of just ino values.
|
||||
*/
|
||||
static int
|
||||
synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
|
||||
{
|
||||
int64_t ino = archive_entry_ino64(entry);
|
||||
int ino_new;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* If no index number was given, don't assign one. In
|
||||
* particular, this handles the end-of-archive marker
|
||||
* correctly by giving it a zero index value. (This is also
|
||||
* why we start our synthetic index numbers with one below.)
|
||||
*/
|
||||
if (ino == 0)
|
||||
return (0);
|
||||
|
||||
/* Don't store a mapping if we don't need to. */
|
||||
if (archive_entry_nlink(entry) < 2) {
|
||||
return (int)(++cpio->ino_next);
|
||||
}
|
||||
|
||||
/* Look up old ino; if we have it, this is a hardlink
|
||||
* and we reuse the same value. */
|
||||
for (i = 0; i < cpio->ino_list_next; ++i) {
|
||||
if (cpio->ino_list[i].old == ino)
|
||||
return (cpio->ino_list[i].new);
|
||||
}
|
||||
|
||||
/* Assign a new index number. */
|
||||
ino_new = (int)(++cpio->ino_next);
|
||||
|
||||
/* Ensure space for the new mapping. */
|
||||
if (cpio->ino_list_size <= cpio->ino_list_next) {
|
||||
size_t newsize = cpio->ino_list_size < 512
|
||||
? 512 : cpio->ino_list_size * 2;
|
||||
void *newlist = realloc(cpio->ino_list,
|
||||
sizeof(cpio->ino_list[0]) * newsize);
|
||||
if (newlist == NULL)
|
||||
return (-1);
|
||||
|
||||
cpio->ino_list_size = newsize;
|
||||
cpio->ino_list = newlist;
|
||||
}
|
||||
|
||||
/* Record and return the new value. */
|
||||
cpio->ino_list[cpio->ino_list_next].old = ino;
|
||||
cpio->ino_list[cpio->ino_list_next].new = ino_new;
|
||||
++cpio->ino_list_next;
|
||||
return (ino_new);
|
||||
}
|
||||
|
||||
|
||||
static struct archive_string_conv *
|
||||
get_sconv(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
struct archive_string_conv *sconv;
|
||||
|
||||
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_write(
|
||||
&(a->archive));
|
||||
cpio->init_default_conversion = 1;
|
||||
}
|
||||
sconv = cpio->sconv_default;
|
||||
}
|
||||
return (sconv);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_binary_header(struct archive_write *a, struct archive_entry *entry)
|
||||
{
|
||||
const char *path;
|
||||
size_t len;
|
||||
|
||||
if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
|
||||
archive_set_error(&a->archive, -1, "Filetype required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
|
||||
&& errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Pathname");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (len == 0 || path == NULL || path[0] == '\0') {
|
||||
archive_set_error(&a->archive, -1, "Pathname required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {
|
||||
archive_set_error(&a->archive, -1, "Size required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
return write_header(a, entry);
|
||||
}
|
||||
|
||||
static int
|
||||
write_header(struct archive_write *a, struct archive_entry *entry)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
const char *p, *path;
|
||||
int pathlength, ret, ret_final;
|
||||
int64_t ino;
|
||||
struct cpio_binary_header h;
|
||||
struct archive_string_conv *sconv;
|
||||
struct archive_entry *entry_main;
|
||||
size_t len;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
ret_final = ARCHIVE_OK;
|
||||
sconv = get_sconv(a);
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (entry_main == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate ustar data");
|
||||
return(ARCHIVE_FATAL);
|
||||
}
|
||||
if (entry != entry_main)
|
||||
entry = entry_main;
|
||||
else
|
||||
entry_main = NULL;
|
||||
#else
|
||||
entry_main = NULL;
|
||||
#endif
|
||||
|
||||
ret = archive_entry_pathname_l(entry, &path, &len, sconv);
|
||||
if (ret != 0) {
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Pathname");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Can't translate pathname '%s' to %s",
|
||||
archive_entry_pathname(entry),
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
ret_final = ARCHIVE_WARN;
|
||||
}
|
||||
/* Include trailing null */
|
||||
pathlength = (int)len + 1;
|
||||
|
||||
h.h_magic = swap16(070707);
|
||||
h.h_dev = swap16(archive_entry_dev(entry));
|
||||
|
||||
ino = synthesize_ino_value(cpio, entry);
|
||||
if (ino < 0) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"No memory for ino translation table");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
} else if (ino > 077777) {
|
||||
archive_set_error(&a->archive, ERANGE,
|
||||
"Too many files for this cpio format");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
h.h_ino = swap16(ino);
|
||||
|
||||
h.h_mode = archive_entry_mode(entry);
|
||||
if (((h.h_mode & AE_IFMT) == AE_IFSOCK) || ((h.h_mode & AE_IFMT) == AE_IFIFO)) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"sockets and fifos cannot be represented in the binary cpio formats");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) {
|
||||
if ((h.h_mode & AE_IFMT) == AE_IFLNK) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"symbolic links cannot be represented in the PWB cpio format");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
/* we could turn off AE_IFREG here, but it does no harm, */
|
||||
/* and allows v7 cpio to read the entry without confusion */
|
||||
}
|
||||
h.h_mode = swap16(h.h_mode);
|
||||
|
||||
h.h_uid = swap16(archive_entry_uid(entry));
|
||||
h.h_gid = swap16(archive_entry_gid(entry));
|
||||
h.h_nlink = swap16(archive_entry_nlink(entry));
|
||||
|
||||
if (archive_entry_filetype(entry) == AE_IFBLK
|
||||
|| archive_entry_filetype(entry) == AE_IFCHR)
|
||||
h.h_majmin = swap16(archive_entry_rdev(entry));
|
||||
else
|
||||
h.h_majmin = 0;
|
||||
|
||||
h.h_mtime = swap32(archive_entry_mtime(entry));
|
||||
h.h_namesize = swap16(pathlength);
|
||||
|
||||
/* Non-regular files don't store bodies. */
|
||||
if (archive_entry_filetype(entry) != AE_IFREG)
|
||||
archive_entry_set_size(entry, 0);
|
||||
|
||||
/* Symlinks get the link written as the body of the entry. */
|
||||
ret = archive_entry_symlink_l(entry, &p, &len, sconv);
|
||||
if (ret != 0) {
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Linkname");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Can't translate linkname '%s' to %s",
|
||||
archive_entry_symlink(entry),
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
ret_final = ARCHIVE_WARN;
|
||||
}
|
||||
|
||||
if (len > 0 && p != NULL && *p != '\0') {
|
||||
if (a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"symlinks are not supported by UNIX V6 or by PWB cpio");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
h.h_filesize = swap32(strlen(p)); /* symlink */
|
||||
} else {
|
||||
if ((a->archive.archive_format == ARCHIVE_FORMAT_CPIO_PWB) &&
|
||||
(archive_entry_size(entry) > 256*256*256-1)) {
|
||||
archive_set_error(&a->archive, ERANGE,
|
||||
"File is too large for PWB binary cpio format.");
|
||||
ret_final = ARCHIVE_FAILED;
|
||||
goto exit_write_header;
|
||||
} else if (archive_entry_size(entry) > INT32_MAX) {
|
||||
archive_set_error(&a->archive, ERANGE,
|
||||
"File is too large for binary cpio format.");
|
||||
ret_final = ARCHIVE_FAILED;
|
||||
goto exit_write_header;
|
||||
}
|
||||
h.h_filesize = swap32(archive_entry_size(entry)); /* file */
|
||||
}
|
||||
|
||||
ret = __archive_write_output(a, &h, HSIZE);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
|
||||
ret = __archive_write_output(a, path, pathlength);
|
||||
if ((ret == ARCHIVE_OK) && ((pathlength % 2) != 0))
|
||||
ret = __archive_write_nulls(a, 1);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
|
||||
cpio->entry_bytes_remaining = archive_entry_size(entry);
|
||||
if ((cpio->entry_bytes_remaining % 2) != 0)
|
||||
cpio->entry_bytes_remaining++;
|
||||
|
||||
/* Write the symlink now. */
|
||||
if (p != NULL && *p != '\0') {
|
||||
ret = __archive_write_output(a, p, strlen(p));
|
||||
if ((ret == ARCHIVE_OK) && ((strlen(p) % 2) != 0))
|
||||
ret = __archive_write_nulls(a, 1);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
}
|
||||
|
||||
exit_write_header:
|
||||
archive_entry_free(entry_main);
|
||||
return (ret_final);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
archive_write_binary_data(struct archive_write *a, const void *buff, size_t s)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
int ret;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
if (s > cpio->entry_bytes_remaining)
|
||||
s = (size_t)cpio->entry_bytes_remaining;
|
||||
|
||||
ret = __archive_write_output(a, buff, s);
|
||||
cpio->entry_bytes_remaining -= s;
|
||||
if (ret >= 0)
|
||||
return (s);
|
||||
else
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_binary_close(struct archive_write *a)
|
||||
{
|
||||
int er;
|
||||
struct archive_entry *trailer;
|
||||
|
||||
trailer = archive_entry_new2(NULL);
|
||||
/* nlink = 1 here for GNU cpio compat. */
|
||||
archive_entry_set_nlink(trailer, 1);
|
||||
archive_entry_set_size(trailer, 0);
|
||||
archive_entry_set_pathname(trailer, "TRAILER!!!");
|
||||
er = write_header(a, trailer);
|
||||
archive_entry_free(trailer);
|
||||
return (er);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_binary_free(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
free(cpio->ino_list);
|
||||
free(cpio);
|
||||
a->format_data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_binary_finish_entry(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
return (__archive_write_nulls(a,
|
||||
(size_t)cpio->entry_bytes_remaining));
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
/*-
|
||||
* Copyright (c) 2003-2007 Tim Kientzle
|
||||
* Copyright (c) 2011-2012 Michihiro NAKAJIMA
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "archive_platform.h"
|
||||
__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_cpio.c 201170 2009-12-29 06:34:23Z kientzle $");
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "archive.h"
|
||||
#include "archive_entry.h"
|
||||
#include "archive_entry_locale.h"
|
||||
#include "archive_private.h"
|
||||
#include "archive_write_private.h"
|
||||
#include "archive_write_set_format_private.h"
|
||||
|
||||
static ssize_t archive_write_odc_data(struct archive_write *,
|
||||
const void *buff, size_t s);
|
||||
static int archive_write_odc_close(struct archive_write *);
|
||||
static int archive_write_odc_free(struct archive_write *);
|
||||
static int archive_write_odc_finish_entry(struct archive_write *);
|
||||
static int archive_write_odc_header(struct archive_write *,
|
||||
struct archive_entry *);
|
||||
static int archive_write_odc_options(struct archive_write *,
|
||||
const char *, const char *);
|
||||
static int format_octal(int64_t, void *, int);
|
||||
static int64_t format_octal_recursive(int64_t, char *, int);
|
||||
static int write_header(struct archive_write *, struct archive_entry *);
|
||||
|
||||
struct cpio {
|
||||
uint64_t entry_bytes_remaining;
|
||||
|
||||
int64_t ino_next;
|
||||
|
||||
struct { int64_t old; int new;} *ino_list;
|
||||
size_t ino_list_size;
|
||||
size_t ino_list_next;
|
||||
|
||||
struct archive_string_conv *opt_sconv;
|
||||
struct archive_string_conv *sconv_default;
|
||||
int init_default_conversion;
|
||||
};
|
||||
|
||||
#define c_magic_offset 0
|
||||
#define c_magic_size 6
|
||||
#define c_dev_offset 6
|
||||
#define c_dev_size 6
|
||||
#define c_ino_offset 12
|
||||
#define c_ino_size 6
|
||||
#define c_mode_offset 18
|
||||
#define c_mode_size 6
|
||||
#define c_uid_offset 24
|
||||
#define c_uid_size 6
|
||||
#define c_gid_offset 30
|
||||
#define c_gid_size 6
|
||||
#define c_nlink_offset 36
|
||||
#define c_nlink_size 6
|
||||
#define c_rdev_offset 42
|
||||
#define c_rdev_size 6
|
||||
#define c_mtime_offset 48
|
||||
#define c_mtime_size 11
|
||||
#define c_namesize_offset 59
|
||||
#define c_namesize_size 6
|
||||
#define c_filesize_offset 65
|
||||
#define c_filesize_size 11
|
||||
|
||||
/*
|
||||
* Set output format to 'cpio' format.
|
||||
*/
|
||||
int
|
||||
archive_write_set_format_cpio_odc(struct archive *_a)
|
||||
{
|
||||
struct archive_write *a = (struct archive_write *)_a;
|
||||
struct cpio *cpio;
|
||||
|
||||
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
|
||||
ARCHIVE_STATE_NEW, "archive_write_set_format_cpio_odc");
|
||||
|
||||
/* If someone else was already registered, unregister them. */
|
||||
if (a->format_free != NULL)
|
||||
(a->format_free)(a);
|
||||
|
||||
cpio = (struct cpio *)calloc(1, sizeof(*cpio));
|
||||
if (cpio == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
a->format_data = cpio;
|
||||
a->format_name = "cpio";
|
||||
a->format_options = archive_write_odc_options;
|
||||
a->format_write_header = archive_write_odc_header;
|
||||
a->format_write_data = archive_write_odc_data;
|
||||
a->format_finish_entry = archive_write_odc_finish_entry;
|
||||
a->format_close = archive_write_odc_close;
|
||||
a->format_free = archive_write_odc_free;
|
||||
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
|
||||
a->archive.archive_format_name = "POSIX cpio";
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_odc_options(struct archive_write *a, const char *key,
|
||||
const char *val)
|
||||
{
|
||||
struct cpio *cpio = (struct cpio *)a->format_data;
|
||||
int ret = ARCHIVE_FAILED;
|
||||
|
||||
if (strcmp(key, "hdrcharset") == 0) {
|
||||
if (val == NULL || val[0] == 0)
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"%s: hdrcharset option needs a character-set name",
|
||||
a->format_name);
|
||||
else {
|
||||
cpio->opt_sconv = archive_string_conversion_to_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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ino values are as long as 64 bits on some systems; cpio format
|
||||
* only allows 18 bits and relies on the ino values to identify hardlinked
|
||||
* files. So, we can't merely "hash" the ino numbers since collisions
|
||||
* would corrupt the archive. Instead, we generate synthetic ino values
|
||||
* to store in the archive and maintain a map of original ino values to
|
||||
* synthetic ones so we can preserve hardlink information.
|
||||
*
|
||||
* TODO: Make this more efficient. It's not as bad as it looks (most
|
||||
* files don't have any hardlinks and we don't do any work here for those),
|
||||
* but it wouldn't be hard to do better.
|
||||
*
|
||||
* TODO: Work with dev/ino pairs here instead of just ino values.
|
||||
*/
|
||||
static int
|
||||
synthesize_ino_value(struct cpio *cpio, struct archive_entry *entry)
|
||||
{
|
||||
int64_t ino = archive_entry_ino64(entry);
|
||||
int ino_new;
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* If no index number was given, don't assign one. In
|
||||
* particular, this handles the end-of-archive marker
|
||||
* correctly by giving it a zero index value. (This is also
|
||||
* why we start our synthetic index numbers with one below.)
|
||||
*/
|
||||
if (ino == 0)
|
||||
return (0);
|
||||
|
||||
/* Don't store a mapping if we don't need to. */
|
||||
if (archive_entry_nlink(entry) < 2) {
|
||||
return (int)(++cpio->ino_next);
|
||||
}
|
||||
|
||||
/* Look up old ino; if we have it, this is a hardlink
|
||||
* and we reuse the same value. */
|
||||
for (i = 0; i < cpio->ino_list_next; ++i) {
|
||||
if (cpio->ino_list[i].old == ino)
|
||||
return (cpio->ino_list[i].new);
|
||||
}
|
||||
|
||||
/* Assign a new index number. */
|
||||
ino_new = (int)(++cpio->ino_next);
|
||||
|
||||
/* Ensure space for the new mapping. */
|
||||
if (cpio->ino_list_size <= cpio->ino_list_next) {
|
||||
size_t newsize = cpio->ino_list_size < 512
|
||||
? 512 : cpio->ino_list_size * 2;
|
||||
void *newlist = realloc(cpio->ino_list,
|
||||
sizeof(cpio->ino_list[0]) * newsize);
|
||||
if (newlist == NULL)
|
||||
return (-1);
|
||||
|
||||
cpio->ino_list_size = newsize;
|
||||
cpio->ino_list = newlist;
|
||||
}
|
||||
|
||||
/* Record and return the new value. */
|
||||
cpio->ino_list[cpio->ino_list_next].old = ino;
|
||||
cpio->ino_list[cpio->ino_list_next].new = ino_new;
|
||||
++cpio->ino_list_next;
|
||||
return (ino_new);
|
||||
}
|
||||
|
||||
|
||||
static struct archive_string_conv *
|
||||
get_sconv(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
struct archive_string_conv *sconv;
|
||||
|
||||
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_write(
|
||||
&(a->archive));
|
||||
cpio->init_default_conversion = 1;
|
||||
}
|
||||
sconv = cpio->sconv_default;
|
||||
}
|
||||
return (sconv);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_odc_header(struct archive_write *a, struct archive_entry *entry)
|
||||
{
|
||||
const char *path;
|
||||
size_t len;
|
||||
|
||||
if (archive_entry_filetype(entry) == 0 && archive_entry_hardlink(entry) == NULL) {
|
||||
archive_set_error(&a->archive, -1, "Filetype required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (archive_entry_pathname_l(entry, &path, &len, get_sconv(a)) != 0
|
||||
&& errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Pathname");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (len == 0 || path == NULL || path[0] == '\0') {
|
||||
archive_set_error(&a->archive, -1, "Pathname required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
|
||||
if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) < 0) {
|
||||
archive_set_error(&a->archive, -1, "Size required");
|
||||
return (ARCHIVE_FAILED);
|
||||
}
|
||||
return write_header(a, entry);
|
||||
}
|
||||
|
||||
static int
|
||||
write_header(struct archive_write *a, struct archive_entry *entry)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
const char *p, *path;
|
||||
int pathlength, ret, ret_final;
|
||||
int64_t ino;
|
||||
char h[76];
|
||||
struct archive_string_conv *sconv;
|
||||
struct archive_entry *entry_main;
|
||||
size_t len;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
ret_final = ARCHIVE_OK;
|
||||
sconv = get_sconv(a);
|
||||
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
/* Make sure the path separators in pathname, hardlink and symlink
|
||||
* are all slash '/', not the Windows path separator '\'. */
|
||||
entry_main = __la_win_entry_in_posix_pathseparator(entry);
|
||||
if (entry_main == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate ustar data");
|
||||
return(ARCHIVE_FATAL);
|
||||
}
|
||||
if (entry != entry_main)
|
||||
entry = entry_main;
|
||||
else
|
||||
entry_main = NULL;
|
||||
#else
|
||||
entry_main = NULL;
|
||||
#endif
|
||||
|
||||
ret = archive_entry_pathname_l(entry, &path, &len, sconv);
|
||||
if (ret != 0) {
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Pathname");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Can't translate pathname '%s' to %s",
|
||||
archive_entry_pathname(entry),
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
ret_final = ARCHIVE_WARN;
|
||||
}
|
||||
/* Include trailing null. */
|
||||
pathlength = (int)len + 1;
|
||||
|
||||
memset(h, 0, sizeof(h));
|
||||
format_octal(070707, h + c_magic_offset, c_magic_size);
|
||||
format_octal(archive_entry_dev(entry), h + c_dev_offset, c_dev_size);
|
||||
|
||||
ino = synthesize_ino_value(cpio, entry);
|
||||
if (ino < 0) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"No memory for ino translation table");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
} else if (ino > 0777777) {
|
||||
archive_set_error(&a->archive, ERANGE,
|
||||
"Too many files for this cpio format");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
format_octal(ino & 0777777, h + c_ino_offset, c_ino_size);
|
||||
|
||||
/* TODO: Set ret_final to ARCHIVE_WARN if any of these overflow. */
|
||||
format_octal(archive_entry_mode(entry), h + c_mode_offset, c_mode_size);
|
||||
format_octal(archive_entry_uid(entry), h + c_uid_offset, c_uid_size);
|
||||
format_octal(archive_entry_gid(entry), h + c_gid_offset, c_gid_size);
|
||||
format_octal(archive_entry_nlink(entry), h + c_nlink_offset, c_nlink_size);
|
||||
if (archive_entry_filetype(entry) == AE_IFBLK
|
||||
|| archive_entry_filetype(entry) == AE_IFCHR)
|
||||
format_octal(archive_entry_rdev(entry), h + c_rdev_offset, c_rdev_size);
|
||||
else
|
||||
format_octal(0, h + c_rdev_offset, c_rdev_size);
|
||||
format_octal(archive_entry_mtime(entry), h + c_mtime_offset, c_mtime_size);
|
||||
format_octal(pathlength, h + c_namesize_offset, c_namesize_size);
|
||||
|
||||
/* Non-regular files don't store bodies. */
|
||||
if (archive_entry_filetype(entry) != AE_IFREG)
|
||||
archive_entry_set_size(entry, 0);
|
||||
|
||||
/* Symlinks get the link written as the body of the entry. */
|
||||
ret = archive_entry_symlink_l(entry, &p, &len, sconv);
|
||||
if (ret != 0) {
|
||||
if (errno == ENOMEM) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate memory for Linkname");
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Can't translate linkname '%s' to %s",
|
||||
archive_entry_symlink(entry),
|
||||
archive_string_conversion_charset_name(sconv));
|
||||
ret_final = ARCHIVE_WARN;
|
||||
}
|
||||
if (len > 0 && p != NULL && *p != '\0')
|
||||
ret = format_octal(strlen(p), h + c_filesize_offset,
|
||||
c_filesize_size);
|
||||
else
|
||||
ret = format_octal(archive_entry_size(entry),
|
||||
h + c_filesize_offset, c_filesize_size);
|
||||
if (ret) {
|
||||
archive_set_error(&a->archive, ERANGE,
|
||||
"File is too large for cpio format.");
|
||||
ret_final = ARCHIVE_FAILED;
|
||||
goto exit_write_header;
|
||||
}
|
||||
|
||||
ret = __archive_write_output(a, h, sizeof(h));
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
|
||||
ret = __archive_write_output(a, path, pathlength);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
|
||||
cpio->entry_bytes_remaining = archive_entry_size(entry);
|
||||
|
||||
/* Write the symlink now. */
|
||||
if (p != NULL && *p != '\0') {
|
||||
ret = __archive_write_output(a, p, strlen(p));
|
||||
if (ret != ARCHIVE_OK) {
|
||||
ret_final = ARCHIVE_FATAL;
|
||||
goto exit_write_header;
|
||||
}
|
||||
}
|
||||
exit_write_header:
|
||||
archive_entry_free(entry_main);
|
||||
return (ret_final);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
archive_write_odc_data(struct archive_write *a, const void *buff, size_t s)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
int ret;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
if (s > cpio->entry_bytes_remaining)
|
||||
s = (size_t)cpio->entry_bytes_remaining;
|
||||
|
||||
ret = __archive_write_output(a, buff, s);
|
||||
cpio->entry_bytes_remaining -= s;
|
||||
if (ret >= 0)
|
||||
return (s);
|
||||
else
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Format a number into the specified field.
|
||||
*/
|
||||
static int
|
||||
format_octal(int64_t v, void *p, int digits)
|
||||
{
|
||||
int64_t max;
|
||||
int ret;
|
||||
|
||||
max = (((int64_t)1) << (digits * 3)) - 1;
|
||||
if (v >= 0 && v <= max) {
|
||||
format_octal_recursive(v, (char *)p, digits);
|
||||
ret = 0;
|
||||
} else {
|
||||
format_octal_recursive(max, (char *)p, digits);
|
||||
ret = -1;
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
format_octal_recursive(int64_t v, char *p, int s)
|
||||
{
|
||||
if (s == 0)
|
||||
return (v);
|
||||
v = format_octal_recursive(v, p+1, s-1);
|
||||
*p = '0' + ((char)v & 7);
|
||||
return (v >> 3);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_odc_close(struct archive_write *a)
|
||||
{
|
||||
int er;
|
||||
struct archive_entry *trailer;
|
||||
|
||||
trailer = archive_entry_new2(NULL);
|
||||
/* nlink = 1 here for GNU cpio compat. */
|
||||
archive_entry_set_nlink(trailer, 1);
|
||||
archive_entry_set_size(trailer, 0);
|
||||
archive_entry_set_pathname(trailer, "TRAILER!!!");
|
||||
er = write_header(a, trailer);
|
||||
archive_entry_free(trailer);
|
||||
return (er);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_odc_free(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
free(cpio->ino_list);
|
||||
free(cpio);
|
||||
a->format_data = NULL;
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
archive_write_odc_finish_entry(struct archive_write *a)
|
||||
{
|
||||
struct cpio *cpio;
|
||||
|
||||
cpio = (struct cpio *)a->format_data;
|
||||
return (__archive_write_nulls(a,
|
||||
(size_t)cpio->entry_bytes_remaining));
|
||||
}
|
||||
@@ -279,7 +279,7 @@ Values between 0 and 9 are supported.
|
||||
The interpretation of the compression level depends on the chosen
|
||||
compression method.
|
||||
.El
|
||||
.It Format cpio
|
||||
.It Format bin
|
||||
.Bl -tag -compact -width indent
|
||||
.It Cm hdrcharset
|
||||
The value is used as a character set name that will be
|
||||
@@ -519,6 +519,18 @@ XXX needs explanation XXX
|
||||
The value is used as a character set name that will be
|
||||
used when translating file names.
|
||||
.El
|
||||
.It Format odc
|
||||
.Bl -tag -compact -width indent
|
||||
.It Cm hdrcharset
|
||||
The value is used as a character set name that will be
|
||||
used when translating file names.
|
||||
.El
|
||||
.It Format pwb
|
||||
.Bl -tag -compact -width indent
|
||||
.It Cm hdrcharset
|
||||
The value is used as a character set name that will be
|
||||
used when translating file names.
|
||||
.El
|
||||
.It Format pax
|
||||
.Bl -tag -compact -width indent
|
||||
.It Cm hdrcharset
|
||||
|
||||
@@ -138,6 +138,7 @@
|
||||
#define HAVE_LIBZ 1
|
||||
#define HAVE_LIMITS_H 1
|
||||
#define HAVE_LINK 1
|
||||
#define HAVE_LINKAT 1
|
||||
#define HAVE_LOCALE_H 1
|
||||
#define HAVE_LOCALTIME_R 1
|
||||
#define HAVE_LONG_LONG_INT 1
|
||||
|
||||
@@ -56,40 +56,44 @@ The end of the archive is indicated by a special record with
|
||||
the pathname
|
||||
.Dq TRAILER!!! .
|
||||
.Ss PWB format
|
||||
XXX Any documentation of the original PWB/UNIX 1.0 format? XXX
|
||||
.Ss Old Binary Format
|
||||
The old binary
|
||||
The PWB binary
|
||||
.Nm
|
||||
format stores numbers as 2-byte and 4-byte binary values.
|
||||
format is the original format, when cpio was introduced as part of the
|
||||
Programmer's Work Bench system, a variant of 6th Edition UNIX. It
|
||||
stores numbers as 2-byte and 4-byte binary values.
|
||||
Each entry begins with a header in the following format:
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
struct header_old_cpio {
|
||||
unsigned short c_magic;
|
||||
unsigned short c_dev;
|
||||
unsigned short c_ino;
|
||||
unsigned short c_mode;
|
||||
unsigned short c_uid;
|
||||
unsigned short c_gid;
|
||||
unsigned short c_nlink;
|
||||
unsigned short c_rdev;
|
||||
unsigned short c_mtime[2];
|
||||
unsigned short c_namesize;
|
||||
unsigned short c_filesize[2];
|
||||
struct header_pwb_cpio {
|
||||
short h_magic;
|
||||
short h_dev;
|
||||
short h_ino;
|
||||
short h_mode;
|
||||
short h_uid;
|
||||
short h_gid;
|
||||
short h_nlink;
|
||||
short h_majmin;
|
||||
long h_mtime;
|
||||
short h_namesize;
|
||||
long h_filesize;
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Va unsigned short
|
||||
fields here are 16-bit integer values; the
|
||||
.Va unsigned int
|
||||
fields are 32-bit integer values.
|
||||
The fields are as follows
|
||||
.Va short
|
||||
fields here are 16-bit integer values, while the
|
||||
.Va long
|
||||
fields are 32 bit integers. Since PWB UNIX, like the 6th Edition UNIX
|
||||
it was based on, only ran on PDP-11 computers, they
|
||||
are in PDP-endian format, which has little-endian shorts, and
|
||||
big-endian longs. That is, the long integer whose hexadecimal
|
||||
representation is 0x12345678 would be stored in four successive bytes
|
||||
as 0x34, 0x12, 0x78, 0x56.
|
||||
The fields are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Va magic
|
||||
.It Va h_magic
|
||||
The integer value octal 070707.
|
||||
This value can be used to determine whether this archive is
|
||||
written with little-endian or big-endian integers.
|
||||
.It Va dev , Va ino
|
||||
.It Va h_dev , Va h_ino
|
||||
The device and inode numbers from the disk.
|
||||
These are used by programs that read
|
||||
.Nm
|
||||
@@ -97,9 +101,94 @@ archives to determine when two entries refer to the same file.
|
||||
Programs that synthesize
|
||||
.Nm
|
||||
archives should be careful to set these to distinct values for each entry.
|
||||
.It Va mode
|
||||
The mode specifies both the regular permissions and the file type.
|
||||
It consists of several bit fields as follows:
|
||||
.It Va h_mode
|
||||
The mode specifies both the regular permissions and the file type, and
|
||||
it also holds a couple of bits that are irrelevant to the cpio format,
|
||||
because the field is actually a raw copy of the mode field in the inode
|
||||
representing the file. These are the IALLOC flag, which shows that
|
||||
the inode entry is in use, and the ILARG flag, which shows that the
|
||||
file it represents is large enough to have indirect blocks pointers in
|
||||
the inode.
|
||||
The mode is decoded as follows:
|
||||
.Pp
|
||||
.Bl -tag -width "MMMMMMM" -compact
|
||||
.It 0100000
|
||||
IALLOC flag - irrelevant to cpio.
|
||||
.It 0060000
|
||||
This masks the file type bits.
|
||||
.It 0040000
|
||||
File type value for directories.
|
||||
.It 0020000
|
||||
File type value for character special devices.
|
||||
.It 0060000
|
||||
File type value for block special devices.
|
||||
.It 0010000
|
||||
ILARG flag - irrelevant to cpio.
|
||||
.It 0004000
|
||||
SUID bit.
|
||||
.It 0002000
|
||||
SGID bit.
|
||||
.It 0001000
|
||||
Sticky bit.
|
||||
.It 0000777
|
||||
The lower 9 bits specify read/write/execute permissions
|
||||
for world, group, and user following standard POSIX conventions.
|
||||
.El
|
||||
.It Va h_uid , Va h_gid
|
||||
The numeric user id and group id of the owner.
|
||||
.It Va h_nlink
|
||||
The number of links to this file.
|
||||
Directories always have a value of at least two here.
|
||||
Note that hardlinked files include file data with every copy in the archive.
|
||||
.It Va h_majmin
|
||||
For block special and character special entries,
|
||||
this field contains the associated device number, with the major
|
||||
number in the high byte, and the minor number in the low byte.
|
||||
For all other entry types, it should be set to zero by writers
|
||||
and ignored by readers.
|
||||
.It Va h_mtime
|
||||
Modification time of the file, indicated as the number
|
||||
of seconds since the start of the epoch,
|
||||
00:00:00 UTC January 1, 1970.
|
||||
.It Va h_namesize
|
||||
The number of bytes in the pathname that follows the header.
|
||||
This count includes the trailing NUL byte.
|
||||
.It Va h_filesize
|
||||
The size of the file. Note that this archive format is limited to 16
|
||||
megabyte file sizes, because PWB UNIX, like 6th Edition, only used
|
||||
an unsigned 24 bit integer for the file size internally.
|
||||
.El
|
||||
.Pp
|
||||
The pathname immediately follows the fixed header.
|
||||
If
|
||||
.Cm h_namesize
|
||||
is odd, an additional NUL byte is added after the pathname.
|
||||
The file data is then appended, again with an additional NUL
|
||||
appended if needed to get the next header at an even offset.
|
||||
.Pp
|
||||
Hardlinked files are not given special treatment;
|
||||
the full file contents are included with each copy of the
|
||||
file.
|
||||
.Ss New Binary Format
|
||||
The new binary
|
||||
.Nm
|
||||
format showed up when cpio was adopted into late 7th Edition UNIX.
|
||||
It is exactly like the PWB binary format, described above, except for
|
||||
three changes:
|
||||
.Pp
|
||||
First, UNIX now ran on more than one hardware type, so the endianness
|
||||
of 16 bit integers must be determined by observing the magic number at
|
||||
the start of the header. The 32 bit integers are still always stored
|
||||
with the most significant word first, though, so each of those two, in
|
||||
the struct shown above, was stored as an array of two 16 bit integers,
|
||||
in the traditional order. Those 16 bit integers, like all the others
|
||||
in the struct, were accessed using a macro that byte swapped them if
|
||||
necessary.
|
||||
.Pp
|
||||
Next, 7th Edition had more file types to store, and the IALLOC and ILARG
|
||||
flag bits were re-purposed to accommodate these. The revised use of the
|
||||
various bits is as follows:
|
||||
.Pp
|
||||
.Bl -tag -width "MMMMMMM" -compact
|
||||
.It 0170000
|
||||
This masks the file type bits.
|
||||
@@ -124,51 +213,26 @@ SUID bit.
|
||||
SGID bit.
|
||||
.It 0001000
|
||||
Sticky bit.
|
||||
On some systems, this modifies the behavior of executables and/or directories.
|
||||
.It 0000777
|
||||
The lower 9 bits specify read/write/execute permissions
|
||||
for world, group, and user following standard POSIX conventions.
|
||||
.El
|
||||
.It Va uid , Va gid
|
||||
The numeric user id and group id of the owner.
|
||||
.It Va nlink
|
||||
The number of links to this file.
|
||||
Directories always have a value of at least two here.
|
||||
Note that hardlinked files include file data with every copy in the archive.
|
||||
.It Va rdev
|
||||
For block special and character special entries,
|
||||
this field contains the associated device number.
|
||||
For all other entry types, it should be set to zero by writers
|
||||
and ignored by readers.
|
||||
.It Va mtime
|
||||
Modification time of the file, indicated as the number
|
||||
of seconds since the start of the epoch,
|
||||
00:00:00 UTC January 1, 1970.
|
||||
The four-byte integer is stored with the most-significant 16 bits first
|
||||
followed by the least-significant 16 bits.
|
||||
Each of the two 16 bit values are stored in machine-native byte order.
|
||||
.It Va namesize
|
||||
The number of bytes in the pathname that follows the header.
|
||||
This count includes the trailing NUL byte.
|
||||
.It Va filesize
|
||||
The size of the file.
|
||||
Note that this archive format is limited to
|
||||
four gigabyte file sizes.
|
||||
See
|
||||
.Va mtime
|
||||
above for a description of the storage of four-byte integers.
|
||||
.El
|
||||
.Pp
|
||||
The pathname immediately follows the fixed header.
|
||||
If the
|
||||
.Cm namesize
|
||||
is odd, an additional NUL byte is added after the pathname.
|
||||
The file data is then appended, padded with NUL
|
||||
bytes to an even length.
|
||||
Finally, the file size field now represents a signed 32 bit integer in
|
||||
the underlying file system, so the maximum file size has increased to
|
||||
2 gigabytes.
|
||||
.Pp
|
||||
Hardlinked files are not given special treatment;
|
||||
the full file contents are included with each copy of the
|
||||
file.
|
||||
Note that there is no obvious way to tell which of the two binary
|
||||
formats an archive uses, other than to see which one makes more
|
||||
sense. The typical error scenario is that a PWB format archive
|
||||
unpacked as if it were in the new format will create named sockets
|
||||
instead of directories, and then fail to unpack files that should
|
||||
go in those directories. Running
|
||||
.Va bsdcpio -itv
|
||||
on an unknown archive will make it obvious which it is: if it's
|
||||
PWB format, directories will be listed with an 's' instead of
|
||||
a 'd' as the first character of the mode string, and the larger
|
||||
files will have a '?' in that position.
|
||||
.Ss Portable ASCII Format
|
||||
.St -susv2
|
||||
standardized an ASCII variant that is portable across all
|
||||
@@ -180,6 +244,7 @@ format or as the
|
||||
format.
|
||||
It stores the same numeric fields as the old binary format, but
|
||||
represents them as 6-character or 11-character octal values.
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
struct cpio_odc_header {
|
||||
char c_magic[6];
|
||||
@@ -196,9 +261,9 @@ struct cpio_odc_header {
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The fields are identical to those in the old binary format.
|
||||
The fields are identical to those in the new binary format.
|
||||
The name and file body follow the fixed header.
|
||||
Unlike the old binary format, there is no additional padding
|
||||
Unlike the binary formats, there is no additional padding
|
||||
after the pathname or file contents.
|
||||
If the files being archived are themselves entirely ASCII, then
|
||||
the resulting archive will be entirely ASCII, except for the
|
||||
@@ -207,6 +272,7 @@ NUL byte that terminates the name field.
|
||||
The "new" ASCII format uses 8-byte hexadecimal fields for
|
||||
all numbers and separates device numbers into separate fields
|
||||
for major and minor numbers.
|
||||
.Pp
|
||||
.Bd -literal -offset indent
|
||||
struct cpio_newc_header {
|
||||
char c_magic[6];
|
||||
@@ -227,7 +293,7 @@ struct cpio_newc_header {
|
||||
.Ed
|
||||
.Pp
|
||||
Except as specified below, the fields here match those specified
|
||||
for the old binary format above.
|
||||
for the new binary format above.
|
||||
.Bl -tag -width indent
|
||||
.It Va magic
|
||||
The string
|
||||
@@ -288,9 +354,9 @@ while working in AT&T's Unix Support Group.
|
||||
It appeared in 1977 as part of PWB/UNIX 1.0, the
|
||||
.Dq Programmer's Work Bench
|
||||
derived from
|
||||
.At v6
|
||||
.At 6th Edition UNIX
|
||||
that was used internally at AT&T.
|
||||
Both the old binary and old character formats were in use
|
||||
Both the new binary and old character formats were in use
|
||||
by 1980, according to the System III source released
|
||||
by SCO under their
|
||||
.Dq Ancient Unix
|
||||
@@ -304,9 +370,9 @@ The
|
||||
format is mis-named, as it uses a simple checksum and
|
||||
not a cyclic redundancy check.
|
||||
.Pp
|
||||
The old binary format is limited to 16 bits for user id,
|
||||
group id, device, and inode numbers.
|
||||
It is limited to 4 gigabyte file sizes.
|
||||
The binary formats are limited to 16 bits for user id, group id,
|
||||
device, and inode numbers. They are limited to 16 megabyte and 2
|
||||
gigabyte file sizes for the older and newer variants, respectively.
|
||||
.Pp
|
||||
The old ASCII format is limited to 18 bits for
|
||||
the user id, group id, device, and inode numbers.
|
||||
|
||||
@@ -201,28 +201,27 @@ POSIX.1-2001 extended the ustar format to create the
|
||||
.Dq pax interchange
|
||||
format.
|
||||
.Ss Cpio Formats
|
||||
The libarchive library can read a number of common cpio variants and can write
|
||||
.Dq odc
|
||||
and
|
||||
.Dq newc
|
||||
format archives.
|
||||
A cpio archive stores each entry as a fixed-size header followed
|
||||
by a variable-length filename and variable-length data.
|
||||
Unlike the tar format, the cpio format does only minimal padding
|
||||
of the header or file data.
|
||||
There are several cpio variants, which differ primarily in
|
||||
how they store the initial header: some store the values as
|
||||
octal or hexadecimal numbers in ASCII, others as binary values of
|
||||
varying byte order and length.
|
||||
The libarchive library can read and write a number of common cpio
|
||||
variants. A cpio archive stores each entry as a fixed-size header
|
||||
followed by a variable-length filename and variable-length data.
|
||||
Unlike the tar format, the cpio format does only minimal padding of
|
||||
the header or file data. There are several cpio variants, which
|
||||
differ primarily in how they store the initial header: some store the
|
||||
values as octal or hexadecimal numbers in ASCII, others as binary
|
||||
values of varying byte order and length.
|
||||
.Bl -tag -width indent
|
||||
.It Cm binary
|
||||
The libarchive library transparently reads both big-endian and little-endian
|
||||
variants of the original binary cpio format.
|
||||
This format used 32-bit binary values for file size and mtime,
|
||||
and 16-bit binary values for the other fields.
|
||||
The libarchive library transparently reads both big-endian and
|
||||
little-endian variants of the the two binary cpio formats; the
|
||||
original one from PWB/UNIX, and the later, more widely used, variant.
|
||||
This format used 32-bit binary values for file size and mtime, and
|
||||
16-bit binary values for the other fields. The formats support only
|
||||
the file types present in UNIX at the time of their creation. File
|
||||
sizes are limited to 24 bits in the PWB format, because of the limits
|
||||
of the file system, and to 31 bits in the newer binary format, where
|
||||
signed 32 bit longs were used.
|
||||
.It Cm odc
|
||||
The libarchive library can both read and write this
|
||||
POSIX-standard format, which is officially known as the
|
||||
This is the POSIX standardized format, which is officially known as the
|
||||
.Dq cpio interchange format
|
||||
or the
|
||||
.Dq octet-oriented cpio archive format
|
||||
|
||||
@@ -105,7 +105,7 @@ POSIX
|
||||
.Dq pax interchange format
|
||||
archives,
|
||||
.It
|
||||
POSIX octet-oriented cpio archives,
|
||||
cpio archives,
|
||||
.It
|
||||
Zip archive,
|
||||
.It
|
||||
|
||||
@@ -150,7 +150,11 @@ typedef struct _U32_S { U32 v; } _PACKED U32_S;
|
||||
#if GCC_VERSION >= 409
|
||||
__attribute__((__no_sanitize_undefined__))
|
||||
#endif
|
||||
static inline U32 A32(const void * x)
|
||||
#if defined(_MSC_VER)
|
||||
static __inline U32 A32(const void * x)
|
||||
#else
|
||||
static inline U32 A32(const void* x)
|
||||
#endif
|
||||
{
|
||||
return (((const U32_S *)(x))->v);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user