From 11f3dcb04887fccf38a8eda19d498bf7a5060486 Mon Sep 17 00:00:00 2001 From: LibArchive Upstream Date: Sun, 9 Jul 2017 19:38:04 -0700 Subject: LibArchive 2017-07-09 (98a69539) Code extracted from: https://github.com/libarchive/libarchive.git at commit 98a695399e8e7420635a5448aecde8b0a82fb83a (v3.3.2). --- CMakeLists.txt | 410 +++++-- build/cmake/config.h.in | 92 +- build/version | 2 +- libarchive/CMakeLists.txt | 15 +- libarchive/archive.h | 4 +- libarchive/archive_check_magic.c | 2 +- libarchive/archive_disk_acl_darwin.c | 559 +++++++++ libarchive/archive_disk_acl_freebsd.c | 700 +++++++++++ libarchive/archive_disk_acl_linux.c | 743 +++++++++++ libarchive/archive_disk_acl_sunos.c | 821 +++++++++++++ libarchive/archive_entry.3 | 2 +- libarchive/archive_entry.c | 31 +- libarchive/archive_entry.h | 2 +- libarchive/archive_entry_acl.3 | 10 +- libarchive/archive_entry_paths.3 | 12 +- libarchive/archive_entry_perms.3 | 4 +- libarchive/archive_entry_sparse.c | 4 +- libarchive/archive_getdate.c | 2 +- libarchive/archive_openssl_hmac_private.h | 2 +- libarchive/archive_pack_dev.c | 2 +- libarchive/archive_platform.h | 26 - libarchive/archive_platform_acl.h | 49 + libarchive/archive_platform_xattr.h | 41 + libarchive/archive_random.c | 5 +- libarchive/archive_read.c | 3 +- libarchive/archive_read_disk.3 | 72 +- libarchive/archive_read_disk_entry_from_file.c | 1285 +++----------------- libarchive/archive_read_disk_private.h | 9 + libarchive/archive_read_format.3 | 6 +- libarchive/archive_read_open.3 | 4 +- libarchive/archive_read_support_filter_lz4.c | 6 +- libarchive/archive_read_support_format_cab.c | 156 +-- libarchive/archive_read_support_format_cpio.c | 2 +- libarchive/archive_read_support_format_iso9660.c | 5 +- libarchive/archive_read_support_format_lha.c | 2 +- libarchive/archive_read_support_format_mtree.c | 180 +-- libarchive/archive_read_support_format_rar.c | 2 +- libarchive/archive_read_support_format_tar.c | 18 +- libarchive/archive_read_support_format_warc.c | 9 +- libarchive/archive_read_support_format_zip.c | 39 +- libarchive/archive_string.c | 3 +- libarchive/archive_string_sprintf.c | 2 +- libarchive/archive_util.c | 88 +- libarchive/archive_version_details.c | 133 ++ libarchive/archive_write_add_filter.c | 2 +- libarchive/archive_write_add_filter_by_name.c | 2 +- libarchive/archive_write_add_filter_lz4.c | 2 +- libarchive/archive_write_add_filter_program.c | 2 +- libarchive/archive_write_data.3 | 24 +- libarchive/archive_write_disk.3 | 185 +-- libarchive/archive_write_disk_acl.c | 654 ---------- libarchive/archive_write_disk_posix.c | 296 +++-- libarchive/archive_write_disk_private.h | 6 +- libarchive/archive_write_finish_entry.3 | 5 +- libarchive/archive_write_format.3 | 1 - libarchive/archive_write_set_format.c | 2 +- libarchive/archive_write_set_format_by_name.c | 2 +- .../archive_write_set_format_filter_by_ext.c | 2 +- libarchive/archive_write_set_format_pax.c | 17 +- libarchive/archive_write_set_format_warc.c | 2 +- libarchive/config_freebsd.h | 351 ++++-- libarchive/libarchive_changes.3 | 1 + libarchive/mtree.5 | 2 +- libarchive/xxhash.c | 12 +- 64 files changed, 4373 insertions(+), 2761 deletions(-) create mode 100644 libarchive/archive_disk_acl_darwin.c create mode 100644 libarchive/archive_disk_acl_freebsd.c create mode 100644 libarchive/archive_disk_acl_linux.c create mode 100644 libarchive/archive_disk_acl_sunos.c create mode 100644 libarchive/archive_platform_acl.h create mode 100644 libarchive/archive_platform_xattr.h create mode 100644 libarchive/archive_version_details.c delete mode 100644 libarchive/archive_write_disk_acl.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ca9d8f..73bf07b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -552,6 +552,7 @@ LA_CHECK_INCLUDE_FILE("sys/types.h" HAVE_SYS_TYPES_H) # Alphabetize the rest unless there's a compelling reason LA_CHECK_INCLUDE_FILE("acl/libacl.h" HAVE_ACL_LIBACL_H) +LA_CHECK_INCLUDE_FILE("attr/xattr.h" HAVE_ATTR_XATTR_H) LA_CHECK_INCLUDE_FILE("ctype.h" HAVE_CTYPE_H) LA_CHECK_INCLUDE_FILE("copyfile.h" HAVE_COPYFILE_H) LA_CHECK_INCLUDE_FILE("direct.h" HAVE_DIRECT_H) @@ -579,6 +580,7 @@ int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS) LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H) LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H) +LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H) LA_CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H) LA_CHECK_INCLUDE_FILE("paths.h" HAVE_PATHS_H) LA_CHECK_INCLUDE_FILE("poll.h" HAVE_POLL_H) @@ -596,11 +598,13 @@ LA_CHECK_INCLUDE_FILE("string.h" HAVE_STRING_H) LA_CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H) LA_CHECK_INCLUDE_FILE("sys/acl.h" HAVE_SYS_ACL_H) LA_CHECK_INCLUDE_FILE("sys/cdefs.h" HAVE_SYS_CDEFS_H) +LA_CHECK_INCLUDE_FILE("sys/extattr.h" HAVE_SYS_EXTATTR_H) LA_CHECK_INCLUDE_FILE("sys/ioctl.h" HAVE_SYS_IOCTL_H) LA_CHECK_INCLUDE_FILE("sys/mkdev.h" HAVE_SYS_MKDEV_H) LA_CHECK_INCLUDE_FILE("sys/mount.h" HAVE_SYS_MOUNT_H) LA_CHECK_INCLUDE_FILE("sys/param.h" HAVE_SYS_PARAM_H) LA_CHECK_INCLUDE_FILE("sys/poll.h" HAVE_SYS_POLL_H) +LA_CHECK_INCLUDE_FILE("sys/richacl.h" HAVE_SYS_RICHACL_H) LA_CHECK_INCLUDE_FILE("sys/select.h" HAVE_SYS_SELECT_H) LA_CHECK_INCLUDE_FILE("sys/stat.h" HAVE_SYS_STAT_H) LA_CHECK_INCLUDE_FILE("sys/statfs.h" HAVE_SYS_STATFS_H) @@ -610,6 +614,7 @@ LA_CHECK_INCLUDE_FILE("sys/utime.h" HAVE_SYS_UTIME_H) LA_CHECK_INCLUDE_FILE("sys/utsname.h" HAVE_SYS_UTSNAME_H) LA_CHECK_INCLUDE_FILE("sys/vfs.h" HAVE_SYS_VFS_H) LA_CHECK_INCLUDE_FILE("sys/wait.h" HAVE_SYS_WAIT_H) +LA_CHECK_INCLUDE_FILE("sys/xattr.h" HAVE_SYS_XATTR_H) LA_CHECK_INCLUDE_FILE("time.h" HAVE_TIME_H) LA_CHECK_INCLUDE_FILE("unistd.h" HAVE_UNISTD_H) LA_CHECK_INCLUDE_FILE("utime.h" HAVE_UTIME_H) @@ -618,6 +623,9 @@ LA_CHECK_INCLUDE_FILE("wctype.h" HAVE_WCTYPE_H) LA_CHECK_INCLUDE_FILE("windows.h" HAVE_WINDOWS_H) IF(ENABLE_CNG) LA_CHECK_INCLUDE_FILE("Bcrypt.h" HAVE_BCRYPT_H) + IF(HAVE_BCRYPT_H) + LIST(APPEND ADDITIONAL_LIBS "Bcrypt") + ENDIF(HAVE_BCRYPT_H) ELSE(ENABLE_CNG) UNSET(HAVE_BCRYPT_H CACHE) ENDIF(ENABLE_CNG) @@ -1195,7 +1203,6 @@ CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS) CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN) CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT) CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R) -CHECK_FUNCTION_EXISTS_GLIBC(dirfd HAVE_DIRFD) CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR) CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS) CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD) @@ -1295,6 +1302,10 @@ CHECK_C_SOURCE_COMPILES( "#include \nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}" HAVE_READDIR_R) +# dirfd can be either a function or a macro. +CHECK_C_SOURCE_COMPILES( + "#include \nint main() {DIR *d = opendir(\".\"); return dirfd(d);}" + HAVE_DIRFD) # Only detect readlinkat() if we also have AT_FDCWD in unistd.h. # NOTE: linux requires fcntl.h for AT_FDCWD. @@ -1527,60 +1538,105 @@ CHECK_FILE_OFFSET_BITS() # Check for Extended Attribute libraries, headers, and functions # IF(ENABLE_XATTR) - LA_CHECK_INCLUDE_FILE(attr/xattr.h HAVE_ATTR_XATTR_H) - LA_CHECK_INCLUDE_FILE(sys/xattr.h HAVE_SYS_XATTR_H) - LA_CHECK_INCLUDE_FILE(sys/extattr.h HAVE_SYS_EXTATTR_H) CHECK_LIBRARY_EXISTS(attr "setxattr" "" HAVE_LIBATTR) IF(HAVE_LIBATTR) SET(CMAKE_REQUIRED_LIBRARIES "attr") ENDIF(HAVE_LIBATTR) CHECK_SYMBOL_EXISTS(EXTATTR_NAMESPACE_USER "sys/types.h;sys/extattr.h" HAVE_DECL_EXTATTR_NAMESPACE_USER) - CHECK_FUNCTION_EXISTS_GLIBC(extattr_get_file HAVE_EXTATTR_GET_FILE) - CHECK_FUNCTION_EXISTS_GLIBC(extattr_list_file HAVE_EXTATTR_LIST_FILE) - CHECK_FUNCTION_EXISTS_GLIBC(extattr_set_fd HAVE_EXTATTR_SET_FD) - CHECK_FUNCTION_EXISTS_GLIBC(extattr_set_file HAVE_EXTATTR_SET_FILE) - CHECK_FUNCTION_EXISTS_GLIBC(fgetxattr HAVE_FGETXATTR) - CHECK_FUNCTION_EXISTS_GLIBC(flistxattr HAVE_FLISTXATTR) - CHECK_FUNCTION_EXISTS_GLIBC(fsetxattr HAVE_FSETXATTR) - CHECK_FUNCTION_EXISTS_GLIBC(getxattr HAVE_GETXATTR) - CHECK_FUNCTION_EXISTS_GLIBC(lgetxattr HAVE_LGETXATTR) - CHECK_FUNCTION_EXISTS_GLIBC(listxattr HAVE_LISTXATTR) - CHECK_FUNCTION_EXISTS_GLIBC(llistxattr HAVE_LLISTXATTR) - CHECK_FUNCTION_EXISTS_GLIBC(lsetxattr HAVE_LSETXATTR) - CHECK_FUNCTION_EXISTS_GLIBC(fgetea HAVE_FGETEA) - CHECK_FUNCTION_EXISTS_GLIBC(flistea HAVE_FLISTEA) - CHECK_FUNCTION_EXISTS_GLIBC(fsetea HAVE_FSETEA) - CHECK_FUNCTION_EXISTS_GLIBC(getea HAVE_GETEA) - CHECK_FUNCTION_EXISTS_GLIBC(lgetea HAVE_LGETEA) - CHECK_FUNCTION_EXISTS_GLIBC(listea HAVE_LISTEA) - CHECK_FUNCTION_EXISTS_GLIBC(llistea HAVE_LLISTEA) - CHECK_FUNCTION_EXISTS_GLIBC(lsetea HAVE_LSETEA) + CHECK_SYMBOL_EXISTS(XATTR_NOFOLLOW "sys/xattr.h" HAVE_DECL_XATTR_NOFOLLOW) + IF(HAVE_SYS_XATTR_H AND HAVE_DECL_XATTR_NOFOLLOW) + CHECK_FUNCTION_EXISTS(fgetxattr HAVE_FGETXATTR) + CHECK_FUNCTION_EXISTS(flistxattr HAVE_FLISTXATTR) + CHECK_FUNCTION_EXISTS(fsetxattr HAVE_FSETXATTR) + CHECK_FUNCTION_EXISTS(getxattr HAVE_GETXATTR) + CHECK_FUNCTION_EXISTS(listxattr HAVE_LISTXATTR) + CHECK_FUNCTION_EXISTS(setxattr HAVE_SETXATTR) + IF(HAVE_FGETXATTR AND + HAVE_FLISTXATTR AND + HAVE_FSETXATTR AND + HAVE_GETXATTR AND + HAVE_LISTXATTR AND + HAVE_SETXATTR) + SET(ARCHIVE_XATTR_DARWIN TRUE) + ENDIF() + ELSEIF(HAVE_SYS_EXTATTR_H AND HAVE_DECL_EXTATTR_NAMESPACE_USER) + # FreeBSD xattr support + CHECK_FUNCTION_EXISTS(extattr_get_fd HAVE_EXTATTR_GET_FD) + CHECK_FUNCTION_EXISTS(extattr_get_file HAVE_EXTATTR_GET_FILE) + CHECK_FUNCTION_EXISTS(extattr_get_link HAVE_EXTATTR_GET_LINK) + CHECK_FUNCTION_EXISTS(extattr_list_fd HAVE_EXTATTR_LIST_FD) + CHECK_FUNCTION_EXISTS(extattr_list_file HAVE_EXTATTR_LIST_FILE) + CHECK_FUNCTION_EXISTS(extattr_list_link HAVE_EXTATTR_LIST_LINK) + CHECK_FUNCTION_EXISTS(extattr_set_fd HAVE_EXTATTR_SET_FD) + CHECK_FUNCTION_EXISTS(extattr_set_link HAVE_EXTATTR_SET_LINK) + IF(HAVE_EXTATTR_GET_FD AND + HAVE_EXTATTR_GET_FILE AND + HAVE_EXTATTR_GET_LINK AND + HAVE_EXTATTR_LIST_FD AND + HAVE_EXTATTR_LIST_FILE AND + HAVE_EXTATTR_LIST_LINK AND + HAVE_EXTATTR_SET_FD AND + HAVE_EXTATTR_SET_LINK) + SET(ARCHIVE_XATTR_FREEBSD TRUE) + ENDIF() + ELSEIF(HAVE_SYS_XATTR_H OR HAVE_ATTR_XATTR_H) + # Linux xattr support + CHECK_FUNCTION_EXISTS_GLIBC(fgetxattr HAVE_FGETXATTR) + CHECK_FUNCTION_EXISTS_GLIBC(flistxattr HAVE_FLISTXATTR) + CHECK_FUNCTION_EXISTS_GLIBC(fsetxattr HAVE_FSETXATTR) + CHECK_FUNCTION_EXISTS_GLIBC(getxattr HAVE_GETXATTR) + CHECK_FUNCTION_EXISTS_GLIBC(lgetxattr HAVE_LGETXATTR) + CHECK_FUNCTION_EXISTS_GLIBC(listxattr HAVE_LISTXATTR) + CHECK_FUNCTION_EXISTS_GLIBC(llistxattr HAVE_LLISTXATTR) + CHECK_FUNCTION_EXISTS_GLIBC(lsetxattr HAVE_LSETXATTR) + IF(HAVE_FGETXATTR AND + HAVE_FLISTXATTR AND + HAVE_FSETXATTR AND + HAVE_GETXATTR AND + HAVE_LGETXATTR AND + HAVE_LISTXATTR AND + HAVE_LLISTXATTR AND + HAVE_LSETXATTR) + SET(ARCHIVE_XATTR_LINUX TRUE) + ENDIF() + ELSEIF(HAVE_SYS_EA_H) + # AIX xattr support + CHECK_FUNCTION_EXISTS(fgetea HAVE_FGETEA) + CHECK_FUNCTION_EXISTS(flistea HAVE_FLISTEA) + CHECK_FUNCTION_EXISTS(fsetea HAVE_FSETEA) + CHECK_FUNCTION_EXISTS(getea HAVE_GETEA) + CHECK_FUNCTION_EXISTS(lgetea HAVE_LGETEA) + CHECK_FUNCTION_EXISTS(listea HAVE_LISTEA) + CHECK_FUNCTION_EXISTS(llistea HAVE_LLISTEA) + CHECK_FUNCTION_EXISTS(lsetea HAVE_LSETEA) + IF(HAVE_FGETEA AND + HAVE_FLISTEA AND + HAVE_FSETEA AND + HAVE_GETEA AND + HAVE_LGETEA AND + HAVE_LISTEA AND + HAVE_LLISTEA AND + HAVE_LSETEA) + SET(ARCHIVE_XATTR_AIX TRUE) + ENDIF() + ENDIF() + + IF(ARCHIVE_XATTR_DARWIN) + MESSAGE(STATUS "Extended attributes support: Darwin") + ELSEIF(ARCHIVE_XATTR_FREEBSD) + MESSAGE(STATUS "Extended attributes support: FreeBSD") + ELSEIF(ARCHIVE_XATTR_LINUX) + MESSAGE(STATUS "Extended attributes support: Linux") + ELSEIF(ARCHIVE_XATTR_AIX) + MESSAGE(STATUS "Extended attributes support: AIX") + ELSE() + MESSAGE(STATUS "Extended attributes support: none") + ENDIF() ELSE(ENABLE_XATTR) - SET(HAVE_ATTR_LIB FALSE) - SET(HAVE_ATTR_XATTR_H FALSE) - SET(HAVE_DECL_EXTATTR_NAMESPACE_USER FALSE) - SET(HAVE_EXTATTR_GET_FILE FALSE) - SET(HAVE_EXTATTR_LIST_FILE FALSE) - SET(HAVE_EXTATTR_SET_FD FALSE) - SET(HAVE_EXTATTR_SET_FILE FALSE) - SET(HAVE_FGETEA FALSE) - SET(HAVE_FGETXATTR FALSE) - SET(HAVE_FLISTEA FALSE) - SET(HAVE_FLISTXATTR FALSE) - SET(HAVE_FSETEA FALSE) - SET(HAVE_FSETXATTR FALSE) - SET(HAVE_GETEA FALSE) - SET(HAVE_GETXATTR FALSE) - SET(HAVE_LGETEA FALSE) - SET(HAVE_LGETXATTR FALSE) - SET(HAVE_LISTEA FALSE) - SET(HAVE_LISTXATTR FALSE) - SET(HAVE_LLISTEA FALSE) - SET(HAVE_LLISTXATTR FALSE) - SET(HAVE_LSETEA FALSE) - SET(HAVE_LSETXATTR FALSE) - SET(HAVE_SYS_EXTATTR_H FALSE) - SET(HAVE_SYS_XATTR_H FALSE) + SET(ARCHIVE_XATTR_DARWIN FALSE) + SET(ARCHIVE_XATTR_FREEBSD FALSE) + SET(ARCHIVE_XATTR_LINUX FALSE) + SET(ARCHIVE_XATTR_AIX FALSE) ENDIF(ENABLE_XATTR) # @@ -1592,78 +1648,212 @@ ENDIF(ENABLE_XATTR) # which makes the following checks rather more complex than I would like. # IF(ENABLE_ACL) + # Solaris and derivates ACLs + CHECK_FUNCTION_EXISTS(acl HAVE_ACL) + CHECK_FUNCTION_EXISTS(facl HAVE_FACL) + + # Libacl CHECK_LIBRARY_EXISTS(acl "acl_get_file" "" HAVE_LIBACL) IF(HAVE_LIBACL) SET(CMAKE_REQUIRED_LIBRARIES "acl") FIND_LIBRARY(ACL_LIBRARY NAMES acl) LIST(APPEND ADDITIONAL_LIBS ${ACL_LIBRARY}) ENDIF(HAVE_LIBACL) - # - CHECK_FUNCTION_EXISTS_GLIBC(acl_create_entry HAVE_ACL_CREATE_ENTRY) - CHECK_FUNCTION_EXISTS_GLIBC(acl_init HAVE_ACL_INIT) - CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd HAVE_ACL_SET_FD) - CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd_np HAVE_ACL_SET_FD_NP) - CHECK_FUNCTION_EXISTS_GLIBC(acl_set_file HAVE_ACL_SET_FILE) - CHECK_TYPE_EXISTS(acl_permset_t "${INCLUDES}" HAVE_ACL_PERMSET_T) - - # The "acl_get_perm()" function was omitted from the POSIX draft. - # (It's a pretty obvious oversight; otherwise, there's no way to - # test for specific permissions in a permset.) Linux uses the obvious - # name, FreeBSD adds _np to mark it as "non-Posix extension." - # Test for both as a double-check that we really have POSIX-style ACL support. - CHECK_FUNCTION_EXISTS(acl_get_fd_np HAVE_ACL_GET_FD_NP) - CHECK_FUNCTION_EXISTS(acl_get_perm HAVE_ACL_GET_PERM) - CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP) - CHECK_FUNCTION_EXISTS(acl_get_link HAVE_ACL_GET_LINK) - CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP) - CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP) - CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP) - CHECK_SYMBOL_EXISTS(ACL_TYPE_NFS4 "${INCLUDES}" HAVE_ACL_TYPE_NFS4) - - # MacOS has an acl.h that isn't POSIX. It can be detected by - # checking for ACL_USER - CHECK_SYMBOL_EXISTS(ACL_USER "${INCLUDES}" HAVE_ACL_USER) - CHECK_C_SOURCE_COMPILES("#include + + CHECK_TYPE_EXISTS(acl_t "sys/types.h;sys/acl.h" HAVE_ACL_T) + CHECK_TYPE_EXISTS(acl_entry_t "sys/types.h;sys/acl.h" HAVE_ACL_ENTRY_T) + CHECK_TYPE_EXISTS(acl_permset_t "sys/types.h;sys/acl.h" HAVE_ACL_PERMSET_T) + CHECK_TYPE_EXISTS(acl_tag_t "sys/types.h;sys/acl.h" HAVE_ACL_TAG_T) + + IF(HAVE_ACL AND HAVE_FACL) + CHECK_TYPE_EXISTS(aclent_t "sys/acl.h" HAVE_ACLENT_T) + IF(HAVE_ACLENT_T) + CHECK_SYMBOL_EXISTS(GETACL "sys/acl.h" HAVE_DECL_GETACL) + CHECK_SYMBOL_EXISTS(GETACLCNT "sys/acl.h" HAVE_DECL_GETACLCNT) + CHECK_SYMBOL_EXISTS(SETACL "sys/acl.h" HAVE_DECL_SETACL) + IF(HAVE_DECL_GETACL AND + HAVE_DECL_GETACLCNT AND + HAVE_DECL_SETACL) + SET(ARCHIVE_ACL_SUNOS TRUE) + ENDIF() + CHECK_TYPE_EXISTS(ace_t "sys/acl.h" HAVE_ACE_T) + IF(HAVE_ACE_T) + CHECK_SYMBOL_EXISTS(ACE_GETACL "sys/acl.h" HAVE_DECL_ACE_GETACL) + CHECK_SYMBOL_EXISTS(ACE_GETACLCNT "sys/acl.h" HAVE_DECL_ACE_GETACLCNT) + CHECK_SYMBOL_EXISTS(ACE_SETACL "sys/acl.h" HAVE_DECL_ACE_SETACL) + IF(HAVE_DECL_ACE_GETACL AND + HAVE_DECL_ACE_GETACLCNT AND + HAVE_DECL_ACE_SETACL) + SET(ARCHIVE_ACL_SUNOS_NFS4 TRUE) + ENDIF() + ENDIF(HAVE_ACE_T) + ENDIF(HAVE_ACLENT_T) + ENDIF(HAVE_ACL AND HAVE_FACL) + + IF(HAVE_ACL_T AND HAVE_ACL_ENTRY_T AND HAVE_ACL_PERMSET_T AND HAVE_ACL_TAG_T) + CHECK_FUNCTION_EXISTS_GLIBC(acl_add_perm HAVE_ACL_ADD_PERM) + CHECK_FUNCTION_EXISTS_GLIBC(acl_clear_perms HAVE_ACL_CLEAR_PERMS) + CHECK_FUNCTION_EXISTS_GLIBC(acl_create_entry HAVE_ACL_CREATE_ENTRY) + CHECK_FUNCTION_EXISTS_GLIBC(acl_delete_def_file HAVE_ACL_DELETE_DEF_FILE) + CHECK_FUNCTION_EXISTS_GLIBC(acl_free HAVE_ACL_FREE) + CHECK_FUNCTION_EXISTS_GLIBC(acl_get_entry HAVE_ACL_GET_ENTRY) + CHECK_FUNCTION_EXISTS_GLIBC(acl_get_fd HAVE_ACL_GET_FD) + CHECK_FUNCTION_EXISTS_GLIBC(acl_get_file HAVE_ACL_GET_FILE) + CHECK_FUNCTION_EXISTS_GLIBC(acl_get_permset HAVE_ACL_GET_PERMSET) + CHECK_FUNCTION_EXISTS_GLIBC(acl_get_qualifier HAVE_ACL_GET_QUALIFIER) + CHECK_FUNCTION_EXISTS_GLIBC(acl_get_tag_type HAVE_ACL_GET_TAG_TYPE) + CHECK_FUNCTION_EXISTS_GLIBC(acl_init HAVE_ACL_INIT) + CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd HAVE_ACL_SET_FD) + CHECK_FUNCTION_EXISTS_GLIBC(acl_set_file HAVE_ACL_SET_FILE) + CHECK_FUNCTION_EXISTS_GLIBC(acl_set_qualifier HAVE_ACL_SET_QUALIFIER) + CHECK_FUNCTION_EXISTS_GLIBC(acl_set_tag_type HAVE_ACL_SET_TAG_TYPE) + IF(HAVE_ACL_ADD_PERM AND + HAVE_ACL_CLEAR_PERMS AND + HAVE_ACL_CREATE_ENTRY AND + HAVE_ACL_DELETE_DEF_FILE AND + HAVE_ACL_FREE AND + HAVE_ACL_GET_ENTRY AND + HAVE_ACL_GET_FD AND + HAVE_ACL_GET_FILE AND + HAVE_ACL_GET_PERMSET AND + HAVE_ACL_GET_QUALIFIER AND + HAVE_ACL_GET_TAG_TYPE AND + HAVE_ACL_INIT AND + HAVE_ACL_SET_FD AND + HAVE_ACL_SET_FILE AND + HAVE_ACL_SET_QUALIFIER AND + HAVE_ACL_SET_TAG_TYPE) + SET(HAVE_POSIX_ACL_FUNCS 1) + ENDIF() + + CHECK_FUNCTION_EXISTS_GLIBC(acl_get_perm HAVE_ACL_GET_PERM) + + IF(HAVE_POSIX_ACL_FUNCS AND HAVE_ACL_LIBACL_H AND HAVE_LIBACL AND + HAVE_ACL_GET_PERM) + SET(ARCHIVE_ACL_LIBACL TRUE) + ELSE() + CHECK_FUNCTION_EXISTS(acl_add_flag_np HAVE_ACL_ADD_FLAG_NP) + CHECK_FUNCTION_EXISTS(acl_clear_flags_np HAVE_ACL_CLEAR_FLAGS_NP) + CHECK_FUNCTION_EXISTS(acl_get_brand_np HAVE_ACL_GET_BRAND_NP) + CHECK_FUNCTION_EXISTS(acl_get_entry_type_np HAVE_ACL_GET_ENTRY_TYPE_NP) + CHECK_FUNCTION_EXISTS(acl_get_flag_np HAVE_ACL_GET_FLAG_NP) + CHECK_FUNCTION_EXISTS(acl_get_flagset_np HAVE_ACL_GET_FLAGSET_NP) + CHECK_FUNCTION_EXISTS(acl_get_fd_np HAVE_ACL_GET_FD_NP) + CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP) + CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP) + CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP) + CHECK_FUNCTION_EXISTS(acl_set_entry_type_np HAVE_ACL_SET_ENTRY_TYPE_NP) + CHECK_FUNCTION_EXISTS(acl_set_fd_np HAVE_ACL_SET_FD_NP) + CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP) + CHECK_FUNCTION_EXISTS(mbr_gid_to_uuid HAVE_MBR_GID_TO_UUID) + CHECK_FUNCTION_EXISTS(mbr_uid_to_uuid HAVE_MBR_UID_TO_UUID) + CHECK_FUNCTION_EXISTS(mbr_uuid_to_id HAVE_MBR_UUID_TO_ID) + + CHECK_C_SOURCE_COMPILES("#include #include -int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_ACL_TYPE_EXTENDED) +int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_DECL_ACL_TYPE_EXTENDED) + CHECK_C_SOURCE_COMPILES("#include +#include +int main(void) { return ACL_SYNCHRONIZE; }" HAVE_DECL_ACL_SYNCHRONIZE) + CHECK_SYMBOL_EXISTS(ACL_TYPE_NFS4 "sys/acl.h" HAVE_DECL_ACL_TYPE_NFS4) + CHECK_SYMBOL_EXISTS(ACL_USER "sys/acl.h" HAVE_DECL_ACL_USER) + + IF(HAVE_POSIX_ACL_FUNCS AND + HAVE_ACL_GET_FD_NP AND + HAVE_ACL_GET_PERM_NP AND + NOT HAVE_ACL_GET_PERM AND + HAVE_ACL_SET_FD_NP) + IF(HAVE_DECL_ACL_USER) + SET(ARCHIVE_ACL_FREEBSD TRUE) + IF(HAVE_DECL_ACL_TYPE_NFS4 AND + HAVE_ACL_ADD_FLAG_NP AND + HAVE_ACL_CLEAR_FLAGS_NP AND + HAVE_ACL_GET_BRAND_NP AND + HAVE_ACL_GET_ENTRY_TYPE_NP AND + HAVE_ACL_GET_FLAGSET_NP AND + HAVE_ACL_SET_ENTRY_TYPE_NP) + SET(ARCHIVE_ACL_FREEBSD_NFS4 TRUE) + ENDIF() + ELSEIF(HAVE_DECL_ACL_TYPE_EXTENDED AND + HAVE_MEMBERSHIP_H AND + HAVE_ACL_ADD_FLAG_NP AND + HAVE_ACL_CLEAR_FLAGS_NP AND + HAVE_ACL_GET_FLAGSET_NP AND + HAVE_ACL_GET_LINK_NP AND + HAVE_ACL_SET_LINK_NP AND + HAVE_MBR_UID_TO_UUID AND + HAVE_MBR_GID_TO_UUID AND + HAVE_MBR_UUID_TO_ID) + SET(ARCHIVE_ACL_DARWIN TRUE) + ENDIF() + ENDIF() + ENDIF() + ENDIF(HAVE_ACL_T AND HAVE_ACL_ENTRY_T AND HAVE_ACL_PERMSET_T AND + HAVE_ACL_TAG_T) + + # Richacl + CHECK_LIBRARY_EXISTS(richacl "richacl_get_file" "" HAVE_LIBRICHACL) + IF(HAVE_LIBRICHACL) + SET(CMAKE_REQUIRED_LIBRARIES "richacl") + FIND_LIBRARY(RICHACL_LIBRARY NAMES richacl) + LIST(APPEND ADDITIONAL_LIBS ${RICHACL_LIBRARY}) + ENDIF(HAVE_LIBRICHACL) + + CHECK_STRUCT_HAS_MEMBER("struct richace" e_type "sys/richacl.h" + HAVE_STRUCT_RICHACE) + CHECK_STRUCT_HAS_MEMBER("struct richacl" a_flags "sys/richacl.h" + HAVE_STRUCT_RICHACL) + + IF(HAVE_LIBRICHACL AND HAVE_STRUCT_RICHACL AND HAVE_STRUCT_RICHACE) + CHECK_FUNCTION_EXISTS_GLIBC(richacl_alloc HAVE_RICHACL_ALLOC) + CHECK_FUNCTION_EXISTS_GLIBC(richacl_equiv_mode HAVE_RICHACL_EQUIV_MODE) + CHECK_FUNCTION_EXISTS_GLIBC(richacl_free HAVE_RICHACL_FREE) + CHECK_FUNCTION_EXISTS_GLIBC(richacl_get_fd HAVE_RICHACL_GET_FD) + CHECK_FUNCTION_EXISTS_GLIBC(richacl_get_file HAVE_RICHACL_GET_FILE) + CHECK_FUNCTION_EXISTS_GLIBC(richacl_set_fd HAVE_RICHACL_SET_FD) + CHECK_FUNCTION_EXISTS_GLIBC(richacl_set_file HAVE_RICHACL_SET_FILE) + IF(HAVE_RICHACL_ALLOC AND + HAVE_RICHACL_EQUIV_MODE AND + HAVE_RICHACL_FREE AND + HAVE_RICHACL_GET_FD AND + HAVE_RICHACL_GET_FILE AND + HAVE_RICHACL_SET_FD AND + HAVE_RICHACL_SET_FILE) + SET(ARCHIVE_ACL_LIBRICHACL TRUE) + ENDIF() + ENDIF(HAVE_LIBRICHACL AND HAVE_STRUCT_RICHACL AND HAVE_STRUCT_RICHACE) + + IF(ARCHIVE_ACL_DARWIN) + MESSAGE(STATUS "ACL support: Darwin (limited NFSv4)") + ELSEIF(ARCHIVE_ACL_FREEBSD_NFS4) + MESSAGE(STATUS "ACL support: FreeBSD (POSIX.1e and NFSv4)") + ELSEIF(ARCHIVE_ACL_FREEBSD) + MESSAGE(STATUS "ACL support: FreeBSD (POSIX.1e)") + ELSEIF(ARCHIVE_ACL_LIBACL OR ARCHIVE_ACL_LIBRICHACL) + IF(ARCHIVE_ACL_LIBACL AND ARCHIVE_ACL_LIBRICHACL) + MESSAGE(STATUS "ACL support: libacl (POSIX.1e) + librichacl (NFSv4)") + ELSEIF(ARCHIVE_ACL_LIBRICHACL) + MESSAGE(STATUS "ACL support: librichacl (NFSv4)") + ELSE() + MESSAGE(STATUS "ACL support: libacl (POSIX.1e)") + ENDIF() + ELSEIF(ARCHIVE_ACL_SUNOS_NFS4) + MESSAGE(STATUS "ACL support: Solaris (POSIX.1e and NFSv4)") + ELSEIF(ARCHIVE_ACL_SUNOS) + MESSAGE(STATUS "ACL support: Solaris (POSIX.1e)") + ELSE() + MESSAGE(STATUS "ACL support: none") + ENDIF() - # Solaris and derivates ACLs - CHECK_LIBRARY_EXISTS(sec "acl_get" "" HAVE_LIBSEC) - IF(HAVE_LIBSEC) - SET(CMAKE_REQUIRED_LIBRARIES "sec") - FIND_LIBRARY(SEC_LIBRARY NAMES sec) - LIST(APPEND ADDITIONAL_LIBS ${SEC_LIBRARY}) - ENDIF(HAVE_LIBSEC) - # - CHECK_TYPE_EXISTS(aclent_t "${INCLUDES}" HAVE_ACLENT_T) - CHECK_TYPE_EXISTS(ace_t "${INCLUDES}" HAVE_ACE_T) - CHECK_FUNCTION_EXISTS(acl_get HAVE_FACL_GET) - CHECK_FUNCTION_EXISTS(facl_get HAVE_FACL_GET) - CHECK_FUNCTION_EXISTS(acl_set HAVE_FACL_SET) - CHECK_FUNCTION_EXISTS(facl_set HAVE_FACL_SET) ELSE(ENABLE_ACL) # If someone runs cmake, then disables ACL support, we need # to forcibly override the cached values for these. - SET(HAVE_ACL_CREATE_ENTRY FALSE) - SET(HAVE_ACL_GET_LINK FALSE) - SET(HAVE_ACL_GET_LINK_NP FALSE) - SET(HAVE_ACL_GET_PERM FALSE) - SET(HAVE_ACL_GET_PERM_NP FALSE) - SET(HAVE_ACL_INIT FALSE) - SET(HAVE_ACL_LIB FALSE) - SET(HAVE_ACL_PERMSET_T FALSE) - SET(HAVE_ACL_SET_FD FALSE) - SET(HAVE_ACL_SET_FD_NP FALSE) - SET(HAVE_ACL_SET_FILE FALSE) - SET(HAVE_ACL_TYPE_NFS4 FALSE) - SET(HAVE_ACL_USER FALSE) - SET(HAVE_ACL_TYPE_EXTENDED FALSE) - SET(HAVE_ACL_GET FALSE) - SET(HAVE_ACLENT_T FALSE) - SET(HAVE_ACE_T FALSE) - SET(HAVE_FACL_GET FALSE) - SET(HAVE_ACL_SET FALSE) - SET(HAVE_FACL_SET FALSE) + SET(ARCHIVE_ACL_DARWIN FALSE) + SET(ARCHIVE_ACL_FREEBSD FALSE) + SET(ARCHIVE_ACL_FREEBSD_NFS4 FALSE) + SET(ARCHIVE_ACL_LIBACL FALSE) + SET(ARCHIVE_ACL_SUNOS FALSE) + SET(ARCHIVE_ACL_SUNOS_NFS4 FALSE) ENDIF(ENABLE_ACL) # diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in index 923a78e..e646213 100644 --- a/build/cmake/config.h.in +++ b/build/cmake/config.h.in @@ -179,6 +179,27 @@ typedef uint64_t uintmax_t; /* Define ZLIB_WINAPI if zlib was built on Visual Studio. */ #cmakedefine ZLIB_WINAPI 1 +/* Darwin ACL support */ +#cmakedefine ARCHIVE_ACL_DARWIN 1 + +/* FreeBSD ACL support */ +#cmakedefine ARCHIVE_ACL_FREEBSD 1 + +/* FreeBSD NFSv4 ACL support */ +#cmakedefine ARCHIVE_ACL_FREEBSD_NFS4 1 + +/* Linux POSIX.1e ACL support via libacl */ +#cmakedefine ARCHIVE_ACL_LIBACL 1 + +/* Linux NFSv4 ACL support via librichacl */ +#cmakedefine ARCHIVE_ACL_LIBRICHACL 1 + +/* Solaris ACL support */ +#cmakedefine ARCHIVE_ACL_SUNOS 1 + +/* Solaris NFSv4 ACL support */ +#cmakedefine ARCHIVE_ACL_SUNOS_NFS4 1 + /* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */ #cmakedefine ARCHIVE_CRYPTO_MD5_LIBC 1 @@ -281,6 +302,18 @@ typedef uint64_t uintmax_t; /* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */ #cmakedefine ARCHIVE_CRYPTO_SHA512_WIN 1 +/* AIX xattr support */ +#cmakedefine ARCHIVE_XATTR_AIX 1 + +/* Darwin xattr support */ +#cmakedefine ARCHIVE_XATTR_DARWIN 1 + +/* FreeBSD xattr support */ +#cmakedefine ARCHIVE_XATTR_FREEBSD 1 + +/* Linux xattr support */ +#cmakedefine ARCHIVE_XATTR_LINUX 1 + /* Version number of bsdcpio */ #cmakedefine BSDCPIO_VERSION_STRING "${BSDCPIO_VERSION_STRING}" @@ -326,15 +359,6 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `acl_set_file' function. */ #cmakedefine HAVE_ACL_SET_FILE 1 -/* True for FreeBSD with NFSv4 ACL support */ -#cmakedefine HAVE_ACL_TYPE_NFS4 1 - -/* True for MacOS ACL support */ -#cmakedefine HAVE_ACL_TYPE_EXTENDED 1 - -/* True for systems with POSIX ACL support */ -#cmakedefine HAVE_ACL_USER 1 - /* Define to 1 if you have the `arc4random_buf' function. */ #cmakedefine HAVE_ARC4RANDOM_BUF 1 @@ -371,6 +395,34 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `cygwin_conv_path' function. */ #cmakedefine HAVE_CYGWIN_CONV_PATH 1 +/* Define to 1 if you have the declaration of `ACE_GETACL', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_ACE_GETACL 1 + +/* Define to 1 if you have the declaration of `ACE_GETACLCNT', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_ACE_GETACLCNT 1 + +/* Define to 1 if you have the declaration of `ACE_SETACL', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_ACE_SETACL 1 + +/* Define to 1 if you have the declaration of `ACL_SYNCHRONIZE', and to 0 if + you don't. */ +#cmakedefine HAVE_DECL_ACL_SYNCHRONIZE 1 + +/* Define to 1 if you have the declaration of `ACL_TYPE_EXTENDED', and to 0 if + you don't. */ +#cmakedefine HAVE_DECL_ACL_TYPE_EXTENDED 1 + +/* Define to 1 if you have the declaration of `ACL_TYPE_NFS4', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_ACL_TYPE_NFS4 1 + +/* Define to 1 if you have the declaration of `ACL_USER', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_ACL_USER 1 + /* Define to 1 if you have the declaration of `INT32_MAX', and to 0 if you don't. */ #cmakedefine HAVE_DECL_INT32_MAX 1 @@ -395,6 +447,10 @@ typedef uint64_t uintmax_t; don't. */ #cmakedefine HAVE_DECL_INTMAX_MIN 1 +/* Define to 1 if you have the declaration of `SETACL', and to 0 if you don't. + */ +#cmakedefine HAVE_DECL_SETACL 1 + /* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you don't. */ #cmakedefine HAVE_DECL_SIZE_MAX 1 @@ -419,6 +475,10 @@ typedef uint64_t uintmax_t; don't. */ #cmakedefine HAVE_DECL_UINTMAX_MAX 1 +/* Define to 1 if you have the declaration of `XATTR_NOFOLLOW', and to 0 if + you don't. */ +#cmakedefine HAVE_DECL_XATTR_NOFOLLOW 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DIRECT_H 1 @@ -468,6 +528,14 @@ typedef uint64_t uintmax_t; /* Define to 1 if EXTATTR_NAMESPACE_USER is defined in sys/extattr.h. */ #cmakedefine HAVE_DECL_EXTATTR_NAMESPACE_USER 1 +/* Define to 1 if you have the declaration of `GETACL', and to 0 if you don't. + */ +#cmakedefine HAVE_DECL_GETACL 1 + +/* Define to 1 if you have the declaration of `GETACLCNT', and to 0 if you + don't. */ +#cmakedefine HAVE_DECL_GETACLCNT 1 + /* Define to 1 if you have the `fchdir' function. */ #cmakedefine HAVE_FCHDIR 1 @@ -742,6 +810,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the `mbrtowc' function. */ #cmakedefine HAVE_MBRTOWC 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMBERSHIP_H 1 + /* Define to 1 if you have the `memmove' function. */ #cmakedefine HAVE_MEMMOVE 1 @@ -979,6 +1050,9 @@ typedef uint64_t uintmax_t; /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_POLL_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_RICHACL_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SELECT_H 1 diff --git a/build/version b/build/version index ef83457..2dd0839 100644 --- a/build/version +++ b/build/version @@ -1 +1 @@ -3003001 +3003002 diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt index 1f85c01..5e958da 100644 --- a/libarchive/CMakeLists.txt +++ b/libarchive/CMakeLists.txt @@ -14,6 +14,7 @@ SET(include_HEADERS # Sources and private headers SET(libarchive_SOURCES archive_acl.c + archive_acl_private.h archive_check_magic.c archive_cmdline.c archive_cmdline_private.h @@ -47,6 +48,8 @@ SET(libarchive_SOURCES archive_pathmatch.c archive_pathmatch.h archive_platform.h + archive_platform_acl.h + archive_platform_xattr.h archive_ppmd_private.h archive_ppmd7.c archive_ppmd7_private.h @@ -106,9 +109,9 @@ SET(libarchive_SOURCES archive_string_composition.h archive_string_sprintf.c archive_util.c + archive_version_details.c archive_virtual.c archive_write.c - archive_write_disk_acl.c archive_write_disk_posix.c archive_write_disk_private.h archive_write_disk_set_standard_lookup.c @@ -210,6 +213,16 @@ IF(WIN32 AND NOT CYGWIN) LIST(APPEND libarchive_SOURCES filter_fork_windows.c) ENDIF(WIN32 AND NOT CYGWIN) +IF(ARCHIVE_ACL_DARWIN) + LIST(APPEND libarchive_SOURCES archive_disk_acl_darwin.c) +ELSEIF(ARCHIVE_ACL_FREEBSD) + LIST(APPEND libarchive_SOURCES archive_disk_acl_freebsd.c) +ELSEIF(ARCHIVE_ACL_LIBACL) + LIST(APPEND libarchive_SOURCES archive_disk_acl_linux.c) +ELSEIF(ARCHIVE_ACL_SUNOS) + LIST(APPEND libarchive_SOURCES archive_disk_acl_sunos.c) +ENDIF() + # Libarchive is a shared library ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS}) TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS}) diff --git a/libarchive/archive.h b/libarchive/archive.h index d400735..316a68a 100644 --- a/libarchive/archive.h +++ b/libarchive/archive.h @@ -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 3003001 +#define ARCHIVE_VERSION_NUMBER 3003002 #include #include /* for wchar_t */ @@ -155,7 +155,7 @@ __LA_DECL int archive_version_number(void); /* * Textual name/version of the library, useful for version displays. */ -#define ARCHIVE_VERSION_ONLY_STRING "3.3.1" +#define ARCHIVE_VERSION_ONLY_STRING "3.3.2" #define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING __LA_DECL const char * archive_version_string(void); diff --git a/libarchive/archive_check_magic.c b/libarchive/archive_check_magic.c index c695e58..288ce23 100644 --- a/libarchive/archive_check_magic.c +++ b/libarchive/archive_check_magic.c @@ -62,7 +62,7 @@ errmsg(const char *m) } } -static void +static __LA_DEAD void diediedie(void) { #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG) diff --git a/libarchive/archive_disk_acl_darwin.c b/libarchive/archive_disk_acl_darwin.c new file mode 100644 index 0000000..48ad016 --- /dev/null +++ b/libarchive/archive_disk_acl_darwin.c @@ -0,0 +1,559 @@ +/*- + * Copyright (c) 2017 Martin Matuska + * 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" + +#if ARCHIVE_ACL_DARWIN + +#ifdef HAVE_FCNTL_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_MEMBERSHIP_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_ACL_H +#define _ACL_PRIVATE /* For debugging */ +#include +#endif + +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_disk_private.h" +#include "archive_write_disk_private.h" + +typedef struct { + const int a_perm; /* Libarchive permission or flag */ + const int p_perm; /* Platform permission or flag */ +} acl_perm_map_t; + +static const acl_perm_map_t acl_nfs4_perm_map[] = { + {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER}, +#if HAVE_DECL_ACL_SYNCHRONIZE + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} +#endif +}; + +static const int acl_nfs4_perm_map_size = + (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0])); + +static const acl_perm_map_t acl_nfs4_flag_map[] = { + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}, + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT} +}; + +static const int acl_nfs4_flag_map_size = + (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0])); + +static int translate_guid(struct archive *a, acl_entry_t acl_entry, + int *ae_id, int *ae_tag, const char **ae_name) +{ + void *q; + uid_t ugid; + int r, idtype; + + q = acl_get_qualifier(acl_entry); + if (q == NULL) + return (1); + r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype); + if (r != 0) { + acl_free(q); + return (1); + } + if (idtype == ID_TYPE_UID) { + *ae_tag = ARCHIVE_ENTRY_ACL_USER; + *ae_id = ugid; + *ae_name = archive_read_disk_uname(a, *ae_id); + } else if (idtype == ID_TYPE_GID) { + *ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + *ae_id = ugid; + *ae_name = archive_read_disk_gname(a, *ae_id); + } else + r = 1; + + acl_free(q); + return (r); +} + +static void +add_trivial_nfs4_acl(struct archive_entry *entry) +{ + mode_t mode; + int i; + const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA; + const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA; + const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE; + const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE; + const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER; + + struct { + const int type; + const int tag; + int permset; + } tacl_entry[] = { + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset} + }; + + mode = archive_entry_mode(entry); + + /* Permissions for everyone@ */ + if (mode & 0004) + tacl_entry[5].permset |= rperm; + if (mode & 0002) + tacl_entry[5].permset |= wperm; + if (mode & 0001) + tacl_entry[5].permset |= eperm; + + /* Permissions for group@ */ + if (mode & 0040) + tacl_entry[4].permset |= rperm; + else if (mode & 0004) + tacl_entry[2].permset |= rperm; + if (mode & 0020) + tacl_entry[4].permset |= wperm; + else if (mode & 0002) + tacl_entry[2].permset |= wperm; + if (mode & 0010) + tacl_entry[4].permset |= eperm; + else if (mode & 0001) + tacl_entry[2].permset |= eperm; + + /* Permissions for owner@ */ + if (mode & 0400) { + tacl_entry[3].permset |= rperm; + if (!(mode & 0040) && (mode & 0004)) + tacl_entry[0].permset |= rperm; + } else if ((mode & 0040) || (mode & 0004)) + tacl_entry[1].permset |= rperm; + if (mode & 0200) { + tacl_entry[3].permset |= wperm; + if (!(mode & 0020) && (mode & 0002)) + tacl_entry[0].permset |= wperm; + } else if ((mode & 0020) || (mode & 0002)) + tacl_entry[1].permset |= wperm; + if (mode & 0100) { + tacl_entry[3].permset |= eperm; + if (!(mode & 0010) && (mode & 0001)) + tacl_entry[0].permset |= eperm; + } else if ((mode & 0010) || (mode & 0001)) + tacl_entry[1].permset |= eperm; + + for (i = 0; i < 6; i++) { + if (tacl_entry[i].permset != 0) { + archive_entry_acl_add_entry(entry, + tacl_entry[i].type, tacl_entry[i].permset, + tacl_entry[i].tag, -1, NULL); + } + } + + return; +} + +static int +translate_acl(struct archive_read_disk *a, + struct archive_entry *entry, acl_t acl) +{ + acl_tag_t acl_tag; + acl_flagset_t acl_flagset; + acl_entry_t acl_entry; + acl_permset_t acl_permset; + int i, entry_acl_type; + int r, s, ae_id, ae_tag, ae_perm; + const char *ae_name; + + s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get first ACL entry"); + return (ARCHIVE_WARN); + } + + while (s == 0) { + ae_id = -1; + ae_name = NULL; + ae_perm = 0; + + if (acl_get_tag_type(acl_entry, &acl_tag) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get ACL tag type"); + return (ARCHIVE_WARN); + } + switch (acl_tag) { + case ACL_EXTENDED_ALLOW: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + r = translate_guid(&a->archive, acl_entry, + &ae_id, &ae_tag, &ae_name); + break; + case ACL_EXTENDED_DENY: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + r = translate_guid(&a->archive, acl_entry, + &ae_id, &ae_tag, &ae_name); + break; + default: + /* Skip types that libarchive can't support. */ + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + continue; + } + + /* Skip if translate_guid() above failed */ + if (r != 0) { + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + continue; + } + + /* + * Libarchive stores "flag" (NFSv4 inheritance bits) + * in the ae_perm bitmap. + * + * acl_get_flagset_np() fails with non-NFSv4 ACLs + */ + if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get flagset from a NFSv4 ACL entry"); + return (ARCHIVE_WARN); + } + for (i = 0; i < acl_nfs4_flag_map_size; ++i) { + r = acl_get_flag_np(acl_flagset, + acl_nfs4_flag_map[i].p_perm); + if (r == -1) { + archive_set_error(&a->archive, errno, + "Failed to check flag in a NFSv4 " + "ACL flagset"); + return (ARCHIVE_WARN); + } else if (r) + ae_perm |= acl_nfs4_flag_map[i].a_perm; + } + + if (acl_get_permset(acl_entry, &acl_permset) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get ACL permission set"); + return (ARCHIVE_WARN); + } + + for (i = 0; i < acl_nfs4_perm_map_size; ++i) { + /* + * acl_get_perm() is spelled differently on different + * platforms; see above. + */ + r = acl_get_perm_np(acl_permset, + acl_nfs4_perm_map[i].p_perm); + if (r == -1) { + archive_set_error(&a->archive, errno, + "Failed to check permission in an ACL " + "permission set"); + return (ARCHIVE_WARN); + } else if (r) + ae_perm |= acl_nfs4_perm_map[i].a_perm; + } + +#if !HAVE_DECL_ACL_SYNCHRONIZE + /* On Mac OS X without ACL_SYNCHRONIZE assume it is set */ + ae_perm |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; +#endif + + archive_entry_acl_add_entry(entry, entry_acl_type, + ae_perm, ae_tag, + ae_id, ae_name); + + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + } + return (ARCHIVE_OK); +} + +static int +set_acl(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, + int ae_requested_type, const char *tname) +{ + acl_t acl; + acl_entry_t acl_entry; + acl_permset_t acl_permset; + acl_flagset_t acl_flagset; + int ret; + int ae_type, ae_permset, ae_tag, ae_id; + uuid_t ae_uuid; + uid_t ae_uid; + gid_t ae_gid; + const char *ae_name; + int entries; + int i; + + ret = ARCHIVE_OK; + entries = archive_acl_reset(abstract_acl, ae_requested_type); + if (entries == 0) + return (ARCHIVE_OK); + + if (ae_requested_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + errno = ENOENT; + archive_set_error(a, errno, "Unsupported ACL type"); + return (ARCHIVE_FAILED); + } + + acl = acl_init(entries); + if (acl == (acl_t)NULL) { + archive_set_error(a, errno, + "Failed to initialize ACL working storage"); + return (ARCHIVE_FAILED); + } + + while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, + &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { + /* + * Mac OS doesn't support NFSv4 ACLs for + * owner@, group@ and everyone@. + * We skip any of these ACLs found. + */ + if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ || + ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ || + ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE) + continue; + + if (acl_create_entry(&acl, &acl_entry) != 0) { + archive_set_error(a, errno, + "Failed to create a new ACL entry"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + switch (ae_type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW); + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY); + break; + default: + /* We don't support any other types on MacOS */ + continue; + } + + switch (ae_tag) { + case ARCHIVE_ENTRY_ACL_USER: + ae_uid = archive_write_disk_uid(a, ae_name, ae_id); + if (mbr_uid_to_uuid(ae_uid, ae_uuid) != 0) + continue; + if (acl_set_qualifier(acl_entry, &ae_uuid) != 0) + continue; + break; + case ARCHIVE_ENTRY_ACL_GROUP: + ae_gid = archive_write_disk_gid(a, ae_name, ae_id); + if (mbr_gid_to_uuid(ae_gid, ae_uuid) != 0) + continue; + if (acl_set_qualifier(acl_entry, &ae_uuid) != 0) + continue; + break; + default: + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unsupported ACL tag"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + if (acl_get_permset(acl_entry, &acl_permset) != 0) { + archive_set_error(a, errno, + "Failed to get ACL permission set"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + if (acl_clear_perms(acl_permset) != 0) { + archive_set_error(a, errno, + "Failed to clear ACL permissions"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + for (i = 0; i < acl_nfs4_perm_map_size; ++i) { + if (ae_permset & acl_nfs4_perm_map[i].a_perm) { + if (acl_add_perm(acl_permset, + acl_nfs4_perm_map[i].p_perm) != 0) { + archive_set_error(a, errno, + "Failed to add ACL permission"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + } + } + + /* + * acl_get_flagset_np() fails with non-NFSv4 ACLs + */ + if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { + archive_set_error(a, errno, + "Failed to get flagset from an NFSv4 ACL entry"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + if (acl_clear_flags_np(acl_flagset) != 0) { + archive_set_error(a, errno, + "Failed to clear flags from an NFSv4 ACL flagset"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + for (i = 0; i < acl_nfs4_flag_map_size; ++i) { + if (ae_permset & acl_nfs4_flag_map[i].a_perm) { + if (acl_add_flag_np(acl_flagset, + acl_nfs4_flag_map[i].p_perm) != 0) { + archive_set_error(a, errno, + "Failed to add flag to " + "NFSv4 ACL flagset"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + } + } + } + + if (fd >= 0) { + if (acl_set_fd_np(fd, acl, ACL_TYPE_EXTENDED) == 0) + ret = ARCHIVE_OK; + else { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, + "Failed to set acl on fd: %s", tname); + ret = ARCHIVE_WARN; + } + } + } else if (acl_set_link_np(name, ACL_TYPE_EXTENDED, acl) != 0) { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, "Failed to set acl: %s", + tname); + ret = ARCHIVE_WARN; + } + } +exit_free: + acl_free(acl); + return (ret); +} + +int +archive_read_disk_entry_setup_acls(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + const char *accpath; + acl_t acl; + int r; + + accpath = NULL; + + if (*fd < 0) { + accpath = archive_read_disk_entry_setup_path(a, entry, fd); + if (accpath == NULL) + return (ARCHIVE_WARN); + } + + archive_entry_acl_clear(entry); + + acl = NULL; + + if (*fd >= 0) + acl = acl_get_fd_np(*fd, ACL_TYPE_EXTENDED); + else if (!a->follow_symlinks) + acl = acl_get_link_np(accpath, ACL_TYPE_EXTENDED); + else + acl = acl_get_file(accpath, ACL_TYPE_EXTENDED); + + if (acl != NULL) { + r = translate_acl(a, entry, acl); + acl_free(acl); + acl = NULL; + + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate NFSv4 ACLs"); + } + + /* + * Because Mac OS doesn't support owner@, group@ and everyone@ + * ACLs we need to add NFSv4 ACLs mirroring the file mode to + * the archive entry. Otherwise extraction on non-Mac platforms + * would lead to an invalid file mode. + */ + if ((archive_entry_acl_types(entry) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) + add_trivial_nfs4_acl(entry); + + return (r); + } + return (ARCHIVE_OK); +} + +int +archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, __LA_MODE_T mode) +{ + int ret = ARCHIVE_OK; + + (void)mode; /* UNUSED */ + + if ((archive_acl_types(abstract_acl) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + ret = set_acl(a, fd, name, abstract_acl, + ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); + } + return (ret); +} +#endif /* ARCHIVE_ACL_DARWIN */ diff --git a/libarchive/archive_disk_acl_freebsd.c b/libarchive/archive_disk_acl_freebsd.c new file mode 100644 index 0000000..07d08ff --- /dev/null +++ b/libarchive/archive_disk_acl_freebsd.c @@ -0,0 +1,700 @@ +/*- + * Copyright (c) 2003-2009 Tim Kientzle + * Copyright (c) 2010-2012 Michihiro NAKAJIMA + * Copyright (c) 2017 Martin Matuska + * 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" + +#if ARCHIVE_ACL_FREEBSD + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_ACL_H +#define _ACL_PRIVATE /* For debugging */ +#include +#endif + +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_disk_private.h" +#include "archive_write_disk_private.h" + +typedef struct { + const int a_perm; /* Libarchive permission or flag */ + const int p_perm; /* Platform permission or flag */ +} acl_perm_map_t; + +static const acl_perm_map_t acl_posix_perm_map[] = { + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, + {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, +}; + +static const int acl_posix_perm_map_size = + (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0])); + +#if ARCHIVE_ACL_FREEBSD_NFS4 +static const acl_perm_map_t acl_nfs4_perm_map[] = { + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} +}; + +static const int acl_nfs4_perm_map_size = + (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0])); + +static const acl_perm_map_t acl_nfs4_flag_map[] = { + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}, + {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS}, + {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED} +}; + +static const int acl_nfs4_flag_map_size = + (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0])); +#endif /* ARCHIVE_ACL_FREEBSD_NFS4 */ + +static int +translate_acl(struct archive_read_disk *a, + struct archive_entry *entry, acl_t acl, int default_entry_acl_type) +{ +#if ARCHIVE_ACL_FREEBSD_NFS4 + int brand; + acl_flagset_t acl_flagset; + acl_entry_type_t acl_type; +#endif + acl_tag_t acl_tag; + acl_entry_t acl_entry; + acl_permset_t acl_permset; + int i, entry_acl_type, perm_map_size; + const acl_perm_map_t *perm_map; + int r, s, ae_id, ae_tag, ae_perm; + void *q; + const char *ae_name; + +#if ARCHIVE_ACL_FREEBSD_NFS4 + // FreeBSD "brands" ACLs as POSIX.1e or NFSv4 + // Make sure the "brand" on this ACL is consistent + // with the default_entry_acl_type bits provided. + if (acl_get_brand_np(acl, &brand) != 0) { + archive_set_error(&a->archive, errno, + "Failed to read ACL brand"); + return (ARCHIVE_WARN); + } + switch (brand) { + case ACL_BRAND_POSIX: + switch (default_entry_acl_type) { + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Invalid ACL entry type for POSIX.1e ACL"); + return (ARCHIVE_WARN); + } + break; + case ACL_BRAND_NFS4: + if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Invalid ACL entry type for NFSv4 ACL"); + return (ARCHIVE_WARN); + } + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Unknown ACL brand"); + return (ARCHIVE_WARN); + } +#endif + + s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get first ACL entry"); + return (ARCHIVE_WARN); + } + + while (s == 1) { + ae_id = -1; + ae_name = NULL; + ae_perm = 0; + + if (acl_get_tag_type(acl_entry, &acl_tag) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get ACL tag type"); + return (ARCHIVE_WARN); + } + switch (acl_tag) { + case ACL_USER: + q = acl_get_qualifier(acl_entry); + if (q != NULL) { + ae_id = (int)*(uid_t *)q; + acl_free(q); + ae_name = archive_read_disk_uname(&a->archive, + ae_id); + } + ae_tag = ARCHIVE_ENTRY_ACL_USER; + break; + case ACL_GROUP: + q = acl_get_qualifier(acl_entry); + if (q != NULL) { + ae_id = (int)*(gid_t *)q; + acl_free(q); + ae_name = archive_read_disk_gname(&a->archive, + ae_id); + } + ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + break; + case ACL_MASK: + ae_tag = ARCHIVE_ENTRY_ACL_MASK; + break; + case ACL_USER_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case ACL_GROUP_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case ACL_OTHER: + ae_tag = ARCHIVE_ENTRY_ACL_OTHER; + break; +#if ARCHIVE_ACL_FREEBSD_NFS4 + case ACL_EVERYONE: + ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; + break; +#endif + default: + /* Skip types that libarchive can't support. */ + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + continue; + } + + // XXX acl_type maps to allow/deny/audit/YYYY bits + entry_acl_type = default_entry_acl_type; + +#if ARCHIVE_ACL_FREEBSD_NFS4 + if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + /* + * acl_get_entry_type_np() fails with non-NFSv4 ACLs + */ + if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) { + archive_set_error(&a->archive, errno, "Failed " + "to get ACL type from a NFSv4 ACL entry"); + return (ARCHIVE_WARN); + } + switch (acl_type) { + case ACL_ENTRY_TYPE_ALLOW: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + break; + case ACL_ENTRY_TYPE_DENY: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + break; + case ACL_ENTRY_TYPE_AUDIT: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; + break; + case ACL_ENTRY_TYPE_ALARM: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; + break; + default: + archive_set_error(&a->archive, errno, + "Invalid NFSv4 ACL entry type"); + return (ARCHIVE_WARN); + } + + /* + * Libarchive stores "flag" (NFSv4 inheritance bits) + * in the ae_perm bitmap. + * + * acl_get_flagset_np() fails with non-NFSv4 ACLs + */ + if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get flagset from a NFSv4 " + "ACL entry"); + return (ARCHIVE_WARN); + } + for (i = 0; i < acl_nfs4_flag_map_size; ++i) { + r = acl_get_flag_np(acl_flagset, + acl_nfs4_flag_map[i].p_perm); + if (r == -1) { + archive_set_error(&a->archive, errno, + "Failed to check flag in a NFSv4 " + "ACL flagset"); + return (ARCHIVE_WARN); + } else if (r) + ae_perm |= acl_nfs4_flag_map[i].a_perm; + } + } +#endif + + if (acl_get_permset(acl_entry, &acl_permset) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get ACL permission set"); + return (ARCHIVE_WARN); + } + +#if ARCHIVE_ACL_FREEBSD_NFS4 + if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + perm_map_size = acl_nfs4_perm_map_size; + perm_map = acl_nfs4_perm_map; + } else { +#endif + perm_map_size = acl_posix_perm_map_size; + perm_map = acl_posix_perm_map; +#if ARCHIVE_ACL_FREEBSD_NFS4 + } +#endif + + for (i = 0; i < perm_map_size; ++i) { + r = acl_get_perm_np(acl_permset, perm_map[i].p_perm); + if (r == -1) { + archive_set_error(&a->archive, errno, + "Failed to check permission in an ACL " + "permission set"); + return (ARCHIVE_WARN); + } else if (r) + ae_perm |= perm_map[i].a_perm; + } + + archive_entry_acl_add_entry(entry, entry_acl_type, + ae_perm, ae_tag, + ae_id, ae_name); + + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get next ACL entry"); + return (ARCHIVE_WARN); + } + } + return (ARCHIVE_OK); +} + +static int +set_acl(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, + int ae_requested_type, const char *tname) +{ + int acl_type = 0; + acl_t acl; + acl_entry_t acl_entry; + acl_permset_t acl_permset; +#if ARCHIVE_ACL_FREEBSD_NFS4 + acl_flagset_t acl_flagset; + int r; +#endif + int ret; + int ae_type, ae_permset, ae_tag, ae_id; + int perm_map_size; + const acl_perm_map_t *perm_map; + uid_t ae_uid; + gid_t ae_gid; + const char *ae_name; + int entries; + int i; + + ret = ARCHIVE_OK; + entries = archive_acl_reset(abstract_acl, ae_requested_type); + if (entries == 0) + return (ARCHIVE_OK); + + + switch (ae_requested_type) { + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + acl_type = ACL_TYPE_ACCESS; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + acl_type = ACL_TYPE_DEFAULT; + break; +#if ARCHIVE_ACL_FREEBSD_NFS4 + case ARCHIVE_ENTRY_ACL_TYPE_NFS4: + acl_type = ACL_TYPE_NFS4; + break; +#endif + default: + errno = ENOENT; + archive_set_error(a, errno, "Unsupported ACL type"); + return (ARCHIVE_FAILED); + } + + acl = acl_init(entries); + if (acl == (acl_t)NULL) { + archive_set_error(a, errno, + "Failed to initialize ACL working storage"); + return (ARCHIVE_FAILED); + } + + while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, + &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { + if (acl_create_entry(&acl, &acl_entry) != 0) { + archive_set_error(a, errno, + "Failed to create a new ACL entry"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + switch (ae_tag) { + case ARCHIVE_ENTRY_ACL_USER: + ae_uid = archive_write_disk_uid(a, ae_name, ae_id); + acl_set_tag_type(acl_entry, ACL_USER); + acl_set_qualifier(acl_entry, &ae_uid); + break; + case ARCHIVE_ENTRY_ACL_GROUP: + ae_gid = archive_write_disk_gid(a, ae_name, ae_id); + acl_set_tag_type(acl_entry, ACL_GROUP); + acl_set_qualifier(acl_entry, &ae_gid); + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + acl_set_tag_type(acl_entry, ACL_USER_OBJ); + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + acl_set_tag_type(acl_entry, ACL_GROUP_OBJ); + break; + case ARCHIVE_ENTRY_ACL_MASK: + acl_set_tag_type(acl_entry, ACL_MASK); + break; + case ARCHIVE_ENTRY_ACL_OTHER: + acl_set_tag_type(acl_entry, ACL_OTHER); + break; +#if ARCHIVE_ACL_FREEBSD_NFS4 + case ARCHIVE_ENTRY_ACL_EVERYONE: + acl_set_tag_type(acl_entry, ACL_EVERYONE); + break; +#endif + default: + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unsupported ACL tag"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + +#if ARCHIVE_ACL_FREEBSD_NFS4 + r = 0; + switch (ae_type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + r = acl_set_entry_type_np(acl_entry, + ACL_ENTRY_TYPE_ALLOW); + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + r = acl_set_entry_type_np(acl_entry, + ACL_ENTRY_TYPE_DENY); + break; + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + r = acl_set_entry_type_np(acl_entry, + ACL_ENTRY_TYPE_AUDIT); + break; + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + r = acl_set_entry_type_np(acl_entry, + ACL_ENTRY_TYPE_ALARM); + break; + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + // These don't translate directly into the system ACL. + break; + default: + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unsupported ACL entry type"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + if (r != 0) { + archive_set_error(a, errno, + "Failed to set ACL entry type"); + ret = ARCHIVE_FAILED; + goto exit_free; + } +#endif + + if (acl_get_permset(acl_entry, &acl_permset) != 0) { + archive_set_error(a, errno, + "Failed to get ACL permission set"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + if (acl_clear_perms(acl_permset) != 0) { + archive_set_error(a, errno, + "Failed to clear ACL permissions"); + ret = ARCHIVE_FAILED; + goto exit_free; + } +#if ARCHIVE_ACL_FREEBSD_NFS4 + if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + perm_map_size = acl_nfs4_perm_map_size; + perm_map = acl_nfs4_perm_map; + } else { +#endif + perm_map_size = acl_posix_perm_map_size; + perm_map = acl_posix_perm_map; +#if ARCHIVE_ACL_FREEBSD_NFS4 + } +#endif + + for (i = 0; i < perm_map_size; ++i) { + if (ae_permset & perm_map[i].a_perm) { + if (acl_add_perm(acl_permset, + perm_map[i].p_perm) != 0) { + archive_set_error(a, errno, + "Failed to add ACL permission"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + } + } + +#if ARCHIVE_ACL_FREEBSD_NFS4 + if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + /* + * acl_get_flagset_np() fails with non-NFSv4 ACLs + */ + if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { + archive_set_error(a, errno, + "Failed to get flagset from an NFSv4 " + "ACL entry"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + if (acl_clear_flags_np(acl_flagset) != 0) { + archive_set_error(a, errno, + "Failed to clear flags from an NFSv4 " + "ACL flagset"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + for (i = 0; i < acl_nfs4_flag_map_size; ++i) { + if (ae_permset & acl_nfs4_flag_map[i].a_perm) { + if (acl_add_flag_np(acl_flagset, + acl_nfs4_flag_map[i].p_perm) != 0) { + archive_set_error(a, errno, + "Failed to add flag to " + "NFSv4 ACL flagset"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + } + } + } +#endif + } + + /* Try restoring the ACL through 'fd' if we can. */ + if (fd >= 0) { + if (acl_set_fd_np(fd, acl, acl_type) == 0) + ret = ARCHIVE_OK; + else { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, + "Failed to set acl on fd: %s", tname); + ret = ARCHIVE_WARN; + } + } + } +#if HAVE_ACL_SET_LINK_NP + 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) +#endif + { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, "Failed to set acl: %s", + tname); + ret = ARCHIVE_WARN; + } + } +exit_free: + acl_free(acl); + return (ret); +} + +int +archive_read_disk_entry_setup_acls(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + const char *accpath; + acl_t acl; + int r; + + accpath = NULL; + + if (*fd < 0) { + accpath = archive_read_disk_entry_setup_path(a, entry, fd); + if (accpath == NULL) + return (ARCHIVE_WARN); + } + + archive_entry_acl_clear(entry); + + acl = NULL; + +#if ARCHIVE_ACL_FREEBSD_NFS4 + /* Try NFSv4 ACL first. */ + if (*fd >= 0) + acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4); + else if (!a->follow_symlinks) + acl = acl_get_link_np(accpath, ACL_TYPE_NFS4); + else + acl = acl_get_file(accpath, ACL_TYPE_NFS4); + + /* Ignore "trivial" ACLs that just mirror the file mode. */ + if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) { + acl_free(acl); + acl = NULL; + return (ARCHIVE_OK); + } + + if (acl != NULL) { + r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4); + acl_free(acl); + acl = NULL; + + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate NFSv4 ACLs"); + } + + return (r); + } +#endif + + /* Retrieve access ACL from file. */ + if (*fd >= 0) + acl = acl_get_fd_np(*fd, ACL_TYPE_ACCESS); +#if HAVE_ACL_GET_LINK_NP + else if (!a->follow_symlinks) + acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS); +#else + else if ((!a->follow_symlinks) + && (archive_entry_filetype(entry) == AE_IFLNK)) + /* We can't get the ACL of a symlink, so we assume it can't + have one. */ + acl = NULL; +#endif + else + acl = acl_get_file(accpath, ACL_TYPE_ACCESS); + +#if HAVE_ACL_IS_TRIVIAL_NP + /* Ignore "trivial" ACLs that just mirror the file mode. */ + if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) { + acl_free(acl); + acl = NULL; + } +#endif + + if (acl != NULL) { + r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); + acl_free(acl); + acl = NULL; + + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate access ACLs"); + return (r); + } + } + + /* Only directories can have default ACLs. */ + if (S_ISDIR(archive_entry_mode(entry))) { + if (*fd >= 0) + acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT); + else + acl = acl_get_file(accpath, ACL_TYPE_DEFAULT); + if (acl != NULL) { + r = translate_acl(a, entry, acl, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); + acl_free(acl); + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate default ACLs"); + return (r); + } + } + } + return (ARCHIVE_OK); +} + +int +archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, __LA_MODE_T mode) +{ + int ret = ARCHIVE_OK; + + (void)mode; /* UNUSED */ + + if ((archive_acl_types(abstract_acl) + & 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, + 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, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); + + /* Simultaneous POSIX.1e and NFSv4 is not supported */ + return (ret); + } +#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, + ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); + } +#endif + return (ret); +} +#endif /* ARCHIVE_ACL_FREEBSD */ diff --git a/libarchive/archive_disk_acl_linux.c b/libarchive/archive_disk_acl_linux.c new file mode 100644 index 0000000..3928f3d --- /dev/null +++ b/libarchive/archive_disk_acl_linux.c @@ -0,0 +1,743 @@ +/*- + * Copyright (c) 2003-2009 Tim Kientzle + * Copyright (c) 2010-2012 Michihiro NAKAJIMA + * Copyright (c) 2017 Martin Matuska + * 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" + +#if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_LIBRICHACL + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#if HAVE_ACL_LIBACL_H +#include +#endif +#ifdef HAVE_SYS_ACL_H +#include +#endif +#ifdef HAVE_SYS_RICHACL_H +#include +#endif + +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_disk_private.h" +#include "archive_write_disk_private.h" + +typedef struct { + const int a_perm; /* Libarchive permission or flag */ + const int p_perm; /* Platform permission or flag */ +} acl_perm_map_t; + +#if ARCHIVE_ACL_LIBACL +static const acl_perm_map_t acl_posix_perm_map[] = { + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, + {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, +}; + +static const int acl_posix_perm_map_size = + (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0])); +#endif /* ARCHIVE_ACL_LIBACL */ + +#if ARCHIVE_ACL_LIBRICHACL +static const acl_perm_map_t acl_nfs4_perm_map[] = { + {ARCHIVE_ENTRY_ACL_EXECUTE, RICHACE_EXECUTE}, + {ARCHIVE_ENTRY_ACL_READ_DATA, RICHACE_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, RICHACE_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, RICHACE_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, RICHACE_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, RICHACE_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, RICHACE_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, RICHACE_READ_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, RICHACE_WRITE_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, RICHACE_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, RICHACE_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, RICHACE_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_DELETE, RICHACE_DELETE}, + {ARCHIVE_ENTRY_ACL_READ_ACL, RICHACE_READ_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, RICHACE_WRITE_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, RICHACE_WRITE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, RICHACE_SYNCHRONIZE} +}; + +static const int acl_nfs4_perm_map_size = + (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0])); + +static const acl_perm_map_t acl_nfs4_flag_map[] = { + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, RICHACE_FILE_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, RICHACE_DIRECTORY_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, RICHACE_NO_PROPAGATE_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, RICHACE_INHERIT_ONLY_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, RICHACE_INHERITED_ACE} +}; + +static const int acl_nfs4_flag_map_size = + (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0])); +#endif /* ARCHIVE_ACL_LIBRICHACL */ + +#if ARCHIVE_ACL_LIBACL +/* + * Translate POSIX.1e ACLs into libarchive internal structure + */ +static int +translate_acl(struct archive_read_disk *a, + struct archive_entry *entry, acl_t acl, int default_entry_acl_type) +{ + acl_tag_t acl_tag; + acl_entry_t acl_entry; + acl_permset_t acl_permset; + int i, entry_acl_type; + int r, s, ae_id, ae_tag, ae_perm; + void *q; + const char *ae_name; + + s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get first ACL entry"); + return (ARCHIVE_WARN); + } + + while (s == 1) { + ae_id = -1; + ae_name = NULL; + ae_perm = 0; + + if (acl_get_tag_type(acl_entry, &acl_tag) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get ACL tag type"); + return (ARCHIVE_WARN); + } + switch (acl_tag) { + case ACL_USER: + q = acl_get_qualifier(acl_entry); + if (q != NULL) { + ae_id = (int)*(uid_t *)q; + acl_free(q); + ae_name = archive_read_disk_uname(&a->archive, + ae_id); + } + ae_tag = ARCHIVE_ENTRY_ACL_USER; + break; + case ACL_GROUP: + q = acl_get_qualifier(acl_entry); + if (q != NULL) { + ae_id = (int)*(gid_t *)q; + acl_free(q); + ae_name = archive_read_disk_gname(&a->archive, + ae_id); + } + ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + break; + case ACL_MASK: + ae_tag = ARCHIVE_ENTRY_ACL_MASK; + break; + case ACL_USER_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case ACL_GROUP_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case ACL_OTHER: + ae_tag = ARCHIVE_ENTRY_ACL_OTHER; + break; + default: + /* Skip types that libarchive can't support. */ + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + continue; + } + + // XXX acl_type maps to allow/deny/audit/YYYY bits + entry_acl_type = default_entry_acl_type; + + if (acl_get_permset(acl_entry, &acl_permset) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get ACL permission set"); + return (ARCHIVE_WARN); + } + + for (i = 0; i < acl_posix_perm_map_size; ++i) { + r = acl_get_perm(acl_permset, + acl_posix_perm_map[i].p_perm); + if (r == -1) { + archive_set_error(&a->archive, errno, + "Failed to check permission in an ACL " + "permission set"); + return (ARCHIVE_WARN); + } else if (r) + ae_perm |= acl_posix_perm_map[i].a_perm; + } + + archive_entry_acl_add_entry(entry, entry_acl_type, + ae_perm, ae_tag, + ae_id, ae_name); + + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get next ACL entry"); + return (ARCHIVE_WARN); + } + } + return (ARCHIVE_OK); +} +#endif /* ARCHIVE_ACL_LIBACL */ + +#if ARCHIVE_ACL_LIBRICHACL +/* + * Translate RichACL into libarchive internal ACL + */ +static int +translate_richacl(struct archive_read_disk *a, struct archive_entry *entry, + struct richacl *richacl) +{ + int ae_id, ae_tag, ae_perm; + int entry_acl_type, i; + const char *ae_name; + + struct richace *richace; + + richacl_for_each_entry(richace, richacl) { + ae_name = NULL; + ae_tag = 0; + ae_perm = 0; + ae_id = -1; + + switch (richace->e_type) { + case RICHACE_ACCESS_ALLOWED_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + break; + case RICHACE_ACCESS_DENIED_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + break; + default: /* Unknown entry type, skip */ + continue; + } + + /* Unsupported */ + if (richace->e_flags & RICHACE_UNMAPPED_WHO) + continue; + + if (richace->e_flags & RICHACE_SPECIAL_WHO) { + switch (richace->e_id) { + case RICHACE_OWNER_SPECIAL_ID: + ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case RICHACE_GROUP_SPECIAL_ID: + ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case RICHACE_EVERYONE_SPECIAL_ID: + ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; + break; + default: /* Unknown special ID type */ + continue; + } + } else { + ae_id = richace->e_id; + if (richace->e_flags & RICHACE_IDENTIFIER_GROUP) { + ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + ae_name = archive_read_disk_gname(&a->archive, + (gid_t)(richace->e_id)); + } else { + ae_tag = ARCHIVE_ENTRY_ACL_USER; + ae_name = archive_read_disk_uname(&a->archive, + (uid_t)(richace->e_id)); + } + } + for (i = 0; i < acl_nfs4_flag_map_size; ++i) { + if ((richace->e_flags & + acl_nfs4_flag_map[i].p_perm) != 0) + ae_perm |= acl_nfs4_flag_map[i].a_perm; + } + for (i = 0; i < acl_nfs4_perm_map_size; ++i) { + if ((richace->e_mask & + acl_nfs4_perm_map[i].p_perm) != 0) + ae_perm |= + acl_nfs4_perm_map[i].a_perm; + } + + archive_entry_acl_add_entry(entry, entry_acl_type, + ae_perm, ae_tag, ae_id, ae_name); + } + return (ARCHIVE_OK); +} +#endif /* ARCHIVE_ACL_LIBRICHACL */ + +#if ARCHIVE_ACL_LIBRICHACL +static int +_richacl_mode_to_mask(short mode) +{ + int mask = 0; + + if (mode & S_IROTH) + mask |= RICHACE_POSIX_MODE_READ; + if (mode & S_IWOTH) + mask |= RICHACE_POSIX_MODE_WRITE; + if (mode & S_IXOTH) + mask |= RICHACE_POSIX_MODE_EXEC; + + return (mask); +} + +static void +_richacl_mode_to_masks(struct richacl *richacl, __LA_MODE_T mode) +{ + richacl->a_owner_mask = _richacl_mode_to_mask((mode & 0700) >> 6); + richacl->a_group_mask = _richacl_mode_to_mask((mode & 0070) >> 3); + richacl->a_other_mask = _richacl_mode_to_mask(mode & 0007); +} +#endif /* ARCHIVE_ACL_LIBRICHACL */ + +#if ARCHIVE_ACL_LIBRICHACL +static int +set_richacl(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, __LA_MODE_T mode, + int ae_requested_type, const char *tname) +{ + int ae_type, ae_permset, ae_tag, ae_id; + uid_t ae_uid; + gid_t ae_gid; + const char *ae_name; + int entries; + int i; + int ret; + int e = 0; + struct richacl *richacl = NULL; + struct richace *richace; + + ret = ARCHIVE_OK; + entries = archive_acl_reset(abstract_acl, ae_requested_type); + if (entries == 0) + return (ARCHIVE_OK); + + if (ae_requested_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + errno = ENOENT; + archive_set_error(a, errno, "Unsupported ACL type"); + return (ARCHIVE_FAILED); + } + + richacl = richacl_alloc(entries); + if (richacl == NULL) { + archive_set_error(a, errno, + "Failed to initialize RichACL working storage"); + return (ARCHIVE_FAILED); + } + + e = 0; + + while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, + &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { + richace = &(richacl->a_entries[e]); + + richace->e_flags = 0; + richace->e_mask = 0; + + switch (ae_tag) { + case ARCHIVE_ENTRY_ACL_USER: + ae_uid = archive_write_disk_uid(a, ae_name, ae_id); + richace->e_id = ae_uid; + break; + case ARCHIVE_ENTRY_ACL_GROUP: + ae_gid = archive_write_disk_gid(a, ae_name, ae_id); + richace->e_id = ae_gid; + richace->e_flags |= RICHACE_IDENTIFIER_GROUP; + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + richace->e_flags |= RICHACE_SPECIAL_WHO; + richace->e_id = RICHACE_OWNER_SPECIAL_ID; + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + richace->e_flags |= RICHACE_SPECIAL_WHO; + richace->e_id = RICHACE_GROUP_SPECIAL_ID; + break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + richace->e_flags |= RICHACE_SPECIAL_WHO; + richace->e_id = RICHACE_EVERYONE_SPECIAL_ID; + break; + default: + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unsupported ACL tag"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + switch (ae_type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + richace->e_type = + RICHACE_ACCESS_ALLOWED_ACE_TYPE; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + richace->e_type = + RICHACE_ACCESS_DENIED_ACE_TYPE; + break; + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + break; + default: + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unsupported ACL entry type"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + for (i = 0; i < acl_nfs4_perm_map_size; ++i) { + if (ae_permset & acl_nfs4_perm_map[i].a_perm) + richace->e_mask |= acl_nfs4_perm_map[i].p_perm; + } + + for (i = 0; i < acl_nfs4_flag_map_size; ++i) { + if (ae_permset & + acl_nfs4_flag_map[i].a_perm) + richace->e_flags |= acl_nfs4_flag_map[i].p_perm; + } + e++; + } + + /* Fill RichACL masks */ + _richacl_mode_to_masks(richacl, mode); + + if (fd >= 0) { + if (richacl_set_fd(fd, richacl) == 0) + ret = ARCHIVE_OK; + else { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, + "Failed to set richacl on fd: %s", tname); + ret = ARCHIVE_WARN; + } + } + } else if (richacl_set_file(name, richacl) != 0) { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, "Failed to set richacl: %s", + tname); + ret = ARCHIVE_WARN; + } + } +exit_free: + richacl_free(richacl); + return (ret); +} +#endif /* ARCHIVE_ACL_RICHACL */ + +#if ARCHIVE_ACL_LIBACL +static int +set_acl(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, + int ae_requested_type, const char *tname) +{ + int acl_type = 0; + int ae_type, ae_permset, ae_tag, ae_id; + uid_t ae_uid; + gid_t ae_gid; + const char *ae_name; + int entries; + int i; + int ret; + acl_t acl = NULL; + acl_entry_t acl_entry; + acl_permset_t acl_permset; + + ret = ARCHIVE_OK; + entries = archive_acl_reset(abstract_acl, ae_requested_type); + if (entries == 0) + return (ARCHIVE_OK); + + switch (ae_requested_type) { + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + acl_type = ACL_TYPE_ACCESS; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + acl_type = ACL_TYPE_DEFAULT; + break; + default: + errno = ENOENT; + archive_set_error(a, errno, "Unsupported ACL type"); + return (ARCHIVE_FAILED); + } + + acl = acl_init(entries); + if (acl == (acl_t)NULL) { + archive_set_error(a, errno, + "Failed to initialize ACL working storage"); + return (ARCHIVE_FAILED); + } + + while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, + &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { + + if (acl_create_entry(&acl, &acl_entry) != 0) { + archive_set_error(a, errno, + "Failed to create a new ACL entry"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + switch (ae_tag) { + case ARCHIVE_ENTRY_ACL_USER: + ae_uid = archive_write_disk_uid(a, ae_name, ae_id); + acl_set_tag_type(acl_entry, ACL_USER); + acl_set_qualifier(acl_entry, &ae_uid); + break; + case ARCHIVE_ENTRY_ACL_GROUP: + ae_gid = archive_write_disk_gid(a, ae_name, ae_id); + acl_set_tag_type(acl_entry, ACL_GROUP); + acl_set_qualifier(acl_entry, &ae_gid); + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + acl_set_tag_type(acl_entry, ACL_USER_OBJ); + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + acl_set_tag_type(acl_entry, ACL_GROUP_OBJ); + break; + case ARCHIVE_ENTRY_ACL_MASK: + acl_set_tag_type(acl_entry, ACL_MASK); + break; + case ARCHIVE_ENTRY_ACL_OTHER: + acl_set_tag_type(acl_entry, ACL_OTHER); + break; + default: + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unsupported ACL tag"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + if (acl_get_permset(acl_entry, &acl_permset) != 0) { + archive_set_error(a, errno, + "Failed to get ACL permission set"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + if (acl_clear_perms(acl_permset) != 0) { + archive_set_error(a, errno, + "Failed to clear ACL permissions"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + for (i = 0; i < acl_posix_perm_map_size; ++i) { + if (ae_permset & acl_posix_perm_map[i].a_perm) { + if (acl_add_perm(acl_permset, + acl_posix_perm_map[i].p_perm) != 0) { + archive_set_error(a, errno, + "Failed to add ACL permission"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + } + } + + } + + if (fd >= 0 && ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { + if (acl_set_fd(fd, acl) == 0) + ret = ARCHIVE_OK; + else { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, + "Failed to set acl on fd: %s", tname); + ret = ARCHIVE_WARN; + } + } + } else if (acl_set_file(name, acl_type, acl) != 0) { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, "Failed to set acl: %s", + tname); + ret = ARCHIVE_WARN; + } + } +exit_free: + acl_free(acl); + return (ret); +} +#endif /* ARCHIVE_ACL_LIBACL */ + +int +archive_read_disk_entry_setup_acls(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + const char *accpath; + int r; +#if ARCHIVE_ACL_LIBACL + acl_t acl; +#endif +#if ARCHIVE_ACL_LIBRICHACL + struct richacl *richacl; + mode_t mode; +#endif + + accpath = NULL; + r = ARCHIVE_OK; + + /* For default ACLs we need reachable accpath */ + if (*fd < 0 || S_ISDIR(archive_entry_mode(entry))) { + accpath = archive_read_disk_entry_setup_path(a, entry, fd); + if (accpath == NULL) + return (ARCHIVE_WARN); + } + + archive_entry_acl_clear(entry); + +#if ARCHIVE_ACL_LIBACL + acl = NULL; +#endif +#if ARCHIVE_ACL_LIBRICHACL + richacl = NULL; +#endif + +#if ARCHIVE_ACL_LIBRICHACL + /* Try NFSv4 ACL first. */ + if (*fd >= 0) + richacl = richacl_get_fd(*fd); + else if ((!a->follow_symlinks) + && (archive_entry_filetype(entry) == AE_IFLNK)) + /* We can't get the ACL of a symlink, so we assume it can't + have one */ + richacl = NULL; + else + richacl = richacl_get_file(accpath); + + /* Ignore "trivial" ACLs that just mirror the file mode. */ + if (richacl != NULL) { + mode = archive_entry_mode(entry); + if (richacl_equiv_mode(richacl, &mode) == 0) { + richacl_free(richacl); + richacl = NULL; + return (ARCHIVE_OK); + } + } + + if (richacl != NULL) { + r = translate_richacl(a, entry, richacl); + richacl_free(richacl); + richacl = NULL; + + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate NFSv4 ACLs"); + } + + return (r); + } +#endif /* ARCHIVE_ACL_LIBRICHACL */ + +#if ARCHIVE_ACL_LIBACL + /* Retrieve access ACL from file. */ + if (*fd >= 0) + acl = acl_get_fd(*fd); + else if ((!a->follow_symlinks) + && (archive_entry_filetype(entry) == AE_IFLNK)) + /* We can't get the ACL of a symlink, so we assume it can't + have one. */ + acl = NULL; + else + acl = acl_get_file(accpath, ACL_TYPE_ACCESS); + + if (acl != NULL) { + r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); + acl_free(acl); + acl = NULL; + + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate access ACLs"); + return (r); + } + } + + /* Only directories can have default ACLs. */ + if (S_ISDIR(archive_entry_mode(entry))) { + acl = acl_get_file(accpath, ACL_TYPE_DEFAULT); + if (acl != NULL) { + r = translate_acl(a, entry, acl, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); + acl_free(acl); + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate default ACLs"); + return (r); + } + } + } +#endif /* ARCHIVE_ACL_LIBACL */ + return (r); +} + +int +archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, __LA_MODE_T mode) +{ + int ret = ARCHIVE_OK; + +#if !ARCHIVE_ACL_LIBRICHACL + (void)mode; /* UNUSED */ +#endif + +#if ARCHIVE_ACL_LIBRICHACL + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + ret = set_richacl(a, fd, name, abstract_acl, mode, + ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); + } +#if ARCHIVE_ACL_LIBACL + else +#endif +#endif /* ARCHIVE_ACL_LIBRICHACL */ +#if ARCHIVE_ACL_LIBACL + if ((archive_acl_types(abstract_acl) + & 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, + 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, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); + } +#endif /* ARCHIVE_ACL_LIBACL */ + return (ret); +} +#endif /* ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_LIBRICHACL */ diff --git a/libarchive/archive_disk_acl_sunos.c b/libarchive/archive_disk_acl_sunos.c new file mode 100644 index 0000000..bc84fd6 --- /dev/null +++ b/libarchive/archive_disk_acl_sunos.c @@ -0,0 +1,821 @@ +/*- + * Copyright (c) 2017 Martin Matuska + * 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" + +#if ARCHIVE_ACL_SUNOS + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_ACL_H +#define _ACL_PRIVATE /* For debugging */ +#include +#endif + +#include "archive_entry.h" +#include "archive_private.h" +#include "archive_read_disk_private.h" +#include "archive_write_disk_private.h" + +typedef struct { + const int a_perm; /* Libarchive permission or flag */ + const int p_perm; /* Platform permission or flag */ +} acl_perm_map_t; + +static const acl_perm_map_t acl_posix_perm_map[] = { + {ARCHIVE_ENTRY_ACL_EXECUTE, S_IXOTH }, + {ARCHIVE_ENTRY_ACL_WRITE, S_IWOTH }, + {ARCHIVE_ENTRY_ACL_READ, S_IROTH } +}; + +static const int acl_posix_perm_map_size = + (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0])); + +#if ARCHIVE_ACL_SUNOS_NFS4 +static const acl_perm_map_t acl_nfs4_perm_map[] = { + {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE}, + {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE} +}; + +static const int acl_nfs4_perm_map_size = + (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0])); + +static const acl_perm_map_t acl_nfs4_flag_map[] = { + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, + {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG}, +#ifdef ACE_INHERITED_ACE + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE} +#endif +}; + +const int acl_nfs4_flag_map_size = + (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0])); + +#endif /* ARCHIVE_ACL_SUNOS_NFS4 */ + +static void * +sunacl_get(int cmd, int *aclcnt, int fd, const char *path) +{ + int cnt, cntcmd; + size_t size; + void *aclp; + + if (cmd == GETACL) { + cntcmd = GETACLCNT; + size = sizeof(aclent_t); + } +#if ARCHIVE_ACL_SUNOS_NFS4 + else if (cmd == ACE_GETACL) { + cntcmd = ACE_GETACLCNT; + size = sizeof(ace_t); + } +#endif + else { + errno = EINVAL; + *aclcnt = -1; + return (NULL); + } + + aclp = NULL; + cnt = -2; + + while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) { + if (path != NULL) + cnt = acl(path, cntcmd, 0, NULL); + else + cnt = facl(fd, cntcmd, 0, NULL); + + if (cnt > 0) { + if (aclp == NULL) + aclp = malloc(cnt * size); + else + aclp = realloc(NULL, cnt * size); + if (aclp != NULL) { + if (path != NULL) + cnt = acl(path, cmd, cnt, aclp); + else + cnt = facl(fd, cmd, cnt, aclp); + } + } else { + if (aclp != NULL) { + free(aclp); + aclp = NULL; + } + break; + } + } + + *aclcnt = cnt; + return (aclp); +} + +/* + * Check if acl is trivial + * This is a FreeBSD acl_is_trivial_np() implementation for Solaris + */ +static int +sun_acl_is_trivial(void *aclp, int aclcnt, mode_t mode, int is_nfs4, + int is_dir, int *trivialp) +{ +#if ARCHIVE_ACL_SUNOS_NFS4 + int i, p; + const uint32_t rperm = ACE_READ_DATA; + const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA; + const uint32_t eperm = ACE_EXECUTE; + const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | + ACE_READ_ACL | ACE_SYNCHRONIZE; + const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES | + ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER; + + ace_t *ace; + ace_t tace[6]; +#endif + + if (aclp == NULL || trivialp == NULL) + return (-1); + + *trivialp = 0; + + /* + * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with + * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries, + * including mask. + */ + if (!is_nfs4) { + if (aclcnt == 4) + *trivialp = 1; + return (0); + } + +#if ARCHIVE_ACL_SUNOS_NFS4 + /* + * Continue with checking NFSv4 ACLs + * + * Create list of trivial ace's to be compared + */ + + /* owner@ allow pre */ + tace[0].a_flags = ACE_OWNER; + tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + tace[0].a_access_mask = 0; + + /* owner@ deny */ + tace[1].a_flags = ACE_OWNER; + tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE; + tace[1].a_access_mask = 0; + + /* group@ deny */ + tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; + tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE; + tace[2].a_access_mask = 0; + + /* owner@ allow */ + tace[3].a_flags = ACE_OWNER; + tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + tace[3].a_access_mask = ownset; + + /* group@ allow */ + tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; + tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + tace[4].a_access_mask = pubset; + + /* everyone@ allow */ + tace[5].a_flags = ACE_EVERYONE; + tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + tace[5].a_access_mask = pubset; + + /* Permissions for everyone@ */ + if (mode & 0004) + tace[5].a_access_mask |= rperm; + if (mode & 0002) + tace[5].a_access_mask |= wperm; + if (mode & 0001) + tace[5].a_access_mask |= eperm; + + /* Permissions for group@ */ + if (mode & 0040) + tace[4].a_access_mask |= rperm; + else if (mode & 0004) + tace[2].a_access_mask |= rperm; + if (mode & 0020) + tace[4].a_access_mask |= wperm; + else if (mode & 0002) + tace[2].a_access_mask |= wperm; + if (mode & 0010) + tace[4].a_access_mask |= eperm; + else if (mode & 0001) + tace[2].a_access_mask |= eperm; + + /* Permissions for owner@ */ + if (mode & 0400) { + tace[3].a_access_mask |= rperm; + if (!(mode & 0040) && (mode & 0004)) + tace[0].a_access_mask |= rperm; + } else if ((mode & 0040) || (mode & 0004)) + tace[1].a_access_mask |= rperm; + if (mode & 0200) { + tace[3].a_access_mask |= wperm; + if (!(mode & 0020) && (mode & 0002)) + tace[0].a_access_mask |= wperm; + } else if ((mode & 0020) || (mode & 0002)) + tace[1].a_access_mask |= wperm; + if (mode & 0100) { + tace[3].a_access_mask |= eperm; + if (!(mode & 0010) && (mode & 0001)) + tace[0].a_access_mask |= eperm; + } else if ((mode & 0010) || (mode & 0001)) + tace[1].a_access_mask |= eperm; + + /* Check if the acl count matches */ + p = 3; + for (i = 0; i < 3; i++) { + if (tace[i].a_access_mask != 0) + p++; + } + if (aclcnt != p) + return (0); + + p = 0; + for (i = 0; i < 6; i++) { + if (tace[i].a_access_mask != 0) { + ace = &((ace_t *)aclp)[p]; + /* + * Illumos added ACE_DELETE_CHILD to write perms for + * directories. We have to check against that, too. + */ + if (ace->a_flags != tace[i].a_flags || + ace->a_type != tace[i].a_type || + (ace->a_access_mask != tace[i].a_access_mask && + (!is_dir || (tace[i].a_access_mask & wperm) == 0 || + ace->a_access_mask != + (tace[i].a_access_mask | ACE_DELETE_CHILD)))) + return (0); + p++; + } + } + + *trivialp = 1; +#else /* !ARCHIVE_ACL_SUNOS_NFS4 */ + (void)is_dir; /* UNUSED */ + (void)aclp; /* UNUSED */ +#endif /* !ARCHIVE_ACL_SUNOS_NFS4 */ + return (0); +} + +/* + * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL + */ +static int +translate_acl(struct archive_read_disk *a, + struct archive_entry *entry, void *aclp, int aclcnt, + int default_entry_acl_type) +{ + int e, i; + int ae_id, ae_tag, ae_perm; + int entry_acl_type; + const char *ae_name; + aclent_t *aclent; +#if ARCHIVE_ACL_SUNOS_NFS4 + ace_t *ace; +#endif + + if (aclcnt <= 0) + return (ARCHIVE_OK); + + for (e = 0; e < aclcnt; e++) { + ae_name = NULL; + ae_tag = 0; + ae_perm = 0; + +#if ARCHIVE_ACL_SUNOS_NFS4 + if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + ace = &((ace_t *)aclp)[e]; + ae_id = ace->a_who; + + switch(ace->a_type) { + case ACE_ACCESS_ALLOWED_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + break; + case ACE_ACCESS_DENIED_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + break; + case ACE_SYSTEM_AUDIT_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + break; + case ACE_SYSTEM_ALARM_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; + break; + default: + /* Unknown entry type, skip */ + continue; + } + + if ((ace->a_flags & ACE_OWNER) != 0) + ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + else if ((ace->a_flags & ACE_GROUP) != 0) + ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + else if ((ace->a_flags & ACE_EVERYONE) != 0) + ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; + else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) { + ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + ae_name = archive_read_disk_gname(&a->archive, + ae_id); + } else { + ae_tag = ARCHIVE_ENTRY_ACL_USER; + ae_name = archive_read_disk_uname(&a->archive, + ae_id); + } + + for (i = 0; i < acl_nfs4_flag_map_size; ++i) { + if ((ace->a_flags & + acl_nfs4_flag_map[i].p_perm) != 0) + ae_perm |= acl_nfs4_flag_map[i].a_perm; + } + + for (i = 0; i < acl_nfs4_perm_map_size; ++i) { + if ((ace->a_access_mask & + acl_nfs4_perm_map[i].p_perm) != 0) + ae_perm |= acl_nfs4_perm_map[i].a_perm; + } + } else +#endif /* ARCHIVE_ACL_SUNOS_NFS4 */ + if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { + aclent = &((aclent_t *)aclp)[e]; + if ((aclent->a_type & ACL_DEFAULT) != 0) + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; + else + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + ae_id = aclent->a_id; + + switch(aclent->a_type) { + case DEF_USER: + case USER: + ae_name = archive_read_disk_uname(&a->archive, + ae_id); + ae_tag = ARCHIVE_ENTRY_ACL_USER; + break; + case DEF_GROUP: + case GROUP: + ae_name = archive_read_disk_gname(&a->archive, + ae_id); + ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + break; + case DEF_CLASS_OBJ: + case CLASS_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_MASK; + break; + case DEF_USER_OBJ: + case USER_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case DEF_GROUP_OBJ: + case GROUP_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case DEF_OTHER_OBJ: + case OTHER_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_OTHER; + break; + default: + /* Unknown tag type, skip */ + continue; + } + + for (i = 0; i < acl_posix_perm_map_size; ++i) { + if ((aclent->a_perm & + acl_posix_perm_map[i].p_perm) != 0) + ae_perm |= acl_posix_perm_map[i].a_perm; + } + } else + return (ARCHIVE_WARN); + + archive_entry_acl_add_entry(entry, entry_acl_type, + ae_perm, ae_tag, ae_id, ae_name); + } + return (ARCHIVE_OK); +} + +static int +set_acl(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, + int ae_requested_type, const char *tname) +{ + aclent_t *aclent; +#if ARCHIVE_ACL_SUNOS_NFS4 + ace_t *ace; +#endif + int cmd, e, r; + void *aclp; + int ret; + int ae_type, ae_permset, ae_tag, ae_id; + int perm_map_size; + const acl_perm_map_t *perm_map; + uid_t ae_uid; + gid_t ae_gid; + const char *ae_name; + int entries; + int i; + + ret = ARCHIVE_OK; + entries = archive_acl_reset(abstract_acl, ae_requested_type); + if (entries == 0) + return (ARCHIVE_OK); + + + switch (ae_requested_type) { + case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: + cmd = SETACL; + aclp = malloc(entries * sizeof(aclent_t)); + break; +#if ARCHIVE_ACL_SUNOS_NFS4 + case ARCHIVE_ENTRY_ACL_TYPE_NFS4: + cmd = ACE_SETACL; + aclp = malloc(entries * sizeof(ace_t)); + + break; +#endif + default: + errno = ENOENT; + archive_set_error(a, errno, "Unsupported ACL type"); + return (ARCHIVE_FAILED); + } + + if (aclp == NULL) { + archive_set_error(a, errno, + "Can't allocate memory for acl buffer"); + return (ARCHIVE_FAILED); + } + + e = 0; + + while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, + &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { + aclent = NULL; +#if ARCHIVE_ACL_SUNOS_NFS4 + ace = NULL; +#endif + if (cmd == SETACL) { + aclent = &((aclent_t *)aclp)[e]; + aclent->a_id = -1; + aclent->a_type = 0; + aclent->a_perm = 0; + } +#if ARCHIVE_ACL_SUNOS_NFS4 + else { /* cmd == ACE_SETACL */ + ace = &((ace_t *)aclp)[e]; + ace->a_who = -1; + ace->a_access_mask = 0; + ace->a_flags = 0; + } +#endif /* ARCHIVE_ACL_SUNOS_NFS4 */ + + switch (ae_tag) { + case ARCHIVE_ENTRY_ACL_USER: + ae_uid = archive_write_disk_uid(a, ae_name, ae_id); + if (aclent != NULL) { + aclent->a_id = ae_uid; + aclent->a_type |= USER; + } +#if ARCHIVE_ACL_SUNOS_NFS4 + else { + ace->a_who = ae_uid; + } +#endif + break; + case ARCHIVE_ENTRY_ACL_GROUP: + ae_gid = archive_write_disk_gid(a, ae_name, ae_id); + if (aclent != NULL) { + aclent->a_id = ae_gid; + aclent->a_type |= GROUP; + } +#if ARCHIVE_ACL_SUNOS_NFS4 + else { + ace->a_who = ae_gid; + ace->a_flags |= ACE_IDENTIFIER_GROUP; + } +#endif + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + if (aclent != NULL) + aclent->a_type |= USER_OBJ; +#if ARCHIVE_ACL_SUNOS_NFS4 + else { + ace->a_flags |= ACE_OWNER; + } +#endif + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + if (aclent != NULL) + aclent->a_type |= GROUP_OBJ; +#if ARCHIVE_ACL_SUNOS_NFS4 + else { + ace->a_flags |= ACE_GROUP; + ace->a_flags |= ACE_IDENTIFIER_GROUP; + } +#endif + break; + case ARCHIVE_ENTRY_ACL_MASK: + if (aclent != NULL) + aclent->a_type |= CLASS_OBJ; + break; + case ARCHIVE_ENTRY_ACL_OTHER: + if (aclent != NULL) + aclent->a_type |= OTHER_OBJ; + break; +#if ARCHIVE_ACL_SUNOS_NFS4 + case ARCHIVE_ENTRY_ACL_EVERYONE: + if (ace != NULL) + ace->a_flags |= ACE_EVERYONE; + break; +#endif + default: + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unsupported ACL tag"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + r = 0; + switch (ae_type) { +#if ARCHIVE_ACL_SUNOS_NFS4 + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + if (ace != NULL) + ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + else + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + if (ace != NULL) + ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE; + else + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + if (ace != NULL) + ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE; + else + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + if (ace != NULL) + ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE; + else + r = -1; + break; +#endif + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + if (aclent == NULL) + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + if (aclent != NULL) + aclent->a_type |= ACL_DEFAULT; + else + r = -1; + break; + default: + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unsupported ACL entry type"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + + if (r != 0) { + errno = EINVAL; + archive_set_error(a, errno, + "Failed to set ACL entry type"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + +#if ARCHIVE_ACL_SUNOS_NFS4 + if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + perm_map_size = acl_nfs4_perm_map_size; + perm_map = acl_nfs4_perm_map; + } else { +#endif + perm_map_size = acl_posix_perm_map_size; + perm_map = acl_posix_perm_map; +#if ARCHIVE_ACL_SUNOS_NFS4 + } +#endif + for (i = 0; i < perm_map_size; ++i) { + if (ae_permset & perm_map[i].a_perm) { +#if ARCHIVE_ACL_SUNOS_NFS4 + if (ae_requested_type == + ARCHIVE_ENTRY_ACL_TYPE_NFS4) + ace->a_access_mask |= + perm_map[i].p_perm; + else +#endif + aclent->a_perm |= perm_map[i].p_perm; + } + } + +#if ARCHIVE_ACL_SUNOS_NFS4 + if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + for (i = 0; i < acl_nfs4_flag_map_size; ++i) { + if (ae_permset & acl_nfs4_flag_map[i].a_perm) { + ace->a_flags |= + acl_nfs4_flag_map[i].p_perm; + } + } + } +#endif + e++; + } + + /* Try restoring the ACL through 'fd' if we can. */ + if (fd >= 0) { + if (facl(fd, cmd, entries, aclp) == 0) + ret = ARCHIVE_OK; + else { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, + "Failed to set acl on fd: %s", tname); + ret = ARCHIVE_WARN; + } + } + } else if (acl(name, cmd, entries, aclp) != 0) { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, "Failed to set acl: %s", + tname); + ret = ARCHIVE_WARN; + } + } +exit_free: + free(aclp); + return (ret); +} + +int +archive_read_disk_entry_setup_acls(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + const char *accpath; + void *aclp; + int aclcnt; + int r; + + accpath = NULL; + + if (*fd < 0) { + accpath = archive_read_disk_entry_setup_path(a, entry, fd); + if (accpath == NULL) + return (ARCHIVE_WARN); + } + + archive_entry_acl_clear(entry); + + aclp = NULL; + +#if ARCHIVE_ACL_SUNOS_NFS4 + if (*fd >= 0) + aclp = sunacl_get(ACE_GETACL, &aclcnt, *fd, NULL); + else if ((!a->follow_symlinks) + && (archive_entry_filetype(entry) == AE_IFLNK)) + /* We can't get the ACL of a symlink, so we assume it can't + have one. */ + aclp = NULL; + else + aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, accpath); + + if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt, + archive_entry_mode(entry), 1, S_ISDIR(archive_entry_mode(entry)), + &r) == 0 && r == 1) { + free(aclp); + aclp = NULL; + return (ARCHIVE_OK); + } + + if (aclp != NULL) { + r = translate_acl(a, entry, aclp, aclcnt, + ARCHIVE_ENTRY_ACL_TYPE_NFS4); + free(aclp); + aclp = NULL; + + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate NFSv4 ACLs"); + } + return (r); + } +#endif /* ARCHIVE_ACL_SUNOS_NFS4 */ + + /* Retrieve POSIX.1e ACLs from file. */ + if (*fd >= 0) + aclp = sunacl_get(GETACL, &aclcnt, *fd, NULL); + else if ((!a->follow_symlinks) + && (archive_entry_filetype(entry) == AE_IFLNK)) + /* We can't get the ACL of a symlink, so we assume it can't + have one. */ + aclp = NULL; + else + aclp = sunacl_get(GETACL, &aclcnt, 0, accpath); + + /* Ignore "trivial" ACLs that just mirror the file mode. */ + if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt, + archive_entry_mode(entry), 0, S_ISDIR(archive_entry_mode(entry)), + &r) == 0 && r == 1) { + free(aclp); + aclp = NULL; + } + + if (aclp != NULL) + { + r = translate_acl(a, entry, aclp, aclcnt, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS); + free(aclp); + aclp = NULL; + + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate access ACLs"); + return (r); + } + } + + return (ARCHIVE_OK); +} + +int +archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, __LA_MODE_T mode) +{ + int ret = ARCHIVE_OK; + + (void)mode; /* UNUSED */ + + 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, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e"); + + /* Simultaneous POSIX.1e and NFSv4 is not supported */ + return (ret); + } +#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, + ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); + } +#endif + return (ret); +} +#endif /* ARCHIVE_ACL_SUNOS */ diff --git a/libarchive/archive_entry.3 b/libarchive/archive_entry.3 index f5e22af..f75916c 100644 --- a/libarchive/archive_entry.3 +++ b/libarchive/archive_entry.3 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd Feburary 2, 2012 +.Dd February 2, 2012 .Dt ARCHIVE_ENTRY 3 .Os .Sh NAME diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c index 10eff11..30fb456 100644 --- a/libarchive/archive_entry.c +++ b/libarchive/archive_entry.c @@ -401,7 +401,7 @@ archive_entry_fflags_text(struct archive_entry *entry) return (NULL); } -int64_t +la_int64_t archive_entry_gid(struct archive_entry *entry) { return (entry->ae_stat.aest_gid); @@ -502,7 +502,7 @@ _archive_entry_hardlink_l(struct archive_entry *entry, return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc)); } -int64_t +la_int64_t archive_entry_ino(struct archive_entry *entry) { return (entry->ae_stat.aest_ino); @@ -514,7 +514,7 @@ archive_entry_ino_is_set(struct archive_entry *entry) return (entry->ae_set & AE_SET_INO); } -int64_t +la_int64_t archive_entry_ino64(struct archive_entry *entry) { return (entry->ae_stat.aest_ino); @@ -627,7 +627,7 @@ archive_entry_rdevminor(struct archive_entry *entry) return minor(entry->ae_stat.aest_rdev); } -int64_t +la_int64_t archive_entry_size(struct archive_entry *entry) { return (entry->ae_stat.aest_size); @@ -715,7 +715,7 @@ _archive_entry_symlink_l(struct archive_entry *entry, return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc)); } -int64_t +la_int64_t archive_entry_uid(struct archive_entry *entry) { return (entry->ae_stat.aest_uid); @@ -819,7 +819,7 @@ archive_entry_copy_fflags_text_w(struct archive_entry *entry, } void -archive_entry_set_gid(struct archive_entry *entry, int64_t g) +archive_entry_set_gid(struct archive_entry *entry, la_int64_t g) { entry->stat_valid = 0; entry->ae_stat.aest_gid = g; @@ -868,7 +868,7 @@ _archive_entry_copy_gname_l(struct archive_entry *entry, } void -archive_entry_set_ino(struct archive_entry *entry, int64_t ino) +archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino) { entry->stat_valid = 0; entry->ae_set |= AE_SET_INO; @@ -876,7 +876,7 @@ archive_entry_set_ino(struct archive_entry *entry, int64_t ino) } void -archive_entry_set_ino64(struct archive_entry *entry, int64_t ino) +archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino) { entry->stat_valid = 0; entry->ae_set |= AE_SET_INO; @@ -1209,7 +1209,7 @@ archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m) } void -archive_entry_set_size(struct archive_entry *entry, int64_t s) +archive_entry_set_size(struct archive_entry *entry, la_int64_t s) { entry->stat_valid = 0; entry->ae_stat.aest_size = s; @@ -1306,7 +1306,7 @@ _archive_entry_copy_symlink_l(struct archive_entry *entry, } void -archive_entry_set_uid(struct archive_entry *entry, int64_t u) +archive_entry_set_uid(struct archive_entry *entry, la_int64_t u) { entry->stat_valid = 0; entry->ae_stat.aest_uid = u; @@ -1638,7 +1638,7 @@ _archive_entry_acl_text_l(struct archive_entry *entry, int flags, * SUCH DAMAGE. */ -static struct flag { +static const struct flag { const char *name; const wchar_t *wname; unsigned long set; @@ -1708,6 +1708,9 @@ static struct flag { #ifdef UF_COMPRESSED { "nocompressed",L"nocompressed", UF_COMPRESSED, 0 }, #endif +#ifdef UF_HIDDEN + { "nohidden", L"nohidden", UF_HIDDEN, 0 }, +#endif #if defined(FS_UNRM_FL) { "nouunlink", L"nouunlink", FS_UNRM_FL, 0}, #elif defined(EXT2_UNRM_FL) @@ -1840,7 +1843,7 @@ ae_fflagstostr(unsigned long bitset, unsigned long bitclear) char *string, *dp; const char *sp; unsigned long bits; - struct flag *flag; + const struct flag *flag; size_t length; bits = bitset | bitclear; @@ -1892,7 +1895,7 @@ static const char * ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) { const char *start, *end; - struct flag *flag; + const struct flag *flag; unsigned long set, clear; const char *failed; @@ -1960,7 +1963,7 @@ static const wchar_t * ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp) { const wchar_t *start, *end; - struct flag *flag; + const struct flag *flag; unsigned long set, clear; const wchar_t *failed; diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h index 7645f0c..bcc2962 100644 --- a/libarchive/archive_entry.h +++ b/libarchive/archive_entry.h @@ -30,7 +30,7 @@ #define ARCHIVE_ENTRY_H_INCLUDED /* Note: Compiler will complain if this does not match archive.h! */ -#define ARCHIVE_VERSION_NUMBER 3003001 +#define ARCHIVE_VERSION_NUMBER 3003002 /* * Note: archive_entry.h is for use outside of libarchive; the diff --git a/libarchive/archive_entry_acl.3 b/libarchive/archive_entry_acl.3 index c5115f7..534dbfa 100644 --- a/libarchive/archive_entry_acl.3 +++ b/libarchive/archive_entry_acl.3 @@ -32,7 +32,7 @@ .Nm archive_entry_acl_clear , .Nm archive_entry_acl_count , .Nm archive_entry_acl_from_text , -.Nm archive_entry_acl_from_text_w, +.Nm archive_entry_acl_from_text_w , .Nm archive_entry_acl_next , .Nm archive_entry_acl_next_w , .Nm archive_entry_acl_reset , @@ -267,7 +267,7 @@ Only inherit, do not apply the permission on the directory itself. .It Dv ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT ( Sy n ) Do not propagate inherit flags. Only first-level entries inherit ACLs. .It Dv ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS ( Sy S ) -Trigger alarm or audit on succesful access. +Trigger alarm or audit on successful access. .It Dv ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS ( Sy F ) Trigger alarm or audit on failed access. .It Dv ARCHIVE_ENTRY_ACL_ENTRY_INHERITED ( Sy I ) @@ -279,7 +279,7 @@ and .Fn archive_entry_acl_add_entry_w add a single ACL entry. For the access ACL and non-extended principals, the classic Unix permissions -are updated. An archive enry cannot contain both POSIX.1e and NFSv4 ACL +are updated. An archive entry cannot contain both POSIX.1e and NFSv4 ACL entries. .Pp .Fn archive_entry_acl_clear @@ -303,7 +303,7 @@ for POSIX.1e ACLs and for NFSv4 ACLs. For POSIX.1e ACLs if .Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS is included and at least one extended ACL entry is found, -the three non-extened ACLs are added. +the three non-extended ACLs are added. .Pp .Fn archive_entry_acl_from_text and @@ -367,7 +367,7 @@ and .Fn archive_entry_acl_to_text_w convert the ACL entries for the given type into a .Pq wide -string of ACL entries separated by newline. If the the pointer +string of ACL entries separated by newline. If the pointer .Fa len_p is not NULL, then the function shall return the length of the string .Pq not including the NULL terminator diff --git a/libarchive/archive_entry_paths.3 b/libarchive/archive_entry_paths.3 index fd22cf7..f647212 100644 --- a/libarchive/archive_entry_paths.3 +++ b/libarchive/archive_entry_paths.3 @@ -31,25 +31,25 @@ .Nm archive_entry_set_hardlink , .Nm archive_entry_copy_hardlink , .Nm archive_entry_copy_hardlink_w , -.Nm archve_entry_update_hardlink_utf8 , +.Nm archive_entry_update_hardlink_utf8 , .Nm archive_entry_set_link , .Nm archive_entry_copy_link , .Nm archive_entry_copy_link_w , -.Nm archve_entry_update_link_utf8 , +.Nm archive_entry_update_link_utf8 , .Nm archive_entry_pathname , .Nm archive_entry_pathname_w , .Nm archive_entry_set_pathname , .Nm archive_entry_copy_pathname , .Nm archive_entry_copy_pathname_w , -.Nm archve_entry_update_pathname_utf8 , +.Nm archive_entry_update_pathname_utf8 , .Nm archive_entry_sourcepath , .Nm archive_entry_copy_sourcepath , -.Nm archive_entry_symlink, -.Nm archive_entry_symlink_w, +.Nm archive_entry_symlink , +.Nm archive_entry_symlink_w , .Nm archive_entry_set_symlink , .Nm archive_entry_copy_symlink , .Nm archive_entry_copy_symlink_w , -.Nm archve_entry_update_symlink_utf8 +.Nm archive_entry_update_symlink_utf8 .Nd functions for manipulating path names in archive entry descriptions .Sh LIBRARY Streaming Archive Library (libarchive, -larchive) diff --git a/libarchive/archive_entry_perms.3 b/libarchive/archive_entry_perms.3 index 340c5ea..aae3648 100644 --- a/libarchive/archive_entry_perms.3 +++ b/libarchive/archive_entry_perms.3 @@ -34,8 +34,8 @@ .Nm archive_entry_perm , .Nm archive_entry_set_perm , .Nm archive_entry_strmode , -.Nm archive_entry_uname -.Nm archive_entry_uname_w +.Nm archive_entry_uname , +.Nm archive_entry_uname_w , .Nm archive_entry_set_uname , .Nm archive_entry_copy_uname , .Nm archive_entry_copy_uname_w , diff --git a/libarchive/archive_entry_sparse.c b/libarchive/archive_entry_sparse.c index fed74f5..74917b3 100644 --- a/libarchive/archive_entry_sparse.c +++ b/libarchive/archive_entry_sparse.c @@ -51,7 +51,7 @@ archive_entry_sparse_clear(struct archive_entry *entry) void archive_entry_sparse_add_entry(struct archive_entry *entry, - int64_t offset, int64_t length) + la_int64_t offset, la_int64_t length) { struct ae_sparse *sp; @@ -135,7 +135,7 @@ archive_entry_sparse_reset(struct archive_entry * entry) int archive_entry_sparse_next(struct archive_entry * entry, - int64_t *offset, int64_t *length) + la_int64_t *offset, la_int64_t *length) { if (entry->sparse_p) { *offset = entry->sparse_p->offset; diff --git a/libarchive/archive_getdate.c b/libarchive/archive_getdate.c index beb0cba..030c083 100644 --- a/libarchive/archive_getdate.c +++ b/libarchive/archive_getdate.c @@ -691,7 +691,7 @@ Convert(time_t Month, time_t Day, time_t Year, time_t Hours, time_t Minutes, time_t Seconds, time_t Timezone, enum DSTMODE DSTmode) { - static int DaysInMonth[12] = { + signed char DaysInMonth[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; time_t Julian; diff --git a/libarchive/archive_openssl_hmac_private.h b/libarchive/archive_openssl_hmac_private.h index 2deeb5f..59f95b8 100644 --- a/libarchive/archive_openssl_hmac_private.h +++ b/libarchive/archive_openssl_hmac_private.h @@ -28,7 +28,7 @@ #include #include -#if OPENSSL_VERSION_NUMBER < 0x10100000L +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) #include /* malloc, free */ #include /* memset */ static inline HMAC_CTX *HMAC_CTX_new(void) diff --git a/libarchive/archive_pack_dev.c b/libarchive/archive_pack_dev.c index 6b7b472..098881b 100644 --- a/libarchive/archive_pack_dev.c +++ b/libarchive/archive_pack_dev.c @@ -280,7 +280,7 @@ pack_bsdos(int n, unsigned long numbers[], const char **error) /* list of formats and pack functions */ /* this list must be sorted lexically */ -static struct format { +static const struct format { const char *name; pack_t *pack; } formats[] = { diff --git a/libarchive/archive_platform.h b/libarchive/archive_platform.h index c9a9602..34be8ed 100644 --- a/libarchive/archive_platform.h +++ b/libarchive/archive_platform.h @@ -143,32 +143,6 @@ #endif /* - * If this platform has , acl_create(), acl_init(), - * acl_set_file(), and ACL_USER, we assume it has the rest of the - * POSIX.1e draft functions used in archive_read_extract.c. - */ -#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE -#if HAVE_ACL_USER -#define HAVE_POSIX_ACL 1 -#elif HAVE_ACL_TYPE_EXTENDED -#define HAVE_DARWIN_ACL 1 -#endif -#endif - -/* - * If this platform has , acl_get(), facl_get(), acl_set(), - * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions - */ -#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T -#define HAVE_SUN_ACL 1 -#endif - -/* Define if platform supports NFSv4 ACLs */ -#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL -#define HAVE_NFS4_ACL 1 -#endif - -/* * If we can't restore metadata using a file descriptor, then * for compatibility's sake, close files before trying to restore metadata. */ diff --git a/libarchive/archive_platform_acl.h b/libarchive/archive_platform_acl.h new file mode 100644 index 0000000..3498f78 --- /dev/null +++ b/libarchive/archive_platform_acl.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2017 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */ + +#ifndef ARCHIVE_PLATFORM_ACL_H_INCLUDED +#define ARCHIVE_PLATFORM_ACL_H_INCLUDED + +/* + * Determine what ACL types are supported + */ +#if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_SUNOS || ARCHIVE_ACL_LIBACL +#define ARCHIVE_ACL_POSIX1E 1 +#endif + +#if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_SUNOS_NFS4 || \ + ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL +#define ARCHIVE_ACL_NFS4 1 +#endif + +#if ARCHIVE_ACL_POSIX1E || ARCHIVE_ACL_NFS4 +#define ARCHIVE_ACL_SUPPORT 1 +#endif + +#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */ diff --git a/libarchive/archive_platform_xattr.h b/libarchive/archive_platform_xattr.h new file mode 100644 index 0000000..4edfecf --- /dev/null +++ b/libarchive/archive_platform_xattr.h @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2017 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */ + +#ifndef ARCHIVE_PLATFORM_XATTR_H_INCLUDED +#define ARCHIVE_PLATFORM_XATTR_H_INCLUDED + +/* + * Determine if we support extended attributes + */ +#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_FREEBSD || \ + ARCHIVE_XATTR_AIX +#define ARCHIVE_XATTR_SUPPORT 1 +#endif + +#endif /* ARCHIVE_PLATFORM_XATTR_H_INCLUDED */ diff --git a/libarchive/archive_random.c b/libarchive/archive_random.c index 357f973..65ea691 100644 --- a/libarchive/archive_random.c +++ b/libarchive/archive_random.c @@ -221,8 +221,11 @@ arc4_stir(void) /* * Discard early keystream, as per recommendations in: * "(Not So) Random Shuffles of RC4" by Ilya Mironov. + * As per the Network Operations Division, cryptographic requirements + * published on wikileaks on March 2017. */ - for (i = 0; i < 1024; i++) + + for (i = 0; i < 3072; i++) (void)arc4_getbyte(); arc4_count = 1600000; } diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c index d1feceb..a642a33 100644 --- a/libarchive/archive_read.c +++ b/libarchive/archive_read.c @@ -881,7 +881,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s) len = a->read_data_remaining; if (len > s) len = s; - memcpy(dest, a->read_data_block, len); + if (len) + memcpy(dest, a->read_data_block, len); s -= len; a->read_data_block += len; a->read_data_remaining -= len; diff --git a/libarchive/archive_read_disk.3 b/libarchive/archive_read_disk.3 index 2a5c130..027f63c 100644 --- a/libarchive/archive_read_disk.3 +++ b/libarchive/archive_read_disk.3 @@ -24,11 +24,12 @@ .\" .\" $FreeBSD$ .\" -.Dd December 30, 2016 +.Dd April 3, 2017 .Dt ARCHIVE_READ_DISK 3 .Os .Sh NAME .Nm archive_read_disk_new , +.Nm archive_read_disk_set_behavior , .Nm archive_read_disk_set_symlink_logical , .Nm archive_read_disk_set_symlink_physical , .Nm archive_read_disk_set_symlink_hybrid , @@ -37,10 +38,7 @@ .Nm archive_read_disk_uname , .Nm archive_read_disk_set_uname_lookup , .Nm archive_read_disk_set_gname_lookup , -.Nm archive_read_disk_set_standard_lookup , -.Nm archive_read_close , -.Nm archive_read_finish , -.Nm archive_read_free +.Nm archive_read_disk_set_standard_lookup .Nd functions for reading objects from disk .Sh LIBRARY Streaming Archive Library (libarchive, -larchive) @@ -49,6 +47,8 @@ Streaming Archive Library (libarchive, -larchive) .Ft struct archive * .Fn archive_read_disk_new "void" .Ft int +.Fn archive_read_disk_set_behavior "struct archive *" "int" +.Ft int .Fn archive_read_disk_set_symlink_logical "struct archive *" .Ft int .Fn archive_read_disk_set_symlink_physical "struct archive *" @@ -81,12 +81,6 @@ Streaming Archive Library (libarchive, -larchive) .Fa "int fd" .Fa "const struct stat *" .Fc -.Ft int -.Fn archive_read_close "struct archive *" -.Ft int -.Fn archive_read_finish "struct archive *" -.Ft int -.Fn archive_read_free "struct archive *" .Sh DESCRIPTION These functions provide an API for reading information about objects on disk. @@ -98,6 +92,51 @@ objects. Allocates and initializes a .Tn struct archive object suitable for reading object information from disk. +.It Fn archive_read_disk_set_behavior +Configures various behavior options when reading entries from disk. +The flags field consists of a bitwise OR of one or more of the +following values: +.Bl -tag -compact -width "indent" +.It Cm ARCHIVE_READDISK_HONOR_NODUMP +Skip files and directories with the nodump file attribute (file flag) set. +By default, the nodump file atrribute is ignored. +.It Cm ARCHIVE_READDISK_MAC_COPYFILE +Mac OS X specific. Read metadata (ACLs and extended attributes) with +.Xr copyfile 3 . +By default, metadata is read using +.Xr copyfile 3 . +.It Cm ARCHIVE_READDISK_NO_ACL +Do not read Access Control Lists. +By default, ACLs are read from disk. +.It Cm ARCHIVE_READDISK_NO_FFLAGS +Do not read file attributes (file flags). +By default, file attributes are read from disk. +See +.Xr chattr 1 +.Pq Linux +or +.Xr chflags 1 +.Pq FreeBSD, Mac OS X +for more information on file attributes. +.It Cm ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS +Do not traverse mount points. +By defaut, moint points are traversed. +.It Cm ARCHIVE_READDISK_NO_XATTR +Do not read extended file attributes (xattrs). +By default, extended file attributes are read from disk. +See +.Xr xattr 7 +.Pq Linux , +.Xr xattr 2 +.Pq Mac OS X , +or +.Xr getextattr 8 +.Pq FreeBSD +for more information on extended file attributes. +.It Cm ARCHIVE_READDISK_RESTORE_ATIME +Restore access time of traversed files. +By default, access time of traversed files is not restored. +.El .It Xo .Fn archive_read_disk_set_symlink_logical , .Fn archive_read_disk_set_symlink_physical , @@ -181,17 +220,6 @@ using the currently registered lookup functions above. This affects the file ownership fields and ACL values in the .Tn struct archive_entry object. -.It Fn archive_read_close -Does nothing for -.Tn archive_read_disk -handles. -.It Fn archive_read_finish -This is a deprecated synonym for -.Fn archive_read_free . -.It Fn archive_read_free -Invokes -.Fn archive_read_close -if it was not invoked manually, then releases all resources. .El More information about the .Va struct archive diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c index b2f1d17..548ba89 100644 --- a/libarchive/archive_read_disk_entry_from_file.c +++ b/libarchive/archive_read_disk_entry_from_file.c @@ -26,23 +26,14 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 201084 2009-12-28 02:14:09Z kientzle $"); +__FBSDID("$FreeBSD"); /* This is the tree-walking code for POSIX systems. */ #if !defined(_WIN32) || defined(__CYGWIN__) #ifdef HAVE_SYS_TYPES_H -/* Mac OSX requires sys/types.h before sys/acl.h. */ #include #endif -#ifdef HAVE_SYS_ACL_H -#include -#endif -#ifdef HAVE_DARWIN_ACL -#include -#include -#include -#endif #ifdef HAVE_SYS_EXTATTR_H #include #endif @@ -63,9 +54,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010 #ifdef HAVE_SYS_EA_H #include #endif -#ifdef HAVE_ACL_LIBACL_H -#include -#endif #ifdef HAVE_COPYFILE_H #include #endif @@ -113,27 +101,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010 #define O_CLOEXEC 0 #endif -/* - * Linux and FreeBSD plug this obvious hole in POSIX.1e in - * different ways. - */ -#if HAVE_ACL_GET_PERM -#define ACL_GET_PERM acl_get_perm -#elif HAVE_ACL_GET_PERM_NP -#define ACL_GET_PERM acl_get_perm_np -#endif - -/* NFSv4 platform ACL type */ -#if HAVE_SUN_ACL -#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T -#elif HAVE_DARWIN_ACL -#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED -#elif HAVE_ACL_TYPE_NFS4 -#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4 -#endif - -static int setup_acls(struct archive_read_disk *, - struct archive_entry *, int *fd); static int setup_mac_metadata(struct archive_read_disk *, struct archive_entry *, int *fd); static int setup_xattrs(struct archive_read_disk *, @@ -145,6 +112,45 @@ static int setup_sparse_fiemap(struct archive_read_disk *, struct archive_entry *, int *fd); #endif +#if !ARCHIVE_ACL_SUPPORT +int +archive_read_disk_entry_setup_acls(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + (void)a; /* UNUSED */ + (void)entry; /* UNUSED */ + (void)fd; /* UNUSED */ + return (ARCHIVE_OK); +} +#endif + +/* + * Enter working directory and return working pathname of archive_entry. + * If a pointer to an integer is provided and its value is below zero + * open a file descriptor on this pahtname. + */ +const char * +archive_read_disk_entry_setup_path(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + const char *path; + + path = archive_entry_sourcepath(entry); + + if (path == NULL || (a->tree != NULL && + a->tree_enter_working_dir(a->tree) != 0)) + path = archive_entry_pathname(entry); + if (path == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Couldn't determine path"); + } else if (fd != NULL && *fd < 0 && a->tree != NULL && + (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)) { + *fd = a->open_on_current_dir(a->tree, path, + O_RDONLY | O_NONBLOCK); + } + return (path); +} + int archive_read_disk_entry_from_file(struct archive *_a, struct archive_entry *entry, @@ -279,7 +285,7 @@ archive_read_disk_entry_from_file(struct archive *_a, r = 0; if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0) - r = setup_acls(a, entry, &fd); + r = archive_read_disk_entry_setup_acls(a, entry, &fd); if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) { r1 = setup_xattrs(a, entry, &fd); if (r1 < r) @@ -328,19 +334,10 @@ setup_mac_metadata(struct archive_read_disk *a, struct archive_string tempfile; (void)fd; /* UNUSED */ - name = archive_entry_sourcepath(entry); + + name = archive_read_disk_entry_setup_path(a, entry, NULL); if (name == NULL) - name = archive_entry_pathname(entry); - else if (a->tree != NULL && a->tree_enter_working_dir(a->tree) != 0) { - archive_set_error(&a->archive, errno, - "Can't change dir to read extended attributes"); - return (ARCHIVE_FAILED); - } - if (name == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Can't open file to read extended attributes: No name"); return (ARCHIVE_WARN); - } /* Short-circuit if there's nothing to do. */ have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK); @@ -426,996 +423,10 @@ setup_mac_metadata(struct archive_read_disk *a, } #endif -#if HAVE_DARWIN_ACL -static int translate_guid(struct archive *, acl_entry_t, - int *, int *, const char **); - -static void add_trivial_nfs4_acl(struct archive_entry *); -#endif - -#if HAVE_SUN_ACL -static int -sun_acl_is_trivial(acl_t *, mode_t, int *trivialp); -#endif - -#if HAVE_POSIX_ACL || HAVE_NFS4_ACL -static int translate_acl(struct archive_read_disk *a, - struct archive_entry *entry, -#if HAVE_SUN_ACL - acl_t *acl, -#else - acl_t acl, -#endif - int archive_entry_acl_type); - -static int -setup_acls(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - const char *accpath; -#if HAVE_SUN_ACL - acl_t *acl; -#else - acl_t acl; -#endif - int r; - - accpath = NULL; - -#if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_ACL_GET_FD_NP - if (*fd < 0) -#else - /* For default ACLs on Linux we need reachable accpath */ - if (*fd < 0 || S_ISDIR(archive_entry_mode(entry))) -#endif - { - accpath = archive_entry_sourcepath(entry); - if (accpath == NULL || (a->tree != NULL && - a->tree_enter_working_dir(a->tree) != 0)) - accpath = archive_entry_pathname(entry); - if (accpath == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Couldn't determine file path to read ACLs"); - return (ARCHIVE_WARN); - } - if (a->tree != NULL && -#if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_ACL_GET_FD_NP - *fd < 0 && -#endif - (a->follow_symlinks || - archive_entry_filetype(entry) != AE_IFLNK)) { - *fd = a->open_on_current_dir(a->tree, - accpath, O_RDONLY | O_NONBLOCK); - } - } - - archive_entry_acl_clear(entry); - - acl = NULL; - -#if HAVE_NFS4_ACL - /* Try NFSv4 ACL first. */ - if (*fd >= 0) -#if HAVE_SUN_ACL - /* Solaris reads both POSIX.1e and NFSv4 ACL here */ - facl_get(*fd, 0, &acl); -#elif HAVE_ACL_GET_FD_NP - acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); -#else - acl = acl_get_fd(*fd); -#endif -#if HAVE_ACL_GET_LINK_NP - else if (!a->follow_symlinks) - acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); -#else - else if ((!a->follow_symlinks) - && (archive_entry_filetype(entry) == AE_IFLNK)) - /* We can't get the ACL of a symlink, so we assume it can't - have one. */ - acl = NULL; -#endif - else -#if HAVE_SUN_ACL - /* Solaris reads both POSIX.1e and NFSv4 ACLs here */ - acl_get(accpath, 0, &acl); -#else - acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); -#endif - - -#if HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL - /* Ignore "trivial" ACLs that just mirror the file mode. */ - if (acl != NULL) { -#if HAVE_SUN_ACL - if (sun_acl_is_trivial(acl, archive_entry_mode(entry), - &r) == 0 && r == 1) -#elif HAVE_ACL_IS_TRIVIAL_NP - if (acl_is_trivial_np(acl, &r) == 0 && r == 1) -#endif - { - acl_free(acl); - acl = NULL; - /* - * Simultaneous NFSv4 and POSIX.1e ACLs for the same - * entry are not allowed, so we should return here - */ - return (ARCHIVE_OK); - } - } -#endif /* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */ - if (acl != NULL) { - r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4); - acl_free(acl); - if (r != ARCHIVE_OK) { - archive_set_error(&a->archive, errno, - "Couldn't translate " -#if !HAVE_SUN_ACL - "NFSv4 " -#endif - "ACLs"); - } -#if HAVE_DARWIN_ACL - /* - * Because Mac OS doesn't support owner@, group@ and everyone@ - * ACLs we need to add NFSv4 ACLs mirroring the file mode to - * the archive entry. Otherwise extraction on non-Mac platforms - * would lead to an invalid file mode. - */ - if ((archive_entry_acl_types(entry) & - ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) - add_trivial_nfs4_acl(entry); -#endif - return (r); - } -#endif /* HAVE_NFS4_ACL */ - -#if HAVE_POSIX_ACL - /* This code path is skipped on MacOS and Solaris */ +#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX - /* Retrieve access ACL from file. */ - if (*fd >= 0) - acl = acl_get_fd(*fd); -#if HAVE_ACL_GET_LINK_NP - else if (!a->follow_symlinks) - acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS); -#else - else if ((!a->follow_symlinks) - && (archive_entry_filetype(entry) == AE_IFLNK)) - /* We can't get the ACL of a symlink, so we assume it can't - have one. */ - acl = NULL; -#endif - else - acl = acl_get_file(accpath, ACL_TYPE_ACCESS); - -#if HAVE_ACL_IS_TRIVIAL_NP - /* Ignore "trivial" ACLs that just mirror the file mode. */ - if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) { - if (r) { - acl_free(acl); - acl = NULL; - } - } -#endif - - if (acl != NULL) { - r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); - acl_free(acl); - acl = NULL; - if (r != ARCHIVE_OK) { - archive_set_error(&a->archive, errno, - "Couldn't translate access ACLs"); - return (r); - } - } - - /* Only directories can have default ACLs. */ - if (S_ISDIR(archive_entry_mode(entry))) { -#if HAVE_ACL_GET_FD_NP - if (*fd >= 0) - acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT); - else -#endif - acl = acl_get_file(accpath, ACL_TYPE_DEFAULT); - if (acl != NULL) { - r = translate_acl(a, entry, acl, - ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); - acl_free(acl); - if (r != ARCHIVE_OK) { - archive_set_error(&a->archive, errno, - "Couldn't translate default ACLs"); - return (r); - } - } - } -#endif /* HAVE_POSIX_ACL */ - return (ARCHIVE_OK); -} - -/* - * Translate system ACL permissions into libarchive internal structure - */ -static const struct { - const int archive_perm; - const int platform_perm; -} acl_perm_map[] = { -#if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */ - {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE}, - {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA}, - {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY}, - {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE}, - {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY}, - {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD}, - {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE}, - {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER}, - {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE} -#elif HAVE_DARWIN_ACL /* MacOS ACL permissions */ - {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, - {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, - {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, - {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, - {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, - {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, - {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, - {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY}, - {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY}, - {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER}, - {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} -#else /* POSIX.1e ACL permissions */ - {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, - {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, - {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, -#if HAVE_ACL_TYPE_NFS4 /* FreeBSD NFSv4 ACL permissions */ - {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, - {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, - {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, - {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, - {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, - {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, - {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, - {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} -#endif -#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ -}; - -#if HAVE_NFS4_ACL -/* - * Translate system NFSv4 inheritance flags into libarchive internal structure - */ -static const struct { - const int archive_inherit; - const int platform_inherit; -} acl_inherit_map[] = { -#if HAVE_SUN_ACL /* Solaris ACL inheritance flags */ - {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE}, - {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE}, - {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE}, - {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, - {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE} -#elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */ - {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}, - {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT} -#else /* FreeBSD NFSv4 ACL inheritance flags */ - {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}, - {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS}, - {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED} -#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ -}; -#endif /* HAVE_NFS4_ACL */ - -#if HAVE_DARWIN_ACL -static int translate_guid(struct archive *a, acl_entry_t acl_entry, - int *ae_id, int *ae_tag, const char **ae_name) -{ - void *q; - uid_t ugid; - int r, idtype; - struct passwd *pwd; - struct group *grp; - - q = acl_get_qualifier(acl_entry); - if (q == NULL) - return (1); - r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype); - if (r != 0) { - acl_free(q); - return (1); - } - if (idtype == ID_TYPE_UID) { - *ae_tag = ARCHIVE_ENTRY_ACL_USER; - pwd = getpwuuid(q); - if (pwd == NULL) { - *ae_id = ugid; - *ae_name = NULL; - } else { - *ae_id = pwd->pw_uid; - *ae_name = archive_read_disk_uname(a, *ae_id); - } - } else if (idtype == ID_TYPE_GID) { - *ae_tag = ARCHIVE_ENTRY_ACL_GROUP; - grp = getgruuid(q); - if (grp == NULL) { - *ae_id = ugid; - *ae_name = NULL; - } else { - *ae_id = grp->gr_gid; - *ae_name = archive_read_disk_gname(a, *ae_id); - } - } else - r = 1; - - acl_free(q); - return (r); -} - -/* - * Add trivial NFSv4 ACL entries from mode - */ -static void -add_trivial_nfs4_acl(struct archive_entry *entry) -{ - mode_t mode; - int i; - const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA; - const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA | - ARCHIVE_ENTRY_ACL_APPEND_DATA; - const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE; - const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | - ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | - ARCHIVE_ENTRY_ACL_READ_ACL | - ARCHIVE_ENTRY_ACL_SYNCHRONIZE; - const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | - ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | - ARCHIVE_ENTRY_ACL_WRITE_ACL | - ARCHIVE_ENTRY_ACL_WRITE_OWNER; - - struct { - const int type; - const int tag; - int permset; - } tacl_entry[] = { - {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0}, - {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0}, - {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0}, - {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset}, - {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset}, - {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset} - }; - - mode = archive_entry_mode(entry); - - /* Permissions for everyone@ */ - if (mode & 0004) - tacl_entry[5].permset |= rperm; - if (mode & 0002) - tacl_entry[5].permset |= wperm; - if (mode & 0001) - tacl_entry[5].permset |= eperm; - - /* Permissions for group@ */ - if (mode & 0040) - tacl_entry[4].permset |= rperm; - else if (mode & 0004) - tacl_entry[2].permset |= rperm; - if (mode & 0020) - tacl_entry[4].permset |= wperm; - else if (mode & 0002) - tacl_entry[2].permset |= wperm; - if (mode & 0010) - tacl_entry[4].permset |= eperm; - else if (mode & 0001) - tacl_entry[2].permset |= eperm; - - /* Permissions for owner@ */ - if (mode & 0400) { - tacl_entry[3].permset |= rperm; - if (!(mode & 0040) && (mode & 0004)) - tacl_entry[0].permset |= rperm; - } else if ((mode & 0040) || (mode & 0004)) - tacl_entry[1].permset |= rperm; - if (mode & 0200) { - tacl_entry[3].permset |= wperm; - if (!(mode & 0020) && (mode & 0002)) - tacl_entry[0].permset |= wperm; - } else if ((mode & 0020) || (mode & 0002)) - tacl_entry[1].permset |= wperm; - if (mode & 0100) { - tacl_entry[3].permset |= eperm; - if (!(mode & 0010) && (mode & 0001)) - tacl_entry[0].permset |= eperm; - } else if ((mode & 0010) || (mode & 0001)) - tacl_entry[1].permset |= eperm; - - for (i = 0; i < 6; i++) { - if (tacl_entry[i].permset != 0) { - archive_entry_acl_add_entry(entry, - tacl_entry[i].type, tacl_entry[i].permset, - tacl_entry[i].tag, -1, NULL); - } - } - - return; -} -#elif HAVE_SUN_ACL -/* - * Check if acl is trivial - * This is a FreeBSD acl_is_trivial_np() implementation for Solaris - */ -static int -sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp) -{ - int i, p; - const uint32_t rperm = ACE_READ_DATA; - const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA; - const uint32_t eperm = ACE_EXECUTE; - const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | - ACE_READ_ACL | ACE_SYNCHRONIZE; - const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES | - ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER; - - ace_t *ace; - ace_t tace[6]; - - if (acl == NULL || trivialp == NULL) - return (-1); - - *trivialp = 0; - - /* ACL_IS_TRIVIAL flag must be set for both POSIX.1e and NFSv4 ACLs */ - if ((acl->acl_flags & ACL_IS_TRIVIAL) == 0) - return (0); - - /* - * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with - * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries, - * including mask. - */ - if (acl->acl_type == ACLENT_T) { - if (acl->acl_cnt == 4) - *trivialp = 1; - return (0); - } - - if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t)) - return (-1); - - /* - * Continue with checking NFSv4 ACLs - * - * Create list of trivial ace's to be compared - */ - - /* owner@ allow pre */ - tace[0].a_flags = ACE_OWNER; - tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; - tace[0].a_access_mask = 0; - - /* owner@ deny */ - tace[1].a_flags = ACE_OWNER; - tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE; - tace[1].a_access_mask = 0; - - /* group@ deny */ - tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; - tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE; - tace[2].a_access_mask = 0; - - /* owner@ allow */ - tace[3].a_flags = ACE_OWNER; - tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; - tace[3].a_access_mask = ownset; - - /* group@ allow */ - tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; - tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; - tace[4].a_access_mask = pubset; - - /* everyone@ allow */ - tace[5].a_flags = ACE_EVERYONE; - tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; - tace[5].a_access_mask = pubset; - - /* Permissions for everyone@ */ - if (mode & 0004) - tace[5].a_access_mask |= rperm; - if (mode & 0002) - tace[5].a_access_mask |= wperm; - if (mode & 0001) - tace[5].a_access_mask |= eperm; - - /* Permissions for group@ */ - if (mode & 0040) - tace[4].a_access_mask |= rperm; - else if (mode & 0004) - tace[2].a_access_mask |= rperm; - if (mode & 0020) - tace[4].a_access_mask |= wperm; - else if (mode & 0002) - tace[2].a_access_mask |= wperm; - if (mode & 0010) - tace[4].a_access_mask |= eperm; - else if (mode & 0001) - tace[2].a_access_mask |= eperm; - - /* Permissions for owner@ */ - if (mode & 0400) { - tace[3].a_access_mask |= rperm; - if (!(mode & 0040) && (mode & 0004)) - tace[0].a_access_mask |= rperm; - } else if ((mode & 0040) || (mode & 0004)) - tace[1].a_access_mask |= rperm; - if (mode & 0200) { - tace[3].a_access_mask |= wperm; - if (!(mode & 0020) && (mode & 0002)) - tace[0].a_access_mask |= wperm; - } else if ((mode & 0020) || (mode & 0002)) - tace[1].a_access_mask |= wperm; - if (mode & 0100) { - tace[3].a_access_mask |= eperm; - if (!(mode & 0010) && (mode & 0001)) - tace[0].a_access_mask |= eperm; - } else if ((mode & 0010) || (mode & 0001)) - tace[1].a_access_mask |= eperm; - - /* Check if the acl count matches */ - p = 3; - for (i = 0; i < 3; i++) { - if (tace[i].a_access_mask != 0) - p++; - } - if (acl->acl_cnt != p) - return (0); - - p = 0; - for (i = 0; i < 6; i++) { - if (tace[i].a_access_mask != 0) { - ace = &((ace_t *)acl->acl_aclp)[p]; - /* - * Illumos added ACE_DELETE_CHILD to write perms for - * directories. We have to check against that, too. - */ - if (ace->a_flags != tace[i].a_flags || - ace->a_type != tace[i].a_type || - (ace->a_access_mask != tace[i].a_access_mask && - ((acl->acl_flags & ACL_IS_DIR) == 0 || - (tace[i].a_access_mask & wperm) == 0 || - ace->a_access_mask != - (tace[i].a_access_mask | ACE_DELETE_CHILD)))) - return (0); - p++; - } - } - - *trivialp = 1; - return (0); -} -#endif /* HAVE_SUN_ACL */ - -#if HAVE_SUN_ACL /* - * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL - */ -static int -translate_acl(struct archive_read_disk *a, - struct archive_entry *entry, acl_t *acl, int default_entry_acl_type) -{ - int e, i; - int ae_id, ae_tag, ae_perm; - int entry_acl_type; - const char *ae_name; - aclent_t *aclent; - ace_t *ace; - - (void)default_entry_acl_type; - - if (acl->acl_cnt <= 0) - return (ARCHIVE_OK); - - for (e = 0; e < acl->acl_cnt; e++) { - ae_name = NULL; - ae_tag = 0; - ae_perm = 0; - - if (acl->acl_type == ACE_T) { - ace = &((ace_t *)acl->acl_aclp)[e]; - ae_id = ace->a_who; - - switch(ace->a_type) { - case ACE_ACCESS_ALLOWED_ACE_TYPE: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; - break; - case ACE_ACCESS_DENIED_ACE_TYPE: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; - break; - case ACE_SYSTEM_AUDIT_ACE_TYPE: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - break; - case ACE_SYSTEM_ALARM_ACE_TYPE: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; - break; - default: - /* Unknown entry type, skip */ - continue; - } - - if ((ace->a_flags & ACE_OWNER) != 0) - ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - else if ((ace->a_flags & ACE_GROUP) != 0) - ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - else if ((ace->a_flags & ACE_EVERYONE) != 0) - ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; - else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) { - ae_tag = ARCHIVE_ENTRY_ACL_GROUP; - ae_name = archive_read_disk_gname(&a->archive, - ae_id); - } else { - ae_tag = ARCHIVE_ENTRY_ACL_USER; - ae_name = archive_read_disk_uname(&a->archive, - ae_id); - } - - for (i = 0; i < (int)(sizeof(acl_inherit_map) / - sizeof(acl_inherit_map[0])); ++i) { - if ((ace->a_flags & - acl_inherit_map[i].platform_inherit) != 0) - ae_perm |= - acl_inherit_map[i].archive_inherit; - } - - for (i = 0; i < (int)(sizeof(acl_perm_map) / - sizeof(acl_perm_map[0])); ++i) { - if ((ace->a_access_mask & - acl_perm_map[i].platform_perm) != 0) - ae_perm |= - acl_perm_map[i].archive_perm; - } - } else { - aclent = &((aclent_t *)acl->acl_aclp)[e]; - if ((aclent->a_type & ACL_DEFAULT) != 0) - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; - else - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; - ae_id = aclent->a_id; - - switch(aclent->a_type) { - case DEF_USER: - case USER: - ae_name = archive_read_disk_uname(&a->archive, - ae_id); - ae_tag = ARCHIVE_ENTRY_ACL_USER; - break; - case DEF_GROUP: - case GROUP: - ae_name = archive_read_disk_gname(&a->archive, - ae_id); - ae_tag = ARCHIVE_ENTRY_ACL_GROUP; - break; - case DEF_CLASS_OBJ: - case CLASS_OBJ: - ae_tag = ARCHIVE_ENTRY_ACL_MASK; - break; - case DEF_USER_OBJ: - case USER_OBJ: - ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - break; - case DEF_GROUP_OBJ: - case GROUP_OBJ: - ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - break; - case DEF_OTHER_OBJ: - case OTHER_OBJ: - ae_tag = ARCHIVE_ENTRY_ACL_OTHER; - break; - default: - /* Unknown tag type, skip */ - continue; - } - - if ((aclent->a_perm & 1) != 0) - ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE; - if ((aclent->a_perm & 2) != 0) - ae_perm |= ARCHIVE_ENTRY_ACL_WRITE; - if ((aclent->a_perm & 4) != 0) - ae_perm |= ARCHIVE_ENTRY_ACL_READ; - } /* default_entry_acl_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4 */ - - archive_entry_acl_add_entry(entry, entry_acl_type, - ae_perm, ae_tag, ae_id, ae_name); - } - return (ARCHIVE_OK); -} -#else /* !HAVE_SUN_ACL */ -/* - * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and - * MacOS (NFSv4 only) ACLs into libarchive internal structure - */ -static int -translate_acl(struct archive_read_disk *a, - struct archive_entry *entry, acl_t acl, int default_entry_acl_type) -{ - acl_tag_t acl_tag; -#if HAVE_ACL_TYPE_NFS4 - acl_entry_type_t acl_type; - int brand; -#endif -#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL - acl_flagset_t acl_flagset; -#endif - acl_entry_t acl_entry; - acl_permset_t acl_permset; - int i, entry_acl_type; - int r, s, ae_id, ae_tag, ae_perm; -#if !HAVE_DARWIN_ACL - void *q; -#endif - const char *ae_name; - -#if HAVE_ACL_TYPE_NFS4 - // FreeBSD "brands" ACLs as POSIX.1e or NFSv4 - // Make sure the "brand" on this ACL is consistent - // with the default_entry_acl_type bits provided. - if (acl_get_brand_np(acl, &brand) != 0) { - archive_set_error(&a->archive, errno, - "Failed to read ACL brand"); - return (ARCHIVE_WARN); - } - switch (brand) { - case ACL_BRAND_POSIX: - switch (default_entry_acl_type) { - case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: - case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Invalid ACL entry type for POSIX.1e ACL"); - return (ARCHIVE_WARN); - } - break; - case ACL_BRAND_NFS4: - if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Invalid ACL entry type for NFSv4 ACL"); - return (ARCHIVE_WARN); - } - break; - default: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Unknown ACL brand"); - return (ARCHIVE_WARN); - } -#endif - - s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); - if (s == -1) { - archive_set_error(&a->archive, errno, - "Failed to get first ACL entry"); - return (ARCHIVE_WARN); - } - -#if HAVE_DARWIN_ACL - while (s == 0) -#else /* FreeBSD, Linux */ - while (s == 1) -#endif - { - ae_id = -1; - ae_name = NULL; - ae_perm = 0; - - if (acl_get_tag_type(acl_entry, &acl_tag) != 0) { - archive_set_error(&a->archive, errno, - "Failed to get ACL tag type"); - return (ARCHIVE_WARN); - } - switch (acl_tag) { -#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ - case ACL_USER: - q = acl_get_qualifier(acl_entry); - if (q != NULL) { - ae_id = (int)*(uid_t *)q; - acl_free(q); - ae_name = archive_read_disk_uname(&a->archive, - ae_id); - } - ae_tag = ARCHIVE_ENTRY_ACL_USER; - break; - case ACL_GROUP: - q = acl_get_qualifier(acl_entry); - if (q != NULL) { - ae_id = (int)*(gid_t *)q; - acl_free(q); - ae_name = archive_read_disk_gname(&a->archive, - ae_id); - } - ae_tag = ARCHIVE_ENTRY_ACL_GROUP; - break; - case ACL_MASK: - ae_tag = ARCHIVE_ENTRY_ACL_MASK; - break; - case ACL_USER_OBJ: - ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - break; - case ACL_GROUP_OBJ: - ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - break; - case ACL_OTHER: - ae_tag = ARCHIVE_ENTRY_ACL_OTHER; - break; -#if HAVE_ACL_TYPE_NFS4 - case ACL_EVERYONE: - ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; - break; -#endif -#else /* HAVE_DARWIN_ACL */ - case ACL_EXTENDED_ALLOW: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; - r = translate_guid(&a->archive, acl_entry, &ae_id, - &ae_tag, &ae_name); - break; - case ACL_EXTENDED_DENY: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; - r = translate_guid(&a->archive, acl_entry, &ae_id, - &ae_tag, &ae_name); - break; -#endif /* HAVE_DARWIN_ACL */ - default: - /* Skip types that libarchive can't support. */ - s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); - continue; - } - -#if HAVE_DARWIN_ACL - /* Skip if translate_guid() above failed */ - if (r != 0) { - s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); - continue; - } -#endif - -#if !HAVE_DARWIN_ACL - // XXX acl_type maps to allow/deny/audit/YYYY bits - entry_acl_type = default_entry_acl_type; -#endif -#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL - if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { -#if HAVE_ACL_TYPE_NFS4 - /* - * acl_get_entry_type_np() fails with non-NFSv4 ACLs - */ - if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) { - archive_set_error(&a->archive, errno, "Failed " - "to get ACL type from a NFSv4 ACL entry"); - return (ARCHIVE_WARN); - } - switch (acl_type) { - case ACL_ENTRY_TYPE_ALLOW: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; - break; - case ACL_ENTRY_TYPE_DENY: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; - break; - case ACL_ENTRY_TYPE_AUDIT: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; - break; - case ACL_ENTRY_TYPE_ALARM: - entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; - break; - default: - archive_set_error(&a->archive, errno, - "Invalid NFSv4 ACL entry type"); - return (ARCHIVE_WARN); - } -#endif /* HAVE_ACL_TYPE_NFS4 */ - - /* - * Libarchive stores "flag" (NFSv4 inheritance bits) - * in the ae_perm bitmap. - * - * acl_get_flagset_np() fails with non-NFSv4 ACLs - */ - if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { - archive_set_error(&a->archive, errno, - "Failed to get flagset from a NFSv4 ACL entry"); - return (ARCHIVE_WARN); - } - for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { - r = acl_get_flag_np(acl_flagset, - acl_inherit_map[i].platform_inherit); - if (r == -1) { - archive_set_error(&a->archive, errno, - "Failed to check flag in a NFSv4 " - "ACL flagset"); - return (ARCHIVE_WARN); - } else if (r) - ae_perm |= acl_inherit_map[i].archive_inherit; - } - } -#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */ - - if (acl_get_permset(acl_entry, &acl_permset) != 0) { - archive_set_error(&a->archive, errno, - "Failed to get ACL permission set"); - return (ARCHIVE_WARN); - } - for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { - /* - * acl_get_perm() is spelled differently on different - * platforms; see above. - */ - r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm); - if (r == -1) { - archive_set_error(&a->archive, errno, - "Failed to check permission in an ACL permission set"); - return (ARCHIVE_WARN); - } else if (r) - ae_perm |= acl_perm_map[i].archive_perm; - } - - archive_entry_acl_add_entry(entry, entry_acl_type, - ae_perm, ae_tag, - ae_id, ae_name); - - s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); -#if !HAVE_DARWIN_ACL - if (s == -1) { - archive_set_error(&a->archive, errno, - "Failed to get next ACL entry"); - return (ARCHIVE_WARN); - } -#endif - } - return (ARCHIVE_OK); -} -#endif /* !HAVE_SUN_ACL */ -#else /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */ -static int -setup_acls(struct archive_read_disk *a, - struct archive_entry *entry, int *fd) -{ - (void)a; /* UNUSED */ - (void)entry; /* UNUSED */ - (void)fd; /* UNUSED */ - return (ARCHIVE_OK); -} -#endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */ - -#if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \ - HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \ - (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA) - -/* - * Linux and AIX extended attribute support. + * Linux, Darwin and AIX extended attribute support. * * TODO: By using a stack-allocated buffer for the first * call to getxattr(), we might be able to avoid the second @@ -1433,21 +444,32 @@ setup_xattr(struct archive_read_disk *a, ssize_t size; void *value = NULL; -#if HAVE_FGETXATTR - if (fd >= 0) + + if (fd >= 0) { +#if ARCHIVE_XATTR_LINUX size = fgetxattr(fd, name, NULL, 0); - else if (!a->follow_symlinks) - size = lgetxattr(accpath, name, NULL, 0); - else - size = getxattr(accpath, name, NULL, 0); -#elif HAVE_FGETEA - if (fd >= 0) +#elif ARCHIVE_XATTR_DARWIN + size = fgetxattr(fd, name, NULL, 0, 0, 0); +#elif ARCHIVE_XATTR_AIX size = fgetea(fd, name, NULL, 0); - else if (!a->follow_symlinks) +#endif + } else if (!a->follow_symlinks) { +#if ARCHIVE_XATTR_LINUX + size = lgetxattr(accpath, name, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + size = getxattr(accpath, name, NULL, 0, 0, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX size = lgetea(accpath, name, NULL, 0); - else +#endif + } else { +#if ARCHIVE_XATTR_LINUX + size = getxattr(accpath, name, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + size = getxattr(accpath, name, NULL, 0, 0, 0); +#elif ARCHIVE_XATTR_AIX size = getea(accpath, name, NULL, 0); #endif + } if (size == -1) { archive_set_error(&a->archive, errno, @@ -1460,21 +482,32 @@ setup_xattr(struct archive_read_disk *a, return (ARCHIVE_FATAL); } -#if HAVE_FGETXATTR - if (fd >= 0) + + if (fd >= 0) { +#if ARCHIVE_XATTR_LINUX size = fgetxattr(fd, name, value, size); - else if (!a->follow_symlinks) - size = lgetxattr(accpath, name, value, size); - else - size = getxattr(accpath, name, value, size); -#elif HAVE_FGETEA - if (fd >= 0) +#elif ARCHIVE_XATTR_DARWIN + size = fgetxattr(fd, name, value, size, 0, 0); +#elif ARCHIVE_XATTR_AIX size = fgetea(fd, name, value, size); - else if (!a->follow_symlinks) +#endif + } else if (!a->follow_symlinks) { +#if ARCHIVE_XATTR_LINUX + size = lgetxattr(accpath, name, value, size); +#elif ARCHIVE_XATTR_DARWIN + size = getxattr(accpath, name, value, size, 0, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX size = lgetea(accpath, name, value, size); - else +#endif + } else { +#if ARCHIVE_XATTR_LINUX + size = getxattr(accpath, name, value, size); +#elif ARCHIVE_XATTR_DARWIN + size = getxattr(accpath, name, value, size, 0, 0); +#elif ARCHIVE_XATTR_AIX size = getea(accpath, name, value, size); #endif + } if (size == -1) { archive_set_error(&a->archive, errno, @@ -1499,38 +532,36 @@ setup_xattrs(struct archive_read_disk *a, path = NULL; if (*fd < 0) { - path = archive_entry_sourcepath(entry); - if (path == NULL || (a->tree != NULL && - a->tree_enter_working_dir(a->tree) != 0)) - path = archive_entry_pathname(entry); - if (path == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Couldn't determine file path to read " - "extended attributes"); + path = archive_read_disk_entry_setup_path(a, entry, fd); + if (path == NULL) return (ARCHIVE_WARN); - } - if (a->tree != NULL && (a->follow_symlinks || - archive_entry_filetype(entry) != AE_IFLNK)) { - *fd = a->open_on_current_dir(a->tree, - path, O_RDONLY | O_NONBLOCK); - } } -#if HAVE_FLISTXATTR - if (*fd >= 0) + if (*fd >= 0) { +#if ARCHIVE_XATTR_LINUX list_size = flistxattr(*fd, NULL, 0); - else if (!a->follow_symlinks) - list_size = llistxattr(path, NULL, 0); - else - list_size = listxattr(path, NULL, 0); -#elif HAVE_FLISTEA - if (*fd >= 0) +#elif ARCHIVE_XATTR_DARWIN + list_size = flistxattr(*fd, NULL, 0, 0); +#elif ARCHIVE_XATTR_AIX list_size = flistea(*fd, NULL, 0); - else if (!a->follow_symlinks) +#endif + } else if (!a->follow_symlinks) { +#if ARCHIVE_XATTR_LINUX + list_size = llistxattr(path, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + list_size = listxattr(path, NULL, 0, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX list_size = llistea(path, NULL, 0); - else +#endif + } else { +#if ARCHIVE_XATTR_LINUX + list_size = listxattr(path, NULL, 0); +#elif ARCHIVE_XATTR_DARWIN + list_size = listxattr(path, NULL, 0, 0); +#elif ARCHIVE_XATTR_AIX list_size = listea(path, NULL, 0); #endif + } if (list_size == -1) { if (errno == ENOTSUP || errno == ENOSYS) @@ -1548,21 +579,31 @@ setup_xattrs(struct archive_read_disk *a, return (ARCHIVE_FATAL); } -#if HAVE_FLISTXATTR - if (*fd >= 0) + if (*fd >= 0) { +#if ARCHIVE_XATTR_LINUX list_size = flistxattr(*fd, list, list_size); - else if (!a->follow_symlinks) - list_size = llistxattr(path, list, list_size); - else - list_size = listxattr(path, list, list_size); -#elif HAVE_FLISTEA - if (*fd >= 0) +#elif ARCHIVE_XATTR_DARWIN + list_size = flistxattr(*fd, list, list_size, 0); +#elif ARCHIVE_XATTR_AIX list_size = flistea(*fd, list, list_size); - else if (!a->follow_symlinks) +#endif + } else if (!a->follow_symlinks) { +#if ARCHIVE_XATTR_LINUX + list_size = llistxattr(path, list, list_size); +#elif ARCHIVE_XATTR_DARWIN + list_size = listxattr(path, list, list_size, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX list_size = llistea(path, list, list_size); - else +#endif + } else { +#if ARCHIVE_XATTR_LINUX + list_size = listxattr(path, list, list_size); +#elif ARCHIVE_XATTR_DARWIN + list_size = listxattr(path, list, list_size, 0); +#elif ARCHIVE_XATTR_AIX list_size = listea(path, list, list_size); #endif + } if (list_size == -1) { archive_set_error(&a->archive, errno, @@ -1572,9 +613,21 @@ setup_xattrs(struct archive_read_disk *a, } for (p = list; (p - list) < list_size; p += strlen(p) + 1) { - if (strncmp(p, "system.", 7) == 0 || - strncmp(p, "xfsroot.", 8) == 0) +#if ARCHIVE_XATTR_LINUX + /* Linux: skip POSIX.1e ACL extended attributes */ + if (strncmp(p, "system.", 7) == 0 && + (strcmp(p + 7, "posix_acl_access") == 0 || + strcmp(p + 7, "posix_acl_default") == 0)) + continue; + if (strncmp(p, "trusted.SGI_", 12) == 0 && + (strcmp(p + 12, "ACL_DEFAULT") == 0 || + strcmp(p + 12, "ACL_FILE") == 0)) + continue; + + /* Linux: xfsroot namespace is obsolete and unsupported */ + if (strncmp(p, "xfsroot.", 8) == 0) continue; +#endif setup_xattr(a, entry, p, *fd, path); } @@ -1582,8 +635,7 @@ setup_xattrs(struct archive_read_disk *a, return (ARCHIVE_OK); } -#elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \ - HAVE_DECL_EXTATTR_NAMESPACE_USER +#elif ARCHIVE_XATTR_FREEBSD /* * FreeBSD extattr interface. @@ -1658,21 +710,9 @@ setup_xattrs(struct archive_read_disk *a, path = NULL; if (*fd < 0) { - path = archive_entry_sourcepath(entry); - if (path == NULL || (a->tree != NULL && - a->tree_enter_working_dir(a->tree) != 0)) - path = archive_entry_pathname(entry); - if (path == NULL) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Couldn't determine file path to read " - "extended attributes"); + path = archive_read_disk_entry_setup_path(a, entry, fd); + if (path == NULL) return (ARCHIVE_WARN); - } - if (a->tree != NULL && (a->follow_symlinks || - archive_entry_filetype(entry) != AE_IFLNK)) { - *fd = a->open_on_current_dir(a->tree, - path, O_RDONLY | O_NONBLOCK); - } } if (*fd >= 0) @@ -1773,6 +813,7 @@ setup_sparse_fiemap(struct archive_read_disk *a, int64_t size; int count, do_fiemap, iters; int exit_sts = ARCHIVE_OK; + const char *path; if (archive_entry_filetype(entry) != AE_IFREG || archive_entry_size(entry) <= 0 @@ -1780,11 +821,10 @@ setup_sparse_fiemap(struct archive_read_disk *a, return (ARCHIVE_OK); if (*fd < 0) { - const char *path; - - path = archive_entry_sourcepath(entry); + path = archive_read_disk_entry_setup_path(a, entry, NULL); if (path == NULL) - path = archive_entry_pathname(entry); + return (ARCHIVE_FAILED); + if (a->tree != NULL) *fd = a->open_on_current_dir(a->tree, path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); @@ -1880,6 +920,7 @@ setup_sparse(struct archive_read_disk *a, off_t off_s, off_e; int exit_sts = ARCHIVE_OK; int check_fully_sparse = 0; + const char *path; if (archive_entry_filetype(entry) != AE_IFREG || archive_entry_size(entry) <= 0 @@ -1887,20 +928,10 @@ setup_sparse(struct archive_read_disk *a, return (ARCHIVE_OK); /* Does filesystem support the reporting of hole ? */ - if (*fd < 0 && a->tree != NULL) { - const char *path; - - path = archive_entry_sourcepath(entry); - if (path == NULL) - path = archive_entry_pathname(entry); - *fd = a->open_on_current_dir(a->tree, path, - O_RDONLY | O_NONBLOCK); - if (*fd < 0) { - archive_set_error(&a->archive, errno, - "Can't open `%s'", path); - return (ARCHIVE_FAILED); - } - } + if (*fd < 0) + path = archive_read_disk_entry_setup_path(a, entry, fd); + else + path = NULL; if (*fd >= 0) { #ifdef _PC_MIN_HOLE_SIZE @@ -1911,12 +942,8 @@ setup_sparse(struct archive_read_disk *a, if (initial_off != 0) lseek(*fd, 0, SEEK_SET); } else { - const char *path; - - path = archive_entry_sourcepath(entry); if (path == NULL) - path = archive_entry_pathname(entry); - + return (ARCHIVE_FAILED); #ifdef _PC_MIN_HOLE_SIZE if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0) return (ARCHIVE_OK); diff --git a/libarchive/archive_read_disk_private.h b/libarchive/archive_read_disk_private.h index b5a8328..f03a0a9 100644 --- a/libarchive/archive_read_disk_private.h +++ b/libarchive/archive_read_disk_private.h @@ -33,6 +33,8 @@ #ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED #define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED +#include "archive_platform_acl.h" + struct tree; struct archive_entry; @@ -86,4 +88,11 @@ struct archive_read_disk { void *excluded_cb_data; }; +const char * +archive_read_disk_entry_setup_path(struct archive_read_disk *, + struct archive_entry *, int *); + +int +archive_read_disk_entry_setup_acls(struct archive_read_disk *, + struct archive_entry *, int *); #endif diff --git a/libarchive/archive_read_format.3 b/libarchive/archive_read_format.3 index 53b9a7e..91c5d2c 100644 --- a/libarchive/archive_read_format.3 +++ b/libarchive/archive_read_format.3 @@ -37,9 +37,9 @@ .Nm archive_read_support_format_empty , .Nm archive_read_support_format_iso9660 , .Nm archive_read_support_format_lha , -.Nm archive_read_support_format_mtree, -.Nm archive_read_support_format_rar, -.Nm archive_read_support_format_raw, +.Nm archive_read_support_format_mtree , +.Nm archive_read_support_format_rar , +.Nm archive_read_support_format_raw , .Nm archive_read_support_format_tar , .Nm archive_read_support_format_xar , .Nm archive_read_support_format_zip diff --git a/libarchive/archive_read_open.3 b/libarchive/archive_read_open.3 index 4d8272c..2278ebc 100644 --- a/libarchive/archive_read_open.3 +++ b/libarchive/archive_read_open.3 @@ -33,7 +33,7 @@ .Nm archive_read_open_fd , .Nm archive_read_open_FILE , .Nm archive_read_open_filename , -.Nm archive_read_open_memory , +.Nm archive_read_open_memory .Nd functions for reading streaming archives .Sh LIBRARY Streaming Archive Library (libarchive, -larchive) @@ -67,7 +67,7 @@ Streaming Archive Library (libarchive, -larchive) .Fa "size_t block_size" .Fc .Ft int -.Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size" +.Fn archive_read_open_memory "struct archive *" "const void *buff" "size_t size" .Sh DESCRIPTION .Bl -tag -compact -width indent .It Fn archive_read_open diff --git a/libarchive/archive_read_support_filter_lz4.c b/libarchive/archive_read_support_filter_lz4.c index 663e2d3..147f502 100644 --- a/libarchive/archive_read_support_filter_lz4.c +++ b/libarchive/archive_read_support_filter_lz4.c @@ -494,7 +494,7 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p) if (read_buf == NULL) goto truncated_error; compressed_size = archive_le32dec(read_buf); - if ((compressed_size & ~(1 << 31)) > state->flags.block_maximum_size) + if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size) goto malformed_error; /* A compressed size == 0 means the end of stream blocks. */ if (compressed_size == 0) { @@ -504,8 +504,8 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p) checksum_size = state->flags.block_checksum; /* Check if the block is uncompressed. */ - if (compressed_size & (1 << 31)) { - compressed_size &= ~(1 << 31); + if (compressed_size & 0x80000000U) { + compressed_size &= 0x7fffffff; uncompressed_size = compressed_size; } else uncompressed_size = 0;/* Unknown yet. */ diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c index e2f8c6b..e5ff5a1 100644 --- a/libarchive/archive_read_support_format_cab.c +++ b/libarchive/archive_read_support_format_cab.c @@ -116,19 +116,11 @@ struct lzx_dec { * coding tree, which is a binary tree. But a use of a large * index table causes L1 cache read miss many times. */ -#define HTBL_BITS 10 int max_bits; - int shift_bits; int tbl_bits; int tree_used; - int tree_avail; /* Direct access table. */ uint16_t *tbl; - /* Binary tree table for extra bits over the direct access. */ - struct htree_t { - uint16_t left; - uint16_t right; - } *tree; } at, lt, mt, pt; int loop; @@ -187,7 +179,7 @@ struct lzx_stream { #define CFDATA_cbData 4 #define CFDATA_cbUncomp 6 -static const char *compression_name[] = { +static const char * const compression_name[] = { "NONE", "MSZIP", "Quantum", @@ -352,7 +344,6 @@ static int lzx_huffman_init(struct huffman *, size_t, int); static void lzx_huffman_free(struct huffman *); static int lzx_make_huffman_table(struct huffman *); static inline int lzx_decode_huffman(struct huffman *, unsigned); -static int lzx_decode_huffman_tree(struct huffman *, unsigned, int); int @@ -3127,7 +3118,6 @@ getdata: static int lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits) { - int bits; if (hf->bitlen == NULL || hf->len_size != (int)len_size) { free(hf->bitlen); @@ -3138,21 +3128,11 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits) } else memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0])); if (hf->tbl == NULL) { - if (tbl_bits < HTBL_BITS) - bits = tbl_bits; - else - bits = HTBL_BITS; - hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0])); + hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0])); if (hf->tbl == NULL) return (ARCHIVE_FATAL); hf->tbl_bits = tbl_bits; } - if (hf->tree == NULL && tbl_bits > HTBL_BITS) { - hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4); - hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0])); - if (hf->tree == NULL) - return (ARCHIVE_FATAL); - } return (ARCHIVE_OK); } @@ -3161,7 +3141,6 @@ lzx_huffman_free(struct huffman *hf) { free(hf->bitlen); free(hf->tbl); - free(hf->tree); } /* @@ -3174,7 +3153,7 @@ lzx_make_huffman_table(struct huffman *hf) const unsigned char *bitlen; int bitptn[17], weight[17]; int i, maxbits = 0, ptn, tbl_size, w; - int diffbits, len_avail; + int len_avail; /* * Initialize bit patterns. @@ -3205,28 +3184,11 @@ lzx_make_huffman_table(struct huffman *hf) weight[i] >>= ebits; } } - if (maxbits > HTBL_BITS) { - int htbl_max; - uint16_t *p; - - diffbits = maxbits - HTBL_BITS; - for (i = 1; i <= HTBL_BITS; i++) { - bitptn[i] >>= diffbits; - weight[i] >>= diffbits; - } - htbl_max = bitptn[HTBL_BITS] + - weight[HTBL_BITS] * hf->freq[HTBL_BITS]; - p = &(hf->tbl[htbl_max]); - while (p < &hf->tbl[1U<shift_bits = diffbits; /* * Make the table. */ - tbl_size = 1 << HTBL_BITS; + tbl_size = 1 << hf->tbl_bits; tbl = hf->tbl; bitlen = hf->bitlen; len_avail = hf->len_size; @@ -3234,120 +3196,32 @@ lzx_make_huffman_table(struct huffman *hf) for (i = 0; i < len_avail; i++) { uint16_t *p; int len, cnt; - uint16_t bit; - int extlen; - struct htree_t *ht; if (bitlen[i] == 0) continue; /* Get a bit pattern */ len = bitlen[i]; + if (len > tbl_size) + return (0); ptn = bitptn[len]; cnt = weight[len]; - if (len <= HTBL_BITS) { - /* Calculate next bit pattern */ - if ((bitptn[len] = ptn + cnt) > tbl_size) - return (0);/* Invalid */ - /* Update the table */ - p = &(tbl[ptn]); - while (--cnt >= 0) - p[cnt] = (uint16_t)i; - continue; - } - - /* - * A bit length is too big to be housed to a direct table, - * so we use a tree model for its extra bits. - */ - bitptn[len] = ptn + cnt; - bit = 1U << (diffbits -1); - extlen = len - HTBL_BITS; - - p = &(tbl[ptn >> diffbits]); - if (*p == 0) { - *p = len_avail + hf->tree_used; - ht = &(hf->tree[hf->tree_used++]); - if (hf->tree_used > hf->tree_avail) - return (0);/* Invalid */ - ht->left = 0; - ht->right = 0; - } else { - if (*p < len_avail || - *p >= (len_avail + hf->tree_used)) - return (0);/* Invalid */ - ht = &(hf->tree[*p - len_avail]); - } - while (--extlen > 0) { - if (ptn & bit) { - if (ht->left < len_avail) { - ht->left = len_avail + hf->tree_used; - ht = &(hf->tree[hf->tree_used++]); - if (hf->tree_used > hf->tree_avail) - return (0);/* Invalid */ - ht->left = 0; - ht->right = 0; - } else { - ht = &(hf->tree[ht->left - len_avail]); - } - } else { - if (ht->right < len_avail) { - ht->right = len_avail + hf->tree_used; - ht = &(hf->tree[hf->tree_used++]); - if (hf->tree_used > hf->tree_avail) - return (0);/* Invalid */ - ht->left = 0; - ht->right = 0; - } else { - ht = &(hf->tree[ht->right - len_avail]); - } - } - bit >>= 1; - } - if (ptn & bit) { - if (ht->left != 0) - return (0);/* Invalid */ - ht->left = (uint16_t)i; - } else { - if (ht->right != 0) - return (0);/* Invalid */ - ht->right = (uint16_t)i; - } + /* Calculate next bit pattern */ + if ((bitptn[len] = ptn + cnt) > tbl_size) + return (0);/* Invalid */ + /* Update the table */ + p = &(tbl[ptn]); + while (--cnt >= 0) + p[cnt] = (uint16_t)i; } return (1); } -static int -lzx_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c) -{ - struct htree_t *ht; - int extlen; - - ht = hf->tree; - extlen = hf->shift_bits; - while (c >= hf->len_size) { - c -= hf->len_size; - if (extlen-- <= 0 || c >= hf->tree_used) - return (0); - if (rbits & (1U << extlen)) - c = ht[c].left; - else - c = ht[c].right; - } - return (c); -} - static inline int lzx_decode_huffman(struct huffman *hf, unsigned rbits) { int c; - /* - * At first search an index table for a bit pattern. - * If it fails, search a huffman tree for. - */ - c = hf->tbl[rbits >> hf->shift_bits]; + c = hf->tbl[rbits]; if (c < hf->len_size) return (c); - /* This bit pattern needs to be found out at a huffman tree. */ - return (lzx_decode_huffman_tree(hf, rbits, c)); + return (0); } - diff --git a/libarchive/archive_read_support_format_cpio.c b/libarchive/archive_read_support_format_cpio.c index ffd4a85..ad9f782 100644 --- a/libarchive/archive_read_support_format_cpio.c +++ b/libarchive/archive_read_support_format_cpio.c @@ -165,7 +165,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_cpio.c 20116 struct links_entry { struct links_entry *next; struct links_entry *previous; - int links; + unsigned int links; dev_t dev; int64_t ino; char *name; diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c index 76da406..f01d37b 100644 --- a/libarchive/archive_read_support_format_iso9660.c +++ b/libarchive/archive_read_support_format_iso9660.c @@ -3021,8 +3021,9 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } - memcpy(new_pending_files, heap->files, - heap->allocated * sizeof(new_pending_files[0])); + if (heap->allocated) + memcpy(new_pending_files, heap->files, + heap->allocated * sizeof(new_pending_files[0])); if (heap->files != NULL) free(heap->files); heap->files = new_pending_files; diff --git a/libarchive/archive_read_support_format_lha.c b/libarchive/archive_read_support_format_lha.c index d77a7c2..b8ef4ae 100644 --- a/libarchive/archive_read_support_format_lha.c +++ b/libarchive/archive_read_support_format_lha.c @@ -2477,7 +2477,7 @@ lzh_huffman_free(struct huffman *hf) free(hf->tree); } -static char bitlen_tbl[0x400] = { +static const char bitlen_tbl[0x400] = { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c index 4231ff5..44b6083 100644 --- a/libarchive/archive_read_support_format_mtree.c +++ b/libarchive/archive_read_support_format_mtree.c @@ -130,9 +130,7 @@ static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t) static int skip(struct archive_read *a); static int read_header(struct archive_read *, struct archive_entry *); -static int64_t mtree_atol10(char **); -static int64_t mtree_atol8(char **); -static int64_t mtree_atol(char **); +static int64_t mtree_atol(char **, int base); /* * There's no standard for TIME_T_MAX/TIME_T_MIN. So we compute them @@ -399,41 +397,41 @@ bid_keycmp(const char *p, const char *key, ssize_t len) static int bid_keyword(const char *p, ssize_t len) { - static const char *keys_c[] = { + static const char * const keys_c[] = { "content", "contents", "cksum", NULL }; - static const char *keys_df[] = { + static const char * const keys_df[] = { "device", "flags", NULL }; - static const char *keys_g[] = { + static const char * const keys_g[] = { "gid", "gname", NULL }; - static const char *keys_il[] = { + static const char * const keys_il[] = { "ignore", "inode", "link", NULL }; - static const char *keys_m[] = { + static const char * const keys_m[] = { "md5", "md5digest", "mode", NULL }; - static const char *keys_no[] = { + static const char * const keys_no[] = { "nlink", "nochange", "optional", NULL }; - static const char *keys_r[] = { + static const char * const keys_r[] = { "resdevice", "rmd160", "rmd160digest", NULL }; - static const char *keys_s[] = { + static const char * const keys_s[] = { "sha1", "sha1digest", "sha256", "sha256digest", "sha384", "sha384digest", "sha512", "sha512digest", "size", NULL }; - static const char *keys_t[] = { + static const char * const keys_t[] = { "tags", "time", "type", NULL }; - static const char *keys_u[] = { + static const char * const keys_u[] = { "uid", "uname", NULL }; - const char **keys; + const char * const *keys; int i; switch (*p) { @@ -1418,7 +1416,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val) "Too many arguments"); return ARCHIVE_WARN; } - numbers[argc++] = (unsigned long)mtree_atol(&p); + numbers[argc++] = (unsigned long)mtree_atol(&p, 0); } if (argc < 2) { archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, @@ -1433,7 +1431,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val) } } else { /* file system raw value. */ - result = (dev_t)mtree_atol(&val); + result = (dev_t)mtree_atol(&val, 0); } *pdev = result; return ARCHIVE_OK; @@ -1513,7 +1511,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, case 'g': if (strcmp(key, "gid") == 0) { *parsed_kws |= MTREE_HAS_GID; - archive_entry_set_gid(entry, mtree_atol10(&val)); + archive_entry_set_gid(entry, mtree_atol(&val, 10)); break; } if (strcmp(key, "gname") == 0) { @@ -1523,7 +1521,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, } case 'i': if (strcmp(key, "inode") == 0) { - archive_entry_set_ino(entry, mtree_atol10(&val)); + archive_entry_set_ino(entry, mtree_atol(&val, 10)); break; } case 'l': @@ -1535,14 +1533,14 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) break; if (strcmp(key, "mode") == 0) { - if (val[0] >= '0' && val[0] <= '9') { + if (val[0] >= '0' && val[0] <= '7') { *parsed_kws |= MTREE_HAS_PERM; archive_entry_set_perm(entry, - (mode_t)mtree_atol8(&val)); + (mode_t)mtree_atol(&val, 8)); } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, - "Symbolic mode \"%s\" unsupported", val); + "Symbolic or non-octal mode \"%s\" unsupported", val); return ARCHIVE_WARN; } break; @@ -1551,7 +1549,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, if (strcmp(key, "nlink") == 0) { *parsed_kws |= MTREE_HAS_NLINK; archive_entry_set_nlink(entry, - (unsigned int)mtree_atol10(&val)); + (unsigned int)mtree_atol(&val, 10)); break; } case 'r': @@ -1582,7 +1580,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, strcmp(key, "sha512digest") == 0) break; if (strcmp(key, "size") == 0) { - archive_entry_set_size(entry, mtree_atol10(&val)); + archive_entry_set_size(entry, mtree_atol(&val, 10)); break; } case 't': @@ -1601,13 +1599,13 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, long ns = 0; *parsed_kws |= MTREE_HAS_MTIME; - m = mtree_atol10(&val); + m = mtree_atol(&val, 10); /* Replicate an old mtree bug: * 123456789.1 represents 123456789 * seconds and 1 nanosecond. */ if (*val == '.') { ++val; - ns = (long)mtree_atol10(&val); + ns = (long)mtree_atol(&val, 10); if (ns < 0) ns = 0; else if (ns > 999999999) @@ -1670,7 +1668,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, case 'u': if (strcmp(key, "uid") == 0) { *parsed_kws |= MTREE_HAS_UID; - archive_entry_set_uid(entry, mtree_atol10(&val)); + archive_entry_set_uid(entry, mtree_atol(&val, 10)); break; } if (strcmp(key, "uname") == 0) { @@ -1825,72 +1823,9 @@ parse_escapes(char *src, struct mtree_entry *mentry) *dest = '\0'; } -/* - * Note that this implementation does not (and should not!) obey - * locale settings; you cannot simply substitute strtol here, since - * it does obey locale. - */ -static int64_t -mtree_atol8(char **p) -{ - int64_t l, limit, last_digit_limit; - int digit, base; - - base = 8; - limit = INT64_MAX / base; - last_digit_limit = INT64_MAX % base; - - l = 0; - digit = **p - '0'; - while (digit >= 0 && digit < base) { - if (l>limit || (l == limit && digit > last_digit_limit)) { - l = INT64_MAX; /* Truncate on overflow. */ - break; - } - l = (l * base) + digit; - digit = *++(*p) - '0'; - } - return (l); -} - -/* - * Note that this implementation does not (and should not!) obey - * locale settings; you cannot simply substitute strtol here, since - * it does obey locale. - */ -static int64_t -mtree_atol10(char **p) -{ - int64_t l, limit, last_digit_limit; - int base, digit, sign; - - base = 10; - - if (**p == '-') { - sign = -1; - limit = ((uint64_t)(INT64_MAX) + 1) / base; - last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base; - ++(*p); - } else { - sign = 1; - limit = INT64_MAX / base; - last_digit_limit = INT64_MAX % base; - } - - l = 0; - digit = **p - '0'; - while (digit >= 0 && digit < base) { - if (l > limit || (l == limit && digit > last_digit_limit)) - return (sign < 0) ? INT64_MIN : INT64_MAX; - l = (l * base) + digit; - digit = *++(*p) - '0'; - } - return (sign < 0) ? -l : l; -} - /* Parse a hex digit. */ static int -parsehex(char c) +parsedigit(char c) { if (c >= '0' && c <= '9') return c - '0'; @@ -1908,45 +1843,50 @@ parsehex(char c) * it does obey locale. */ static int64_t -mtree_atol16(char **p) +mtree_atol(char **p, int base) { - int64_t l, limit, last_digit_limit; - int base, digit, sign; - - base = 16; + int64_t l, limit; + int digit, last_digit_limit; + + if (base == 0) { + if (**p != '0') + base = 10; + else if ((*p)[1] == 'x' || (*p)[1] == 'X') { + *p += 2; + base = 16; + } else { + base = 8; + } + } if (**p == '-') { - sign = -1; - limit = ((uint64_t)(INT64_MAX) + 1) / base; - last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base; + 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)) + return INT64_MIN; + l = (l * base) - digit; + digit = parsedigit(*++(*p)); + } + return l; } else { - sign = 1; limit = INT64_MAX / base; last_digit_limit = INT64_MAX % base; - } - l = 0; - digit = parsehex(**p); - while (digit >= 0 && digit < base) { - if (l > limit || (l == limit && digit > last_digit_limit)) - return (sign < 0) ? INT64_MIN : INT64_MAX; - l = (l * base) + digit; - digit = parsehex(*++(*p)); - } - return (sign < 0) ? -l : l; -} - -static int64_t -mtree_atol(char **p) -{ - if (**p != '0') - return mtree_atol10(p); - if ((*p)[1] == 'x' || (*p)[1] == 'X') { - *p += 2; - return mtree_atol16(p); + l = 0; + digit = parsedigit(**p); + while (digit >= 0 && digit < base) { + if (l > limit || (l == limit && digit > last_digit_limit)) + return INT64_MAX; + l = (l * base) + digit; + digit = parsedigit(*++(*p)); + } + return l; } - return mtree_atol8(p); } /* diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c index 1e9849f..cbb14c3 100644 --- a/libarchive/archive_read_support_format_rar.c +++ b/libarchive/archive_read_support_format_rar.c @@ -1750,7 +1750,7 @@ read_exttime(const char *p, struct rar *rar, const char *endp) return (-1); for (j = 0; j < count; j++) { - rem = ((*p) << 16) | (rem >> 8); + rem = (((unsigned)(unsigned char)*p) << 16) | (rem >> 8); p++; } tm = localtime(&t); diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index bd7f13d..30d5bc8 100644 --- a/libarchive/archive_read_support_format_tar.c +++ b/libarchive/archive_read_support_format_tar.c @@ -155,6 +155,7 @@ struct tar { int compat_2x; int process_mac_extensions; int read_concatenated_archives; + int realsize_override; }; static int archive_block_is_null(const char *p); @@ -527,6 +528,7 @@ archive_read_format_tar_read_header(struct archive_read *a, tar->entry_offset = 0; gnu_clear_sparse_list(tar); tar->realsize = -1; /* Mark this as "unset" */ + tar->realsize_override = 0; /* Setup default string conversion. */ tar->sconv = tar->opt_sconv; @@ -1894,6 +1896,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, if (strcmp(key, "GNU.sparse.size") == 0) { tar->realsize = tar_atol10(value, strlen(value)); archive_entry_set_size(entry, tar->realsize); + tar->realsize_override = 1; } /* GNU "0.1" sparse pax format. */ @@ -1925,6 +1928,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, if (strcmp(key, "GNU.sparse.realsize") == 0) { tar->realsize = tar_atol10(value, strlen(value)); archive_entry_set_size(entry, tar->realsize); + tar->realsize_override = 1; } break; case 'L': @@ -1977,6 +1981,7 @@ pax_attribute(struct archive_read *a, struct tar *tar, tar_atol10(value, strlen(value))); } else if (strcmp(key, "SCHILY.realsize") == 0) { tar->realsize = tar_atol10(value, strlen(value)); + tar->realsize_override = 1; archive_entry_set_size(entry, tar->realsize); } else if (strncmp(key, "SCHILY.xattr.", 13) == 0) { pax_attribute_schily_xattr(entry, key, value, @@ -2055,14 +2060,12 @@ pax_attribute(struct archive_read *a, struct tar *tar, tar->entry_bytes_remaining = tar_atol10(value, strlen(value)); /* - * But, "size" is not necessarily the size of - * the file on disk; if this is a sparse file, - * the disk size may have already been set from - * GNU.sparse.realsize or GNU.sparse.size or - * an old GNU header field or SCHILY.realsize - * or .... + * The "size" pax header keyword always overrides the + * "size" field in the tar header. + * GNU.sparse.realsize, GNU.sparse.size and + * SCHILY.realsize override this value. */ - if (tar->realsize < 0) { + if (!tar->realsize_override) { archive_entry_set_size(entry, tar->entry_bytes_remaining); tar->realsize @@ -2206,6 +2209,7 @@ header_gnutar(struct archive_read *a, struct tar *tar, tar->realsize = tar_atol(header->realsize, sizeof(header->realsize)); archive_entry_set_size(entry, tar->realsize); + tar->realsize_override = 1; } if (header->sparse[0].offset[0] != 0) { diff --git a/libarchive/archive_read_support_format_warc.c b/libarchive/archive_read_support_format_warc.c index b162465..e875385 100644 --- a/libarchive/archive_read_support_format_warc.c +++ b/libarchive/archive_read_support_format_warc.c @@ -600,9 +600,10 @@ _warc_rdver(const char *buf, size_t bsz) /* looks good so far, read the version number for a laugh */ buf += sizeof(magic) - 1U; - if (isdigit(buf[0U]) && (buf[1U] == '.') && isdigit(buf[2U])) { + if (isdigit((unsigned char)buf[0U]) && (buf[1U] == '.') && + isdigit((unsigned char)buf[2U])) { /* we support a maximum of 2 digits in the minor version */ - if (isdigit(buf[3U])) + if (isdigit((unsigned char)buf[3U])) end = 1U; /* set up major version */ ver = (buf[0U] - '0') * 10000U; @@ -686,7 +687,7 @@ _warc_rduri(const char *buf, size_t bsz) /* spaces inside uri are not allowed, CRLF should follow */ for (p = val; p < eol; p++) { - if (isspace(*p)) + if (isspace((unsigned char)*p)) return res; } @@ -736,7 +737,7 @@ _warc_rdlen(const char *buf, size_t bsz) while (val < eol && (*val == ' ' || *val == '\t')) val++; /* there must be at least one digit */ - if (!isdigit(*val)) + if (!isdigit((unsigned char)*val)) return -1; len = strtol(val, &on, 10); if (on != eol) { diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c index 08bcf1f..4c4f6fa 100644 --- a/libarchive/archive_read_support_format_zip.c +++ b/libarchive/archive_read_support_format_zip.c @@ -347,7 +347,7 @@ fake_crc32(unsigned long crc, const void *buff, size_t len) return 0; } -static struct { +static const struct { int id; const char * name; } compression_methods[] = { @@ -2407,7 +2407,7 @@ read_eocd(struct zip *zip, const char *p, int64_t current_offset) * Examine Zip64 EOCD locator: If it's valid, store the information * from it. */ -static void +static int read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p) { int64_t eocd64_offset; @@ -2417,35 +2417,37 @@ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p) /* Central dir must be on first volume. */ if (archive_le32dec(p + 4) != 0) - return; + return 0; /* Must be only a single volume. */ if (archive_le32dec(p + 16) != 1) - return; + return 0; /* Find the Zip64 EOCD record. */ eocd64_offset = archive_le64dec(p + 8); if (__archive_read_seek(a, eocd64_offset, SEEK_SET) < 0) - return; + return 0; if ((p = __archive_read_ahead(a, 56, NULL)) == NULL) - return; + return 0; /* Make sure we can read all of it. */ eocd64_size = archive_le64dec(p + 4) + 12; if (eocd64_size < 56 || eocd64_size > 16384) - return; + return 0; if ((p = __archive_read_ahead(a, (size_t)eocd64_size, NULL)) == NULL) - return; + return 0; /* Sanity-check the EOCD64 */ if (archive_le32dec(p + 16) != 0) /* Must be disk #0 */ - return; + return 0; if (archive_le32dec(p + 20) != 0) /* CD must be on disk #0 */ - return; + return 0; /* CD can't be split. */ if (archive_le64dec(p + 24) != archive_le64dec(p + 32)) - return; + return 0; /* Save the central directory offset for later use. */ zip->central_directory_offset = archive_le64dec(p + 48); + + return 32; } static int @@ -2483,15 +2485,14 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid) if (memcmp(p + i, "PK\005\006", 4) == 0) { int ret = read_eocd(zip, p + i, current_offset + i); - if (ret > 0) { - /* Zip64 EOCD locator precedes - * regular EOCD if present. */ - if (i >= 20 - && memcmp(p + i - 20, "PK\006\007", 4) == 0) { - read_zip64_eocd(a, zip, p + i - 20); - } - return (ret); + /* Zip64 EOCD locator precedes + * regular EOCD if present. */ + if (i >= 20 && memcmp(p + i - 20, "PK\006\007", 4) == 0) { + int ret_zip64 = read_zip64_eocd(a, zip, p + i - 20); + if (ret_zip64 > ret) + ret = ret_zip64; } + return (ret); } i -= 4; break; diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c index 592ead2..5ae09b6 100644 --- a/libarchive/archive_string.c +++ b/libarchive/archive_string.c @@ -202,7 +202,8 @@ archive_string_append(struct archive_string *as, const char *p, size_t s) { if (archive_string_ensure(as, as->length + s + 1) == NULL) return (NULL); - memmove(as->s + as->length, p, s); + if (s) + memmove(as->s + as->length, p, s); as->length += s; as->s[as->length] = 0; return (as); diff --git a/libarchive/archive_string_sprintf.c b/libarchive/archive_string_sprintf.c index 964ea2b..969a560 100644 --- a/libarchive/archive_string_sprintf.c +++ b/libarchive/archive_string_sprintf.c @@ -53,7 +53,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string_sprintf.c 189435 2009-03- static void append_uint(struct archive_string *as, uintmax_t d, unsigned base) { - static const char *digits = "0123456789abcdef"; + static const char digits[] = "0123456789abcdef"; if (d >= base) append_uint(as, d/base, base); archive_strappend_char(as, digits[d % base]); diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c index 6b3bd61..bac9ba1 100644 --- a/libarchive/archive_util.c +++ b/libarchive/archive_util.c @@ -89,88 +89,6 @@ archive_version_string(void) return (ARCHIVE_VERSION_STRING); } -const char * -archive_version_details(void) -{ - static struct archive_string str; - static int init = 0; - const char *zlib = archive_zlib_version(); - const char *liblzma = archive_liblzma_version(); - const char *bzlib = archive_bzlib_version(); - const char *liblz4 = archive_liblz4_version(); - - if (!init) { - archive_string_init(&str); - - archive_strcat(&str, ARCHIVE_VERSION_STRING); - if (zlib != NULL) { - archive_strcat(&str, " zlib/"); - archive_strcat(&str, zlib); - } - if (liblzma) { - archive_strcat(&str, " liblzma/"); - archive_strcat(&str, liblzma); - } - if (bzlib) { - const char *p = bzlib; - const char *sep = strchr(p, ','); - if (sep == NULL) - sep = p + strlen(p); - archive_strcat(&str, " bz2lib/"); - archive_strncat(&str, p, sep - p); - } - if (liblz4) { - archive_strcat(&str, " liblz4/"); - archive_strcat(&str, liblz4); - } - } - return str.s; -} - -const char * -archive_zlib_version(void) -{ -#ifdef HAVE_ZLIB_H - return ZLIB_VERSION; -#else - return NULL; -#endif -} - -const char * -archive_liblzma_version(void) -{ -#ifdef HAVE_LZMA_H - return LZMA_VERSION_STRING; -#else - return NULL; -#endif -} - -const char * -archive_bzlib_version(void) -{ -#ifdef HAVE_BZLIB_H - return BZ2_bzlibVersion(); -#else - return NULL; -#endif -} - -const char * -archive_liblz4_version(void) -{ -#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4) -#define str(s) #s -#define NUMBER(x) str(x) - return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE); -#undef NUMBER -#undef str -#else - return NULL; -#endif -} - int archive_errno(struct archive *a) { @@ -275,7 +193,7 @@ archive_copy_error(struct archive *dest, struct archive *src) void __archive_errx(int retvalue, const char *msg) { - static const char *msg1 = "Fatal Internal Error in libarchive: "; + static const char msg1[] = "Fatal Internal Error in libarchive: "; size_t s; s = write(2, msg1, strlen(msg1)); @@ -303,8 +221,8 @@ __archive_errx(int retvalue, const char *msg) int __archive_mktemp(const char *tmpdir) { - static const wchar_t *prefix = L"libarchive_"; - static const wchar_t *suffix = L"XXXXXXXXXX"; + static const wchar_t prefix[] = L"libarchive_"; + static const wchar_t suffix[] = L"XXXXXXXXXX"; static const wchar_t num[] = { L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F', diff --git a/libarchive/archive_version_details.c b/libarchive/archive_version_details.c new file mode 100644 index 0000000..813f0f3 --- /dev/null +++ b/libarchive/archive_version_details.c @@ -0,0 +1,133 @@ +/*- + * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "archive_platform.h" +__FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $"); + +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_ZLIB_H +#include +#endif +#ifdef HAVE_LZMA_H +#include +#endif +#ifdef HAVE_BZLIB_H +#include +#endif +#ifdef HAVE_LZ4_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_string.h" + +const char * +archive_version_details(void) +{ + static struct archive_string str; + static int init = 0; + const char *zlib = archive_zlib_version(); + const char *liblzma = archive_liblzma_version(); + const char *bzlib = archive_bzlib_version(); + const char *liblz4 = archive_liblz4_version(); + + if (!init) { + archive_string_init(&str); + + archive_strcat(&str, ARCHIVE_VERSION_STRING); + if (zlib != NULL) { + archive_strcat(&str, " zlib/"); + archive_strcat(&str, zlib); + } + if (liblzma) { + archive_strcat(&str, " liblzma/"); + archive_strcat(&str, liblzma); + } + if (bzlib) { + const char *p = bzlib; + const char *sep = strchr(p, ','); + if (sep == NULL) + sep = p + strlen(p); + archive_strcat(&str, " bz2lib/"); + archive_strncat(&str, p, sep - p); + } + if (liblz4) { + archive_strcat(&str, " liblz4/"); + archive_strcat(&str, liblz4); + } + } + return str.s; +} + +const char * +archive_zlib_version(void) +{ +#ifdef HAVE_ZLIB_H + return ZLIB_VERSION; +#else + return NULL; +#endif +} + +const char * +archive_liblzma_version(void) +{ +#ifdef HAVE_LZMA_H + return LZMA_VERSION_STRING; +#else + return NULL; +#endif +} + +const char * +archive_bzlib_version(void) +{ +#ifdef HAVE_BZLIB_H + return BZ2_bzlibVersion(); +#else + return NULL; +#endif +} + +const char * +archive_liblz4_version(void) +{ +#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4) +#define str(s) #s +#define NUMBER(x) str(x) + return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE); +#undef NUMBER +#undef str +#else + return NULL; +#endif +} diff --git a/libarchive/archive_write_add_filter.c b/libarchive/archive_write_add_filter.c index ad5dc83..08f518a 100644 --- a/libarchive/archive_write_add_filter.c +++ b/libarchive/archive_write_add_filter.c @@ -38,7 +38,7 @@ __FBSDID("$FreeBSD$"); #include "archive_private.h" /* A table that maps filter codes to functions. */ -static +static const struct { int code; int (*setter)(struct archive *); } codes[] = { { ARCHIVE_FILTER_NONE, archive_write_add_filter_none }, diff --git a/libarchive/archive_write_add_filter_by_name.c b/libarchive/archive_write_add_filter_by_name.c index eac4011..85a8d47 100644 --- a/libarchive/archive_write_add_filter_by_name.c +++ b/libarchive/archive_write_add_filter_by_name.c @@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$"); #include "archive_private.h" /* A table that maps names to functions. */ -static +static const struct { const char *name; int (*setter)(struct archive *); } names[] = { { "b64encode", archive_write_add_filter_b64encode }, diff --git a/libarchive/archive_write_add_filter_lz4.c b/libarchive/archive_write_add_filter_lz4.c index e655185..15fd494 100644 --- a/libarchive/archive_write_add_filter_lz4.c +++ b/libarchive/archive_write_add_filter_lz4.c @@ -225,7 +225,7 @@ archive_filter_lz4_open(struct archive_write_filter *f) struct private_data *data = (struct private_data *)f->data; int ret; size_t required_size; - static size_t bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024, + static size_t const bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024, 4 * 1024 * 1024 }; size_t pre_block_size; diff --git a/libarchive/archive_write_add_filter_program.c b/libarchive/archive_write_add_filter_program.c index 55b5e8e..660f693 100644 --- a/libarchive/archive_write_add_filter_program.c +++ b/libarchive/archive_write_add_filter_program.c @@ -92,7 +92,7 @@ archive_write_add_filter_program(struct archive *_a, const char *cmd) { struct archive_write_filter *f = __archive_write_allocate_filter(_a); struct private_data *data; - static const char *prefix = "Program: "; + static const char prefix[] = "Program: "; archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_add_filter_program"); diff --git a/libarchive/archive_write_data.3 b/libarchive/archive_write_data.3 index 0cdd25f..9c16cd9 100644 --- a/libarchive/archive_write_data.3 +++ b/libarchive/archive_write_data.3 @@ -24,11 +24,12 @@ .\" .\" $FreeBSD$ .\" -.Dd February 2, 2012 +.Dd February 28, 2017 .Dt ARCHIVE_WRITE_DATA 3 .Os .Sh NAME -.Nm archive_write_data +.Nm archive_write_data , +.Nm archive_write_data_block .Nd functions for creating archives .Sh LIBRARY Streaming Archive Library (libarchive, -larchive) @@ -36,8 +37,27 @@ Streaming Archive Library (libarchive, -larchive) .In archive.h .Ft la_ssize_t .Fn archive_write_data "struct archive *" "const void *" "size_t" +.Ft la_ssize_t +.Fn archive_write_data_block "struct archive *" "const void *" "size_t size" "int64_t offset" .Sh DESCRIPTION +.Bl -tag -width indent +.It Fn archive_write_data +Write data corresponding to the header just written. +.It Fn archive_write_data_block Write data corresponding to the header just written. +This is like +.Fn archive_write_data +except that it performs a seek on the file being +written to the specified offset before writing the data. +This is useful when restoring sparse files from archive +formats that support sparse files. +Returns number of bytes written or -1 on error. +(Note: This is currently not supported for +.Tn archive_write +handles, only for +.Tn archive_write_disk +handles. +.El .\" .Sh EXAMPLE .\" .Sh RETURN VALUES diff --git a/libarchive/archive_write_disk.3 b/libarchive/archive_write_disk.3 index ba6c970..949c9ef 100644 --- a/libarchive/archive_write_disk.3 +++ b/libarchive/archive_write_disk.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 2, 2012 +.Dd April 3, 2017 .Dt ARCHIVE_WRITE_DISK 3 .Os .Sh NAME @@ -33,14 +33,7 @@ .Nm archive_write_disk_set_skip_file , .Nm archive_write_disk_set_group_lookup , .Nm archive_write_disk_set_standard_lookup , -.Nm archive_write_disk_set_user_lookup , -.Nm archive_write_header , -.Nm archive_write_data , -.Nm archive_write_data_block , -.Nm archive_write_finish_entry , -.Nm archive_write_close , -.Nm archive_write_finish -.Nm archive_write_free +.Nm archive_write_disk_set_user_lookup .Nd functions for creating objects on disk .Sh LIBRARY Streaming Archive Library (libarchive, -larchive) @@ -68,20 +61,6 @@ Streaming Archive Library (libarchive, -larchive) .Fa "uid_t (*)(void *, const char *uname, uid_t uid)" .Fa "void (*cleanup)(void *)" .Fc -.Ft int -.Fn archive_write_header "struct archive *" "struct archive_entry *" -.Ft la_ssize_t -.Fn archive_write_data "struct archive *" "const void *" "size_t" -.Ft la_ssize_t -.Fn archive_write_data_block "struct archive *" "const void *" "size_t size" "int64_t offset" -.Ft int -.Fn archive_write_finish_entry "struct archive *" -.Ft int -.Fn archive_write_close "struct archive *" -.Ft int -.Fn archive_write_finish "struct archive *" -.Ft int -.Fn archive_write_free "struct archive *" .Sh DESCRIPTION These functions provide a complete API for creating objects on disk from @@ -117,6 +96,33 @@ performance optimization in practice. The options field consists of a bitwise OR of one or more of the following values: .Bl -tag -compact -width "indent" +.It Cm ARCHIVE_EXTRACT_ACL +Attempt to restore Access Control Lists. +By default, extended ACLs are ignored. +.It Cm ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS +Before removing a file system object prior to replacing it, clear +platform-specific file flags which might prevent its removal. +.It Cm ARCHIVE_EXTRACT_FFLAGS +Attempt to restore file attributes (file flags). +By default, file attributes are ignored. +See +.Xr chattr 1 +.Pq Linux +or +.Xr chflags 1 +.Pq FreeBSD, Mac OS X +for more information on file attributes. +.It Cm ARCHIVE_EXTRACT_MAC_METADATA +Mac OS X specific. Restore metadata using +.Xr copyfile 3 . +By default, +.Xr copyfile 3 +metadata is ignored. +.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE +Existing files on disk will not be overwritten. +By default, existing regular files are truncated and overwritten; +existing directories will have their permissions updated; +other pre-existing objects are unlinked and recreated from scratch. .It Cm ARCHIVE_EXTRACT_OWNER The user and group IDs should be set on the restored file. By default, the user and group IDs are not restored. @@ -132,15 +138,37 @@ is not specified, then SUID and SGID bits will only be restored if the default user and group IDs of newly-created objects on disk happen to match those specified in the archive entry. By default, only basic permissions are restored, and umask is obeyed. +.It Cm ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS +Refuse to extract an absolute path. +The default is to not refuse such paths. +.It Cm ARCHIVE_EXTRACT_SECURE_NODOTDOT +Refuse to extract a path that contains a +.Pa .. +element anywhere within it. +The default is to not refuse such paths. +Note that paths ending in +.Pa .. +always cause an error, regardless of this flag. +.It Cm ARCHIVE_EXTRACT_SECURE_SYMLINKS +Refuse to extract any object whose final location would be altered +by a symlink on disk. +This is intended to help guard against a variety of mischief +caused by archives that (deliberately or otherwise) extract +files outside of the current directory. +The default is not to perform this check. +If +.It Cm ARCHIVE_EXTRACT_SPARSE +Scan data for blocks of NUL bytes and try to recreate them with holes. +This results in sparse files, independent of whether the archive format +supports or uses them. +.Cm ARCHIVE_EXTRACT_UNLINK +is specified together with this option, the library will +remove any intermediate symlinks it finds and return an +error only if such symlink could not be removed. .It Cm ARCHIVE_EXTRACT_TIME The timestamps (mtime, ctime, and atime) should be restored. By default, they are ignored. Note that restoring of atime is not currently supported. -.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE -Existing files on disk will not be overwritten. -By default, existing regular files are truncated and overwritten; -existing directories will have their permissions updated; -other pre-existing objects are unlinked and recreated from scratch. .It Cm ARCHIVE_EXTRACT_UNLINK Existing files on disk will be unlinked before any attempt to create them. @@ -148,45 +176,18 @@ In some cases, this can prove to be a significant performance improvement. By default, existing files are truncated and rewritten, but the file is not recreated. In particular, the default behavior does not break existing hard links. -.It Cm ARCHIVE_EXTRACT_ACL -Attempt to restore ACLs. -By default, extended ACLs are ignored. -.It Cm ARCHIVE_EXTRACT_FFLAGS -Attempt to restore extended file flags. -By default, file flags are ignored. .It Cm ARCHIVE_EXTRACT_XATTR -Attempt to restore POSIX.1e extended attributes. +Attempt to restore extended file attributes. By default, they are ignored. -.It Cm ARCHIVE_EXTRACT_SECURE_SYMLINKS -Refuse to extract any object whose final location would be altered -by a symlink on disk. -This is intended to help guard against a variety of mischief -caused by archives that (deliberately or otherwise) extract -files outside of the current directory. -The default is not to perform this check. -If -.Cm ARCHIVE_EXTRACT_UNLINK -is specified together with this option, the library will -remove any intermediate symlinks it finds and return an -error only if such symlink could not be removed. -.It Cm ARCHIVE_EXTRACT_SECURE_NODOTDOT -Refuse to extract a path that contains a -.Pa .. -element anywhere within it. -The default is to not refuse such paths. -Note that paths ending in -.Pa .. -always cause an error, regardless of this flag. -.It Cm ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS -Refuse to extract an absolute path. -The default is to not refuse such paths. -.It Cm ARCHIVE_EXTRACT_SPARSE -Scan data for blocks of NUL bytes and try to recreate them with holes. -This results in sparse files, independent of whether the archive format -supports or uses them. -.It Cm ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS -Before removing a file system object prior to replacing it, clear -platform-specific file flags which might prevent its removal. +See +.Xr xattr 7 +.Pq Linux , +.Xr xattr 2 +.Pq Mac OS X , +or +.Xr getextattr 8 +.Pq FreeBSD +for more information on extended file attributes. .El .It Xo .Fn archive_write_disk_set_group_lookup , @@ -223,60 +224,6 @@ the number of calls to .Xr getpwnam 3 and .Xr getgrnam 3 . -.It Fn archive_write_header -Build and write a header using the data in the provided -.Tn struct archive_entry -structure. -See -.Xr archive_entry 3 -for information on creating and populating -.Tn struct archive_entry -objects. -.It Fn archive_write_data -Write data corresponding to the header just written. -Returns number of bytes written or -1 on error. -.It Fn archive_write_data_block -Write data corresponding to the header just written. -This is like -.Fn archive_write_data -except that it performs a seek on the file being -written to the specified offset before writing the data. -This is useful when restoring sparse files from archive -formats that support sparse files. -Returns number of bytes written or -1 on error. -(Note: This is currently not supported for -.Tn archive_write -handles, only for -.Tn archive_write_disk -handles.) -.It Fn archive_write_finish_entry -Close out the entry just written. -Ordinarily, clients never need to call this, as it -is called automatically by -.Fn archive_write_next_header -and -.Fn archive_write_close -as needed. -However, some file attributes are written to disk only -after the file is closed, so this can be necessary -if you need to work with the file on disk right away. -.It Fn archive_write_close -Set any attributes that could not be set during the initial restore. -For example, directory timestamps are not restored initially because -restoring a subsequent file would alter that timestamp. -Similarly, non-writable directories are initially created with -write permissions (so that their contents can be restored). -The -.Nm -library maintains a list of all such deferred attributes and -sets them when this function is invoked. -.It Fn archive_write_finish -This is a deprecated synonym for -.Fn archive_write_free . -.It Fn archive_write_free -Invokes -.Fn archive_write_close -if it was not invoked manually, then releases all resources. .El More information about the .Va struct archive diff --git a/libarchive/archive_write_disk_acl.c b/libarchive/archive_write_disk_acl.c deleted file mode 100644 index 144ab7e..0000000 --- a/libarchive/archive_write_disk_acl.c +++ /dev/null @@ -1,654 +0,0 @@ -/*- - * Copyright (c) 2003-2010 Tim Kientzle - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer - * in this position and unchanged. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" -__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $"); - -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_ACL_H -#define _ACL_PRIVATE /* For debugging */ -#include -#endif -#if HAVE_DARWIN_ACL -#include -#endif -#ifdef HAVE_ERRNO_H -#include -#endif - -#include "archive.h" -#include "archive_entry.h" -#include "archive_acl_private.h" -#include "archive_write_disk_private.h" - -#if !HAVE_POSIX_ACL && !HAVE_NFS4_ACL -/* Default empty function body to satisfy mainline code. */ -int -archive_write_disk_set_acls(struct archive *a, int fd, const char *name, - struct archive_acl *abstract_acl) -{ - (void)a; /* UNUSED */ - (void)fd; /* UNUSED */ - (void)name; /* UNUSED */ - (void)abstract_acl; /* UNUSED */ - return (ARCHIVE_OK); -} - -#else /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */ - -#if HAVE_SUN_ACL -#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T -#elif HAVE_DARWIN_ACL -#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED -#elif HAVE_ACL_TYPE_NFS4 -#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4 -#endif - -static int set_acl(struct archive *, int fd, const char *, - struct archive_acl *, - acl_type_t, int archive_entry_acl_type, const char *tn); - -int -archive_write_disk_set_acls(struct archive *a, int fd, const char *name, - struct archive_acl *abstract_acl) -{ - int ret = ARCHIVE_OK; - -#if !HAVE_DARWIN_ACL - if ((archive_acl_types(abstract_acl) - & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { -#if HAVE_SUN_ACL - /* Solaris writes POSIX.1e access and default ACLs together */ - ret = set_acl(a, fd, name, abstract_acl, ACLENT_T, - ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e"); -#else /* HAVE_POSIX_ACL */ - if ((archive_acl_types(abstract_acl) - & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - ret = set_acl(a, fd, name, abstract_acl, - ACL_TYPE_ACCESS, 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, - ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, - "default"); -#endif /* !HAVE_SUN_ACL */ - /* Simultaneous POSIX.1e and NFSv4 is not supported */ - return (ret); - } -#endif /* !HAVE_DARWIN_ACL */ -#if HAVE_NFS4_ACL - if ((archive_acl_types(abstract_acl) & - ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { - ret = set_acl(a, fd, name, abstract_acl, - ARCHIVE_PLATFORM_ACL_TYPE_NFS4, - ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); - } -#endif /* HAVE_NFS4_ACL */ - return (ret); -} - -/* - * Translate system ACL permissions into libarchive internal structure - */ -static const struct { - const int archive_perm; - const int platform_perm; -} acl_perm_map[] = { -#if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */ - {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE}, - {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA}, - {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY}, - {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE}, - {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY}, - {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD}, - {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE}, - {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER}, - {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE} -#elif HAVE_DARWIN_ACL /* MacOS ACL permissions */ - {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, - {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, - {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, - {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, - {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, - {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, - {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, - {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY}, - {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY}, - {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER}, - {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} -#else /* POSIX.1e ACL permissions */ - {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, - {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, - {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, -#if HAVE_ACL_TYPE_NFS4 /* FreeBSD NFSv4 ACL permissions */ - {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, - {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, - {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, - {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, - {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, - {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, - {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, - {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} -#endif -#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ -}; - -#if HAVE_NFS4_ACL -/* - * Translate system NFSv4 inheritance flags into libarchive internal structure - */ -static const struct { - const int archive_inherit; - const int platform_inherit; -} acl_inherit_map[] = { -#if HAVE_SUN_ACL /* Solaris NFSv4 inheritance flags */ - {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE}, - {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE}, - {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE}, - {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, - {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE} -#elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */ - {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}, - {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT} -#else /* FreeBSD NFSv4 ACL inheritance flags */ - {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}, - {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS}, - {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED} -#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ -}; -#endif /* HAVE_NFS4_ACL */ - -static int -set_acl(struct archive *a, int fd, const char *name, - struct archive_acl *abstract_acl, - acl_type_t acl_type, int ae_requested_type, const char *tname) -{ -#if HAVE_SUN_ACL - aclent_t *aclent; - ace_t *ace; - int e, r; - acl_t *acl; -#else - acl_t acl; - acl_entry_t acl_entry; - acl_permset_t acl_permset; -#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL - acl_flagset_t acl_flagset; -#endif -#endif /* HAVE_SUN_ACL */ -#if HAVE_ACL_TYPE_NFS4 - int r; -#endif - int ret; - int ae_type, ae_permset, ae_tag, ae_id; -#if HAVE_DARWIN_ACL - uuid_t ae_uuid; -#endif - uid_t ae_uid; - gid_t ae_gid; - const char *ae_name; - int entries; - int i; - - ret = ARCHIVE_OK; - entries = archive_acl_reset(abstract_acl, ae_requested_type); - if (entries == 0) - return (ARCHIVE_OK); - -#if HAVE_SUN_ACL - acl = NULL; - acl = malloc(sizeof(acl_t)); - if (acl == NULL) { - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Invalid ACL type"); - return (ARCHIVE_FAILED); - } - if (acl_type == ACE_T) - acl->acl_entry_size = sizeof(ace_t); - else if (acl_type == ACLENT_T) - acl->acl_entry_size = sizeof(aclent_t); - else { - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Invalid ACL type"); - acl_free(acl); - return (ARCHIVE_FAILED); - } - acl->acl_type = acl_type; - acl->acl_cnt = entries; - - acl->acl_aclp = malloc(entries * acl->acl_entry_size); - if (acl->acl_aclp == NULL) { - archive_set_error(a, errno, - "Can't allocate memory for acl buffer"); - acl_free(acl); - return (ARCHIVE_FAILED); - } -#else /* !HAVE_SUN_ACL */ - acl = acl_init(entries); - if (acl == (acl_t)NULL) { - archive_set_error(a, errno, - "Failed to initialize ACL working storage"); - return (ARCHIVE_FAILED); - } -#endif /* !HAVE_SUN_ACL */ -#if HAVE_SUN_ACL - e = 0; -#endif - while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, - &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { -#if HAVE_SUN_ACL - ace = NULL; - aclent = NULL; - if (acl->acl_type == ACE_T) { - ace = &((ace_t *)acl->acl_aclp)[e]; - ace->a_who = -1; - ace->a_access_mask = 0; - ace->a_flags = 0; - } else { - aclent = &((aclent_t *)acl->acl_aclp)[e]; - aclent->a_id = -1; - aclent->a_type = 0; - aclent->a_perm = 0; - } -#else /* !HAVE_SUN_ACL */ -#if HAVE_DARWIN_ACL - /* - * Mac OS doesn't support NFSv4 ACLs for - * owner@, group@ and everyone@. - * We skip any of these ACLs found. - */ - if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ || - ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ || - ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE) - continue; -#endif - if (acl_create_entry(&acl, &acl_entry) != 0) { - archive_set_error(a, errno, - "Failed to create a new ACL entry"); - ret = ARCHIVE_FAILED; - goto exit_free; - } -#endif /* !HAVE_SUN_ACL */ -#if HAVE_DARWIN_ACL - switch (ae_type) { - case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: - acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW); - break; - case ARCHIVE_ENTRY_ACL_TYPE_DENY: - acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY); - break; - default: - /* We don't support any other types on MacOS */ - continue; - } -#endif - switch (ae_tag) { -#if HAVE_SUN_ACL - case ARCHIVE_ENTRY_ACL_USER: - ae_uid = archive_write_disk_uid(a, ae_name, ae_id); - if (acl->acl_type == ACE_T) - ace->a_who = ae_uid; - else { - aclent->a_id = ae_uid; - aclent->a_type |= USER; - } - break; - case ARCHIVE_ENTRY_ACL_GROUP: - ae_gid = archive_write_disk_gid(a, ae_name, ae_id); - if (acl->acl_type == ACE_T) { - ace->a_who = ae_gid; - ace->a_flags |= ACE_IDENTIFIER_GROUP; - } else { - aclent->a_id = ae_gid; - aclent->a_type |= GROUP; - } - break; - case ARCHIVE_ENTRY_ACL_USER_OBJ: - if (acl->acl_type == ACE_T) - ace->a_flags |= ACE_OWNER; - else - aclent->a_type |= USER_OBJ; - break; - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - if (acl->acl_type == ACE_T) { - ace->a_flags |= ACE_GROUP; - ace->a_flags |= ACE_IDENTIFIER_GROUP; - } else - aclent->a_type |= GROUP_OBJ; - break; - case ARCHIVE_ENTRY_ACL_MASK: - aclent->a_type |= CLASS_OBJ; - break; - case ARCHIVE_ENTRY_ACL_OTHER: - aclent->a_type |= OTHER_OBJ; - break; - case ARCHIVE_ENTRY_ACL_EVERYONE: - ace->a_flags |= ACE_EVERYONE; - break; -#else /* !HAVE_SUN_ACL */ - case ARCHIVE_ENTRY_ACL_USER: - ae_uid = archive_write_disk_uid(a, ae_name, ae_id); -#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ - acl_set_tag_type(acl_entry, ACL_USER); - acl_set_qualifier(acl_entry, &ae_uid); -#else /* MacOS */ - if (mbr_identifier_to_uuid(ID_TYPE_UID, &ae_uid, - sizeof(uid_t), ae_uuid) != 0) - continue; - if (acl_set_qualifier(acl_entry, &ae_uuid) != 0) - continue; -#endif /* HAVE_DARWIN_ACL */ - break; - case ARCHIVE_ENTRY_ACL_GROUP: - ae_gid = archive_write_disk_gid(a, ae_name, ae_id); -#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ - acl_set_tag_type(acl_entry, ACL_GROUP); - acl_set_qualifier(acl_entry, &ae_gid); -#else /* MacOS */ - if (mbr_identifier_to_uuid(ID_TYPE_GID, &ae_gid, - sizeof(gid_t), ae_uuid) != 0) - continue; - if (acl_set_qualifier(acl_entry, &ae_uuid) != 0) - continue; -#endif /* HAVE_DARWIN_ACL */ - break; -#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ - case ARCHIVE_ENTRY_ACL_USER_OBJ: - acl_set_tag_type(acl_entry, ACL_USER_OBJ); - break; - case ARCHIVE_ENTRY_ACL_GROUP_OBJ: - acl_set_tag_type(acl_entry, ACL_GROUP_OBJ); - break; - case ARCHIVE_ENTRY_ACL_MASK: - acl_set_tag_type(acl_entry, ACL_MASK); - break; - case ARCHIVE_ENTRY_ACL_OTHER: - acl_set_tag_type(acl_entry, ACL_OTHER); - break; -#if HAVE_ACL_TYPE_NFS4 /* FreeBSD only */ - case ARCHIVE_ENTRY_ACL_EVERYONE: - acl_set_tag_type(acl_entry, ACL_EVERYONE); - break; -#endif -#endif /* !HAVE_DARWIN_ACL */ -#endif /* !HAVE_SUN_ACL */ - default: - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Unknown ACL tag"); - ret = ARCHIVE_FAILED; - goto exit_free; - } - -#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL - r = 0; - switch (ae_type) { -#if HAVE_SUN_ACL - case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: - if (ace != NULL) - ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; - else - r = -1; - break; - case ARCHIVE_ENTRY_ACL_TYPE_DENY: - if (ace != NULL) - ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE; - else - r = -1; - break; - case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: - if (ace != NULL) - ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE; - else - r = -1; - break; - case ARCHIVE_ENTRY_ACL_TYPE_ALARM: - if (ace != NULL) - ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE; - else - r = -1; - break; - case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: - if (aclent == NULL) - r = -1; - break; - case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: - if (aclent != NULL) - aclent->a_type |= ACL_DEFAULT; - else - r = -1; - break; -#else /* !HAVE_SUN_ACL */ - case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: - r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW); - break; - case ARCHIVE_ENTRY_ACL_TYPE_DENY: - r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY); - break; - case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: - r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT); - break; - case ARCHIVE_ENTRY_ACL_TYPE_ALARM: - r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM); - break; - case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: - case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: - // These don't translate directly into the system ACL. - break; -#endif /* !HAVE_SUN_ACL */ - default: - archive_set_error(a, ARCHIVE_ERRNO_MISC, - "Unknown ACL entry type"); - ret = ARCHIVE_FAILED; - goto exit_free; - } - - if (r != 0) { -#if HAVE_SUN_ACL - errno = EINVAL; -#endif - archive_set_error(a, errno, - "Failed to set ACL entry type"); - ret = ARCHIVE_FAILED; - goto exit_free; - } -#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */ - -#if HAVE_SUN_ACL - if (acl->acl_type == ACLENT_T) { - if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE) - aclent->a_perm |= 1; - if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE) - aclent->a_perm |= 2; - if (ae_permset & ARCHIVE_ENTRY_ACL_READ) - aclent->a_perm |= 4; - } else -#else - if (acl_get_permset(acl_entry, &acl_permset) != 0) { - archive_set_error(a, errno, - "Failed to get ACL permission set"); - ret = ARCHIVE_FAILED; - goto exit_free; - } - if (acl_clear_perms(acl_permset) != 0) { - archive_set_error(a, errno, - "Failed to clear ACL permissions"); - ret = ARCHIVE_FAILED; - goto exit_free; - } -#endif /* !HAVE_SUN_ACL */ - for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { - if (ae_permset & acl_perm_map[i].archive_perm) { -#if HAVE_SUN_ACL - ace->a_access_mask |= - acl_perm_map[i].platform_perm; -#else - if (acl_add_perm(acl_permset, - acl_perm_map[i].platform_perm) != 0) { - archive_set_error(a, errno, - "Failed to add ACL permission"); - ret = ARCHIVE_FAILED; - goto exit_free; - } -#endif - } - } - -#if HAVE_NFS4_ACL -#if HAVE_SUN_ACL - if (acl_type == ACE_T) -#elif HAVE_DARWIN_ACL - if (acl_type == ACL_TYPE_EXTENDED) -#else /* FreeBSD */ - if (acl_type == ACL_TYPE_NFS4) -#endif - { -#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL - /* - * acl_get_flagset_np() fails with non-NFSv4 ACLs - */ - if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { - archive_set_error(a, errno, - "Failed to get flagset from an NFSv4 ACL entry"); - ret = ARCHIVE_FAILED; - goto exit_free; - } - if (acl_clear_flags_np(acl_flagset) != 0) { - archive_set_error(a, errno, - "Failed to clear flags from an NFSv4 ACL flagset"); - ret = ARCHIVE_FAILED; - goto exit_free; - } -#endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */ - for (i = 0; i < (int)(sizeof(acl_inherit_map) /sizeof(acl_inherit_map[0])); ++i) { - if (ae_permset & acl_inherit_map[i].archive_inherit) { -#if HAVE_SUN_ACL - ace->a_flags |= - acl_inherit_map[i].platform_inherit; -#else /* !HAVE_SUN_ACL */ - if (acl_add_flag_np(acl_flagset, - acl_inherit_map[i].platform_inherit) != 0) { - archive_set_error(a, errno, - "Failed to add flag to NFSv4 ACL flagset"); - ret = ARCHIVE_FAILED; - goto exit_free; - } -#endif /* HAVE_SUN_ACL */ - } - } - } -#endif /* HAVE_NFS4_ACL */ -#if HAVE_SUN_ACL - e++; -#endif - } - -#if HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL - /* Try restoring the ACL through 'fd' if we can. */ -#if HAVE_SUN_ACL || HAVE_ACL_SET_FD_NP - if (fd >= 0) -#else /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */ - if (fd >= 0 && acl_type == ACL_TYPE_ACCESS) -#endif - { -#if HAVE_SUN_ACL - if (facl_set(fd, acl) == 0) -#elif HAVE_ACL_SET_FD_NP - if (acl_set_fd_np(fd, acl, acl_type) == 0) -#else /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */ - if (acl_set_fd(fd, acl) == 0) -#endif - ret = ARCHIVE_OK; - else { - if (errno == EOPNOTSUPP) { - /* Filesystem doesn't support ACLs */ - ret = ARCHIVE_OK; - } else { - archive_set_error(a, errno, - "Failed to set %s acl on fd", tname); - } - } - } else -#endif /* HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL */ -#if HAVE_SUN_ACL - if (acl_set(name, acl) != 0) -#elif HAVE_ACL_SET_LINK_NP - if (acl_set_link_np(name, acl_type, acl) != 0) -#else - /* TODO: Skip this if 'name' is a symlink. */ - if (acl_set_file(name, acl_type, acl) != 0) -#endif - { - if (errno == EOPNOTSUPP) { - /* Filesystem doesn't support ACLs */ - ret = ARCHIVE_OK; - } else { - archive_set_error(a, errno, "Failed to set %s acl", - tname); - ret = ARCHIVE_WARN; - } - } -exit_free: - acl_free(acl); - return (ret); -} -#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */ diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c index 5a01e84..6ad5399 100644 --- a/libarchive/archive_write_disk_posix.c +++ b/libarchive/archive_write_disk_posix.c @@ -39,9 +39,9 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_SYS_EXTATTR_H #include #endif -#if defined(HAVE_SYS_XATTR_H) +#if HAVE_SYS_XATTR_H #include -#elif defined(HAVE_ATTR_XATTR_H) +#elif HAVE_ATTR_XATTR_H #include #endif #ifdef HAVE_SYS_EA_H @@ -575,10 +575,55 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) if (a->flags & ARCHIVE_EXTRACT_TIME) a->todo |= TODO_TIMES; if (a->flags & ARCHIVE_EXTRACT_ACL) { +#if ARCHIVE_ACL_DARWIN + /* + * On MacOS, platform ACLs get stored in mac_metadata, too. + * If we intend to extract mac_metadata and it is present + * we skip extracting libarchive NFSv4 ACLs. + */ + size_t metadata_size; + + if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || + archive_entry_mac_metadata(a->entry, + &metadata_size) == NULL || metadata_size == 0) +#endif +#if ARCHIVE_ACL_LIBRICHACL + /* + * RichACLs are stored in an extended attribute. + * If we intend to extract extended attributes and have this + * attribute we skip extracting libarchive NFSv4 ACLs. + */ + short extract_acls = 1; + if (a->flags & ARCHIVE_EXTRACT_XATTR && ( + archive_entry_acl_types(a->entry) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4)) { + const char *attr_name; + const void *attr_value; + size_t attr_size; + int i = archive_entry_xattr_reset(a->entry); + while (i--) { + archive_entry_xattr_next(a->entry, &attr_name, + &attr_value, &attr_size); + if (attr_name != NULL && attr_value != NULL && + attr_size > 0 && strcmp(attr_name, + "trusted.richacl") == 0) { + extract_acls = 0; + break; + } + } + } + if (extract_acls) +#endif +#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL + { +#endif if (archive_entry_filetype(a->entry) == AE_IFDIR) a->deferred |= TODO_ACLS; else a->todo |= TODO_ACLS; +#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL + } +#endif } if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) { if (archive_entry_filetype(a->entry) == AE_IFDIR) @@ -619,8 +664,21 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) } #endif - if (a->flags & ARCHIVE_EXTRACT_XATTR) + if (a->flags & ARCHIVE_EXTRACT_XATTR) { +#if ARCHIVE_XATTR_DARWIN + /* + * On MacOS, extended attributes get stored in mac_metadata, + * too. If we intend to extract mac_metadata and it is present + * we skip extracting extended attributes. + */ + size_t metadata_size; + + if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 || + archive_entry_mac_metadata(a->entry, + &metadata_size) == NULL || metadata_size == 0) +#endif a->todo |= TODO_XATTR; + } if (a->flags & ARCHIVE_EXTRACT_FFLAGS) a->todo |= TODO_FFLAGS; if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) { @@ -1703,25 +1761,11 @@ _archive_write_disk_finish_entry(struct archive *_a) */ if (a->todo & TODO_ACLS) { int r2; -#ifdef HAVE_DARWIN_ACL - /* - * On Mac OS, platform ACLs are stored also in mac_metadata by - * the operating system. If mac_metadata is present it takes - * precedence and we skip extracting libarchive NFSv4 ACLs - */ - const void *metadata; - size_t metadata_size; - metadata = archive_entry_mac_metadata(a->entry, &metadata_size); - if ((a->todo & TODO_MAC_METADATA) == 0 || - metadata == NULL || metadata_size == 0) { -#endif r2 = archive_write_disk_set_acls(&a->archive, a->fd, archive_entry_pathname(a->entry), - archive_entry_acl(a->entry)); + archive_entry_acl(a->entry), + archive_entry_mode(a->entry)); if (r2 < ret) ret = r2; -#ifdef HAVE_DARWIN_ACL - } -#endif } finish_metadata: @@ -2293,13 +2337,8 @@ _archive_write_disk_close(struct archive *_a) if (p->fixup & TODO_MODE_BASE) chmod(p->name, p->mode); if (p->fixup & TODO_ACLS) -#ifdef HAVE_DARWIN_ACL - if ((p->fixup & TODO_MAC_METADATA) == 0 || - p->mac_metadata == NULL || - p->mac_metadata_size == 0) -#endif - archive_write_disk_set_acls(&a->archive, - -1, p->name, &p->acl); + archive_write_disk_set_acls(&a->archive, -1, p->name, + &p->acl, p->mode); if (p->fixup & TODO_FFLAGS) set_fflags_platform(a, -1, p->name, p->mode, p->fflags_set, 0); @@ -2467,7 +2506,7 @@ fsobj_error(int *a_eno, struct archive_string *a_estr, if (a_eno) *a_eno = err; if (a_estr) - archive_string_sprintf(a_estr, errstr, path); + archive_string_sprintf(a_estr, "%s%s", errstr, path); } /* @@ -2573,7 +2612,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, * with the deep-directory editing. */ fsobj_error(a_eno, a_estr, errno, - "Could not stat %s", path); + "Could not stat ", path); res = ARCHIVE_FAILED; break; } @@ -2582,7 +2621,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, if (chdir(head) != 0) { tail[0] = c; fsobj_error(a_eno, a_estr, errno, - "Could not chdir %s", path); + "Could not chdir ", path); res = (ARCHIVE_FATAL); break; } @@ -2599,7 +2638,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, if (unlink(head)) { tail[0] = c; fsobj_error(a_eno, a_estr, errno, - "Could not remove symlink %s", + "Could not remove symlink ", path); res = ARCHIVE_FAILED; break; @@ -2618,7 +2657,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, /* if (!S_ISLNK(path)) { fsobj_error(a_eno, a_estr, 0, - "Removing symlink %s", path); + "Removing symlink ", path); } */ /* Symlink gone. No more problem! */ @@ -2630,7 +2669,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, tail[0] = c; fsobj_error(a_eno, a_estr, 0, "Cannot remove intervening " - "symlink %s", path); + "symlink ", path); res = ARCHIVE_FAILED; break; } @@ -2652,7 +2691,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, } else { fsobj_error(a_eno, a_estr, errno, - "Could not stat %s", path); + "Could not stat ", path); res = (ARCHIVE_FAILED); break; } @@ -2661,7 +2700,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, tail[0] = c; fsobj_error(a_eno, a_estr, errno, - "Could not chdir %s", path); + "Could not chdir ", path); res = (ARCHIVE_FATAL); break; } @@ -2674,14 +2713,14 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, tail[0] = c; fsobj_error(a_eno, a_estr, 0, "Cannot extract through " - "symlink %s", path); + "symlink ", path); res = ARCHIVE_FAILED; break; } } else { tail[0] = c; fsobj_error(a_eno, a_estr, 0, - "Cannot extract through symlink %s", path); + "Cannot extract through symlink ", path); res = ARCHIVE_FAILED; break; } @@ -4044,71 +4083,98 @@ skip_appledouble: } #endif -#if HAVE_LSETXATTR || HAVE_LSETEA +#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX /* - * Restore extended attributes - Linux and AIX implementations: + * Restore extended attributes - Linux, Darwin and AIX implementations: * AIX' ea interface is syntaxwise identical to the Linux xattr interface. */ static int set_xattrs(struct archive_write_disk *a) { struct archive_entry *entry = a->entry; - static int warning_done = 0; + struct archive_string errlist; int ret = ARCHIVE_OK; int i = archive_entry_xattr_reset(entry); + short fail = 0; + + archive_string_init(&errlist); while (i--) { const char *name; const void *value; size_t size; + int e; + archive_entry_xattr_next(entry, &name, &value, &size); - if (name != NULL && - strncmp(name, "xfsroot.", 8) != 0 && - strncmp(name, "system.", 7) != 0) { - int e; -#if HAVE_FSETXATTR - if (a->fd >= 0) - e = fsetxattr(a->fd, name, value, size, 0); - else -#elif HAVE_FSETEA - if (a->fd >= 0) - e = fsetea(a->fd, name, value, size, 0); - else + + if (name == NULL) + continue; +#if ARCHIVE_XATTR_LINUX + /* Linux: quietly skip POSIX.1e ACL extended attributes */ + if (strncmp(name, "system.", 7) == 0 && + (strcmp(name + 7, "posix_acl_access") == 0 || + strcmp(name + 7, "posix_acl_default") == 0)) + continue; + if (strncmp(name, "trusted.SGI_", 12) == 0 && + (strcmp(name + 12, "ACL_DEFAULT") == 0 || + strcmp(name + 12, "ACL_FILE") == 0)) + continue; + + /* Linux: xfsroot namespace is obsolete and unsupported */ + if (strncmp(name, "xfsroot.", 8) == 0) { + fail = 1; + archive_strcat(&errlist, name); + archive_strappend_char(&errlist, ' '); + continue; + } #endif - { -#if HAVE_LSETXATTR - e = lsetxattr(archive_entry_pathname(entry), - name, value, size, 0); -#elif HAVE_LSETEA - e = lsetea(archive_entry_pathname(entry), - name, value, size, 0); + + if (a->fd >= 0) { +#if ARCHIVE_XATTR_LINUX + e = fsetxattr(a->fd, name, value, size, 0); +#elif ARCHIVE_XATTR_DARWIN + e = fsetxattr(a->fd, name, value, size, 0, 0); +#elif ARCHIVE_XATTR_AIX + e = fsetea(a->fd, name, value, size, 0); #endif - } - if (e == -1) { - if (errno == ENOTSUP || errno == ENOSYS) { - if (!warning_done) { - warning_done = 1; - archive_set_error(&a->archive, - errno, - "Cannot restore extended " - "attributes on this file " - "system"); - } - } else - archive_set_error(&a->archive, errno, - "Failed to set extended attribute"); - ret = ARCHIVE_WARN; - } } else { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Invalid extended attribute encountered"); +#if ARCHIVE_XATTR_LINUX + e = lsetxattr(archive_entry_pathname(entry), + name, value, size, 0); +#elif ARCHIVE_XATTR_DARWIN + e = setxattr(archive_entry_pathname(entry), + name, value, size, 0, XATTR_NOFOLLOW); +#elif ARCHIVE_XATTR_AIX + e = lsetea(archive_entry_pathname(entry), + name, value, size, 0); +#endif + } + if (e == -1) { ret = ARCHIVE_WARN; + archive_strcat(&errlist, name); + archive_strappend_char(&errlist, ' '); + if (errno != ENOTSUP && errno != ENOSYS) + fail = 1; } } + + if (ret == ARCHIVE_WARN) { + if (fail && errlist.length > 0) { + errlist.length--; + errlist.s[errlist.length] = '\0'; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore extended attributes: %s", + errlist.s); + } else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore extended " + "attributes on this file system."); + } + + archive_string_free(&errlist); return (ret); } -#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER +#elif ARCHIVE_XATTR_FREEBSD /* * Restore extended attributes - FreeBSD implementation */ @@ -4116,9 +4182,12 @@ static int set_xattrs(struct archive_write_disk *a) { struct archive_entry *entry = a->entry; - static int warning_done = 0; + struct archive_string errlist; int ret = ARCHIVE_OK; int i = archive_entry_xattr_reset(entry); + short fail = 0; + + archive_string_init(&errlist); while (i--) { const char *name; @@ -4134,46 +4203,47 @@ set_xattrs(struct archive_write_disk *a) name += 5; namespace = EXTATTR_NAMESPACE_USER; } else { - /* Warn about other extended attributes. */ - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't restore extended attribute ``%s''", - name); + /* Other namespaces are unsupported */ + archive_strcat(&errlist, name); + archive_strappend_char(&errlist, ' '); + fail = 1; ret = ARCHIVE_WARN; continue; } - errno = 0; -#if HAVE_EXTATTR_SET_FD - if (a->fd >= 0) + + if (a->fd >= 0) { e = extattr_set_fd(a->fd, namespace, name, value, size); - else -#endif - /* TODO: should we use extattr_set_link() instead? */ - { - e = extattr_set_file( + } else { + e = extattr_set_link( archive_entry_pathname(entry), namespace, name, value, size); } if (e != (int)size) { - if (errno == ENOTSUP || errno == ENOSYS) { - if (!warning_done) { - warning_done = 1; - archive_set_error(&a->archive, - errno, - "Cannot restore extended " - "attributes on this file " - "system"); - } - } else { - archive_set_error(&a->archive, errno, - "Failed to set extended attribute"); - } - + archive_strcat(&errlist, name); + archive_strappend_char(&errlist, ' '); ret = ARCHIVE_WARN; + if (errno != ENOTSUP && errno != ENOSYS) + fail = 1; } } } + + if (ret == ARCHIVE_WARN) { + if (fail && errlist.length > 0) { + errlist.length--; + errlist.s[errlist.length] = '\0'; + + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore extended attributes: %s", + errlist.s); + } else + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Cannot restore extended " + "attributes on this file system."); + } + + archive_string_free(&errlist); return (ret); } #else @@ -4239,5 +4309,19 @@ older(struct stat *st, struct archive_entry *entry) return (0); } +#ifndef ARCHIVE_ACL_SUPPORT +int +archive_write_disk_set_acls(struct archive *a, int fd, const char *name, + struct archive_acl *abstract_acl, __LA_MODE_T mode) +{ + (void)a; /* UNUSED */ + (void)fd; /* UNUSED */ + (void)name; /* UNUSED */ + (void)abstract_acl; /* UNUSED */ + (void)mode; /* UNUSED */ + return (ARCHIVE_OK); +} +#endif + #endif /* !_WIN32 || __CYGWIN__ */ diff --git a/libarchive/archive_write_disk_private.h b/libarchive/archive_write_disk_private.h index d84e7e1..b655dea 100644 --- a/libarchive/archive_write_disk_private.h +++ b/libarchive/archive_write_disk_private.h @@ -33,11 +33,13 @@ #ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED #define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED +#include "archive_platform_acl.h" #include "archive_acl_private.h" +#include "archive_entry.h" struct archive_write_disk; -int -archive_write_disk_set_acls(struct archive *, int /* fd */, const char * /* pathname */, struct archive_acl *); +int archive_write_disk_set_acls(struct archive *, int, const char *, + struct archive_acl *, __LA_MODE_T); #endif diff --git a/libarchive/archive_write_finish_entry.3 b/libarchive/archive_write_finish_entry.3 index c5ef69e..dc1b94b 100644 --- a/libarchive/archive_write_finish_entry.3 +++ b/libarchive/archive_write_finish_entry.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 2, 2012 +.Dd February 28, 2017 .Dt ARCHIVE_WRITE_FINISH_ENTRY 3 .Os .Sh NAME @@ -45,6 +45,9 @@ is called automatically by and .Fn archive_write_close as needed. +For +.Tn archive_write_disk +handles, this flushes pending file attribute changes like modification time. .\" .Sh EXAMPLE .Sh RETURN VALUES This function returns diff --git a/libarchive/archive_write_format.3 b/libarchive/archive_write_format.3 index d4ba6ab..aaafb0a 100644 --- a/libarchive/archive_write_format.3 +++ b/libarchive/archive_write_format.3 @@ -108,7 +108,6 @@ Streaming Archive Library (libarchive, -larchive) These functions set the format that will be used for the archive. .Pp The library can write a variety of common archive formats. - .Bl -tag -width indent .It Fn archive_write_set_format Sets the format based on the format code (see diff --git a/libarchive/archive_write_set_format.c b/libarchive/archive_write_set_format.c index 744302d..0f70623 100644 --- a/libarchive/archive_write_set_format.c +++ b/libarchive/archive_write_set_format.c @@ -38,7 +38,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format.c 201168 2009-1 #include "archive_private.h" /* A table that maps format codes to functions. */ -static +static const struct { int code; int (*setter)(struct archive *); } codes[] = { { ARCHIVE_FORMAT_7ZIP, archive_write_set_format_7zip }, diff --git a/libarchive/archive_write_set_format_by_name.c b/libarchive/archive_write_set_format_by_name.c index a2ce7c6..86e8621 100644 --- a/libarchive/archive_write_set_format_by_name.c +++ b/libarchive/archive_write_set_format_by_name.c @@ -41,7 +41,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 20116 #include "archive_private.h" /* A table that maps names to functions. */ -static +static const struct { const char *name; int (*setter)(struct archive *); } names[] = { { "7zip", archive_write_set_format_7zip }, diff --git a/libarchive/archive_write_set_format_filter_by_ext.c b/libarchive/archive_write_set_format_filter_by_ext.c index adec9b2..9fe21e4 100644 --- a/libarchive/archive_write_set_format_filter_by_ext.c +++ b/libarchive/archive_write_set_format_filter_by_ext.c @@ -42,7 +42,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 20116 #include "archive_private.h" /* A table that maps names to functions. */ -static +static const struct { const char *name; int (*format)(struct archive *); int (*filter)(struct archive *); } names[] = { { ".7z", archive_write_set_format_7zip, archive_write_add_filter_none}, diff --git a/libarchive/archive_write_set_format_pax.c b/libarchive/archive_write_set_format_pax.c index 6a301ac..0eaf733 100644 --- a/libarchive/archive_write_set_format_pax.c +++ b/libarchive/archive_write_set_format_pax.c @@ -1196,8 +1196,12 @@ archive_write_pax_header(struct archive_write *a, "GNU.sparse.major", 1); add_pax_attr_int(&(pax->pax_header), "GNU.sparse.minor", 0); + /* + * Make sure to store the original path, since + * truncation to ustar limit happened already. + */ add_pax_attr(&(pax->pax_header), - "GNU.sparse.name", entry_name.s); + "GNU.sparse.name", path); add_pax_attr_int(&(pax->pax_header), "GNU.sparse.realsize", archive_entry_size(entry_main)); @@ -1650,13 +1654,14 @@ build_pax_attribute_name(char *dest, const char *src) * GNU PAX Format 1.0 requires the special name, which pattern is: * /GNUSparseFile./ * + * Since reproducable archives are more important, use 0 as pid. + * * This function is used for only Sparse file, a file type of which * is regular file. */ static char * build_gnu_sparse_name(char *dest, const char *src) { - char buff[64]; const char *p; /* Handle the null filename case. */ @@ -1682,15 +1687,9 @@ build_gnu_sparse_name(char *dest, const char *src) break; } -#if HAVE_GETPID && 0 /* Disable this as pax attribute name. */ - sprintf(buff, "GNUSparseFile.%d", getpid()); -#else - /* If the platform can't fetch the pid, don't include it. */ - strcpy(buff, "GNUSparseFile"); -#endif /* General case: build a ustar-compatible name adding * "/GNUSparseFile/". */ - build_ustar_entry_name(dest, src, p - src, buff); + build_ustar_entry_name(dest, src, p - src, "GNUSparseFile.0"); return (dest); } diff --git a/libarchive/archive_write_set_format_warc.c b/libarchive/archive_write_set_format_warc.c index 8b6daf9..edad072 100644 --- a/libarchive/archive_write_set_format_warc.c +++ b/libarchive/archive_write_set_format_warc.c @@ -354,7 +354,7 @@ static ssize_t _popul_ehdr(struct archive_string *tgt, size_t tsz, warc_essential_hdr_t hdr) { static const char _ver[] = "WARC/1.0\r\n"; - static const char *_typ[LAST_WT] = { + static const char * const _typ[LAST_WT] = { NULL, "warcinfo", "metadata", "resource", NULL }; char std_uuid[48U]; diff --git a/libarchive/config_freebsd.h b/libarchive/config_freebsd.h index 215e886..be25258 100644 --- a/libarchive/config_freebsd.h +++ b/libarchive/config_freebsd.h @@ -22,141 +22,238 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: head/lib/libarchive/config_freebsd.h 201079 2009-12-28 02:01:42Z kientzle $ + * $FreeBSD$ */ -/* FreeBSD 5.0 and later have ACL and extattr support. */ +#include + +/* FreeBSD 5.0 and later has ACL and extattr support. */ #if __FreeBSD__ > 4 -#define HAVE_ACL_CREATE_ENTRY 1 -#define HAVE_ACL_GET_FD_NP 1 -#define HAVE_ACL_GET_LINK_NP 1 -#define HAVE_ACL_GET_PERM_NP 1 -#define HAVE_ACL_INIT 1 -#define HAVE_ACL_SET_FD 1 -#define HAVE_ACL_SET_FD_NP 1 -#define HAVE_ACL_SET_FILE 1 -#define HAVE_ACL_USER 1 -#define HAVE_EXTATTR_GET_FILE 1 -#define HAVE_EXTATTR_LIST_FILE 1 -#define HAVE_EXTATTR_SET_FD 1 -#define HAVE_EXTATTR_SET_FILE 1 -#define HAVE_STRUCT_XVFSCONF 1 -#define HAVE_SYS_ACL_H 1 -#define HAVE_SYS_EXTATTR_H 1 -#endif +#define ARCHIVE_ACL_FREEBSD 1 +#define HAVE_ACL_GET_PERM_NP 1 +#define HAVE_ARC4RANDOM_BUF 1 +#define HAVE_EXTATTR_GET_FILE 1 +#define HAVE_EXTATTR_LIST_FILE 1 +#define HAVE_EXTATTR_SET_FD 1 +#define HAVE_EXTATTR_SET_FILE 1 +#define HAVE_STRUCT_XVFSCONF 1 +#define HAVE_SYS_ACL_H 1 +#define HAVE_SYS_EXTATTR_H 1 +#if __FreeBSD__ > 7 +/* FreeBSD 8.0 and later has NFSv4 ACL support */ +#define ARCHIVE_ACL_FREEBSD_NFS4 1 +#define HAVE_ACL_GET_LINK_NP 1 +#define HAVE_ACL_IS_TRIVIAL_NP 1 +#define HAVE_ACL_SET_LINK_NP 1 +#endif /* __FreeBSD__ > 7 */ +#endif /* __FreeBSD__ > 4 */ #ifdef WITH_OPENSSL -#define HAVE_OPENSSL_MD5_H 1 -#define HAVE_OPENSSL_RIPEMD_H 1 -#define HAVE_OPENSSL_SHA_H 1 -#define HAVE_SHA384 1 -#define HAVE_SHA512 1 +#define HAVE_LIBCRYPTO 1 +#define HAVE_OPENSSL_EVP_H 1 +#define HAVE_OPENSSL_MD5_H 1 +#define HAVE_OPENSSL_RIPEMD_H 1 +#define HAVE_OPENSSL_SHA_H 1 +#define HAVE_OPENSSL_SHA256_INIT 1 +#define HAVE_OPENSSL_SHA384_INIT 1 +#define HAVE_OPENSSL_SHA512_INIT 1 +#define HAVE_PKCS5_PBKDF2_HMAC_SHA1 1 +#define HAVE_SHA256 1 +#define HAVE_SHA384 1 +#define HAVE_SHA512 1 +#else +#define HAVE_LIBMD 1 +#define HAVE_MD5_H 1 +#define HAVE_MD5INIT 1 +#define HAVE_RIPEMD_H 1 +#define HAVE_SHA_H 1 +#define HAVE_SHA1 1 +#define HAVE_SHA1_INIT 1 +#define HAVE_SHA256 1 +#define HAVE_SHA256_H 1 +#define HAVE_SHA256_INIT 1 +#define HAVE_SHA512 1 +#define HAVE_SHA512_H 1 +#define HAVE_SHA512_INIT 1 #endif -#define HAVE_BSDXML_H 1 -#define HAVE_BZLIB_H 1 -#define HAVE_CHFLAGS 1 -#define HAVE_CHOWN 1 -#define HAVE_DECL_INT64_MAX 1 -#define HAVE_DECL_INT64_MIN 1 -#define HAVE_DECL_SIZE_MAX 1 -#define HAVE_DECL_SSIZE_MAX 1 -#define HAVE_DECL_STRERROR_R 1 -#define HAVE_DECL_UINT32_MAX 1 -#define HAVE_DECL_UINT64_MAX 1 -#define HAVE_DIRENT_H 1 -#define HAVE_EFTYPE 1 -#define HAVE_EILSEQ 1 -#define HAVE_ERRNO_H 1 -#define HAVE_FCHDIR 1 -#define HAVE_FCHFLAGS 1 -#define HAVE_FCHMOD 1 -#define HAVE_FCHOWN 1 -#define HAVE_FCNTL 1 -#define HAVE_FCNTL_H 1 -#define HAVE_FSEEKO 1 -#define HAVE_FSTAT 1 -#define HAVE_FTRUNCATE 1 -#define HAVE_FUTIMES 1 -#define HAVE_GETEUID 1 -#define HAVE_GETGRGID_R 1 -#define HAVE_GETPID 1 -#define HAVE_GETPWUID_R 1 -#define HAVE_GRP_H 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_LCHFLAGS 1 -#define HAVE_LCHMOD 1 -#define HAVE_LCHOWN 1 -#define HAVE_LIMITS_H 1 -#define HAVE_LINK 1 -#define HAVE_LSTAT 1 -#define HAVE_LUTIMES 1 -#define HAVE_MALLOC 1 -#define HAVE_MD5 1 -#define HAVE_MD5_H 1 -#define HAVE_MEMMOVE 1 -#define HAVE_MKDIR 1 -#define HAVE_MKFIFO 1 -#define HAVE_MKNOD 1 -#define HAVE_PIPE 1 -#define HAVE_POLL 1 -#define HAVE_POLL_H 1 -#define HAVE_PWD_H 1 -#define HAVE_READLINK 1 -#define HAVE_RMD160 1 -#define HAVE_SELECT 1 -#define HAVE_SETENV 1 -#define HAVE_SHA_H 1 -#define HAVE_SHA1 1 -#define HAVE_SHA256 1 -#define HAVE_SHA256_H 1 -#define HAVE_SIGNAL_H 1 -#define HAVE_STDINT_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_STRCHR 1 -#define HAVE_STRDUP 1 -#define HAVE_STRERROR 1 -#define HAVE_STRERROR_R 1 -#define HAVE_STRINGS_H 1 -#define HAVE_STRING_H 1 -#define HAVE_STRRCHR 1 -#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 -#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 -#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 -#define HAVE_STRUCT_STAT_ST_FLAGS 1 -#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 -#define HAVE_STRUCT_TM_TM_GMTOFF 1 -#define HAVE_SYMLINK 1 -#define HAVE_SYS_CDEFS_H 1 -#define HAVE_SYS_IOCTL_H 1 -#define HAVE_SYS_MOUNT_H 1 -#define HAVE_SYS_PARAM_H 1 -#define HAVE_SYS_SELECT_H 1 -#define HAVE_SYS_STAT_H 1 -#define HAVE_SYS_TIME_H 1 -#define HAVE_SYS_TYPES_H 1 -#undef HAVE_SYS_UTIME_H -#define HAVE_SYS_UTSNAME_H 1 -#define HAVE_SYS_WAIT_H 1 -#define HAVE_TIMEGM 1 -#define HAVE_TZSET 1 -#define HAVE_UNISTD_H 1 -#define HAVE_UNSETENV 1 -#define HAVE_UTIME 1 -#define HAVE_UTIMES 1 -#define HAVE_UTIME_H 1 -#define HAVE_VFORK 1 -#define HAVE_WCHAR_H 1 -#define HAVE_WCSCPY 1 -#define HAVE_WCSLEN 1 -#define HAVE_WCTOMB 1 -#define HAVE_WMEMCMP 1 -#define HAVE_WMEMCPY 1 -#define HAVE_ZLIB_H 1 -#define TIME_WITH_SYS_TIME 1 +#define HAVE_BSDXML_H 1 +#define HAVE_BZLIB_H 1 +#define HAVE_CHFLAGS 1 +#define HAVE_CHOWN 1 +#define HAVE_CHROOT 1 +#define HAVE_CTIME_R 1 +#define HAVE_CTYPE_H 1 +#define HAVE_DECL_EXTATTR_NAMESPACE_USER 1 +#define HAVE_DECL_INT32_MAX 1 +#define HAVE_DECL_INT32_MIN 1 +#define HAVE_DECL_INT64_MAX 1 +#define HAVE_DECL_INT64_MIN 1 +#define HAVE_DECL_INTMAX_MAX 1 +#define HAVE_DECL_INTMAX_MIN 1 +#define HAVE_DECL_SIZE_MAX 1 +#define HAVE_DECL_SSIZE_MAX 1 +#define HAVE_DECL_STRERROR_R 1 +#define HAVE_DECL_UINT32_MAX 1 +#define HAVE_DECL_UINT64_MAX 1 +#define HAVE_DECL_UINTMAX_MAX 1 +#define HAVE_DIRENT_H 1 +#define HAVE_DLFCN_H 1 +#define HAVE_D_MD_ORDER 1 +#define HAVE_EFTYPE 1 +#define HAVE_EILSEQ 1 +#define HAVE_ERRNO_H 1 +#define HAVE_FCHDIR 1 +#define HAVE_FCHFLAGS 1 +#define HAVE_FCHMOD 1 +#define HAVE_FCHOWN 1 +#define HAVE_FCNTL 1 +#define HAVE_FCNTL_H 1 +#define HAVE_FDOPENDIR 1 +#define HAVE_FORK 1 +#define HAVE_FSEEKO 1 +#define HAVE_FSTAT 1 +#define HAVE_FSTATAT 1 +#define HAVE_FSTATFS 1 +#define HAVE_FSTATVFS 1 +#define HAVE_FTRUNCATE 1 +#define HAVE_FUTIMES 1 +#define HAVE_FUTIMESAT 1 +#define HAVE_GETEUID 1 +#define HAVE_GETGRGID_R 1 +#define HAVE_GETGRNAM_R 1 +#define HAVE_GETPID 1 +#define HAVE_GETPWNAM_R 1 +#define HAVE_GETPWUID_R 1 +#define HAVE_GETVFSBYNAME 1 +#define HAVE_GMTIME_R 1 +#define HAVE_GRP_H 1 +#define HAVE_INTMAX_T 1 +#define HAVE_INTTYPES_H 1 +#define HAVE_LANGINFO_H 1 +#define HAVE_LCHFLAGS 1 +#define HAVE_LCHMOD 1 +#define HAVE_LCHOWN 1 +#define HAVE_LIBZ 1 +#define HAVE_LIMITS_H 1 +#define HAVE_LINK 1 +#define HAVE_LOCALE_H 1 +#define HAVE_LOCALTIME_R 1 +#define HAVE_LONG_LONG_INT 1 +#define HAVE_LSTAT 1 +#define HAVE_LUTIMES 1 +#define HAVE_MBRTOWC 1 +#define HAVE_MEMMOVE 1 +#define HAVE_MEMORY_H 1 +#define HAVE_MEMSET 1 +#define HAVE_MKDIR 1 +#define HAVE_MKFIFO 1 +#define HAVE_MKNOD 1 +#define HAVE_MKSTEMP 1 +#define HAVE_NL_LANGINFO 1 +#define HAVE_OPENAT 1 +#define HAVE_PATHS_H 1 +#define HAVE_PIPE 1 +#define HAVE_POLL 1 +#define HAVE_POLL_H 1 +#define HAVE_POSIX_SPAWNP 1 +#define HAVE_PTHREAD_H 1 +#define HAVE_PWD_H 1 +#define HAVE_READDIR_R 1 +#define HAVE_READLINK 1 +#define HAVE_READLINKAT 1 +#define HAVE_READPASSPHRASE 1 +#define HAVE_READPASSPHRASE_H 1 +#define HAVE_REGEX_H 1 +#define HAVE_SELECT 1 +#define HAVE_SETENV 1 +#define HAVE_SETLOCALE 1 +#define HAVE_SIGACTION 1 +#define HAVE_SIGNAL_H 1 +#define HAVE_SPAWN_H 1 +#define HAVE_STATFS 1 +#define HAVE_STATVFS 1 +#define HAVE_STDARG_H 1 +#define HAVE_STDINT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRCHR 1 +#define HAVE_STRDUP 1 +#define HAVE_STRERROR 1 +#define HAVE_STRERROR_R 1 +#define HAVE_STRFTIME 1 +#define HAVE_STRINGS_H 1 +#define HAVE_STRING_H 1 +#define HAVE_STRRCHR 1 +#define HAVE_STRUCT_STATFS_F_NAMEMAX 1 +#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 +#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1 +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 +#define HAVE_STRUCT_STAT_ST_FLAGS 1 +#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1 +#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1 +#define HAVE_STRUCT_TM_TM_GMTOFF 1 +#define HAVE_SYMLINK 1 +#define HAVE_SYS_CDEFS_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_MOUNT_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_POLL_H 1 +#define HAVE_SYS_SELECT_H 1 +#define HAVE_SYS_STATVFS_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_SYS_UTSNAME_H 1 +#define HAVE_SYS_WAIT_H 1 +#define HAVE_TIMEGM 1 +#define HAVE_TIME_H 1 +#define HAVE_TZSET 1 +#define HAVE_UINTMAX_T 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UNSETENV 1 +#define HAVE_UNSIGNED_LONG_LONG 1 +#define HAVE_UNSIGNED_LONG_LONG_INT 1 +#define HAVE_UTIME 1 +#define HAVE_UTIMES 1 +#define HAVE_UTIME_H 1 +#define HAVE_VFORK 1 +#define HAVE_VPRINTF 1 +#define HAVE_WCHAR_H 1 +#define HAVE_WCHAR_T 1 +#define HAVE_WCRTOMB 1 +#define HAVE_WCSCMP 1 +#define HAVE_WCSCPY 1 +#define HAVE_WCSLEN 1 +#define HAVE_WCTOMB 1 +#define HAVE_WCTYPE_H 1 +#define HAVE_WMEMCMP 1 +#define HAVE_WMEMCPY 1 +#define HAVE_WMEMMOVE 1 +#define HAVE_ZLIB_H 1 +#define TIME_WITH_SYS_TIME 1 + +#if __FreeBSD_version >= 1100056 +#define HAVE_FUTIMENS 1 +#define HAVE_UTIMENSAT 1 +#endif /* FreeBSD 4 and earlier lack intmax_t/uintmax_t */ #if __FreeBSD__ < 5 -#define intmax_t int64_t -#define uintmax_t uint64_t +#define intmax_t int64_t +#define uintmax_t uint64_t +#endif + +/* FreeBSD defines for archive_hash.h */ +#ifdef WITH_OPENSSL +#define ARCHIVE_CRYPTO_MD5_OPENSSL 1 +#define ARCHIVE_CRYPTO_RMD160_OPENSSL 1 +#define ARCHIVE_CRYPTO_SHA1_OPENSSL +#define ARCHIVE_CRYPTO_SHA256_OPENSSL 1 +#define ARCHIVE_CRYPTO_SHA384_OPENSSL 1 +#define ARCHIVE_CRYPTO_SHA512_OPENSSL 1 +#else +#define ARCHIVE_CRYPTO_MD5_LIBMD 1 +#define ARCHIVE_CRYPTO_SHA1_LIBMD 1 +#define ARCHIVE_CRYPTO_SHA256_LIBMD 1 +#define ARCHIVE_CRYPTO_SHA512_LIBMD 1 #endif diff --git a/libarchive/libarchive_changes.3 b/libarchive/libarchive_changes.3 index 881a67c..adc87fe 100644 --- a/libarchive/libarchive_changes.3 +++ b/libarchive/libarchive_changes.3 @@ -28,6 +28,7 @@ .Dt LIBARCHIVE_CHANGES 3 .Os .Sh NAME +.Nm libarchive_changes .Nd changes in libarchive interface .\" .Sh CHANGES IN LIBARCHIVE 3 diff --git a/libarchive/mtree.5 b/libarchive/mtree.5 index 16c8abe..e607e4a 100644 --- a/libarchive/mtree.5 +++ b/libarchive/mtree.5 @@ -48,7 +48,7 @@ Leading whitespace is always ignored. .Pp When encoding file or pathnames, any backslash character or character outside of the 95 printable ASCII characters must be -encoded as a a backslash followed by three +encoded as a backslash followed by three octal digits. When reading mtree files, any appearance of a backslash followed by three octal digits should be converted into the diff --git a/libarchive/xxhash.c b/libarchive/xxhash.c index 6f5ba52..70750ba 100644 --- a/libarchive/xxhash.c +++ b/libarchive/xxhash.c @@ -141,13 +141,19 @@ typedef struct _U32_S { U32 v; } _PACKED U32_S; # pragma pack(pop) #endif -#define A32(x) (((const U32_S *)(x))->v) - /**************************************** ** Compiler-specific Functions and Macros *****************************************/ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#define GCC_VERSION ((__GNUC__-0) * 100 + (__GNUC_MINOR__ - 0)) + +#if GCC_VERSION >= 409 +__attribute__((__no_sanitize_undefined__)) +#endif +static inline U32 A32(const void * x) +{ + return (((const U32_S *)(x))->v); +} /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */ #if defined(_MSC_VER) -- cgit v0.12