From 11cc5c6d300e5734ba8e274a945bd688aae9b1f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Podg=C3=B3rski?= <kuba--@users.noreply.github.com> Date: Mon, 10 Jan 2022 23:19:36 +0100 Subject: [PATCH] permissions xattr. logic from zip info (#227) --- src/miniz.h | 39 ++++++++++++---------- src/zip.c | 81 ++++++++++++++++++++++++++++++++++++++-------- test/test_append.c | 4 +-- 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/src/miniz.h b/src/miniz.h index 46c93e6..168b176 100644 --- a/src/miniz.h +++ b/src/miniz.h @@ -1357,11 +1357,10 @@ MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, mz_uint64 file_start_ofs, mz_uint64 archive_size); MINIZ_EXPORT mz_bool mz_zip_reader_init_file_v2_rpb(mz_zip_archive *pZip, - const char *pFilename, - mz_uint flags, - mz_uint64 file_start_ofs, - mz_uint64 archive_size); - + const char *pFilename, + mz_uint flags, + mz_uint64 file_start_ofs, + mz_uint64 archive_size); /* Read an archive from an already opened FILE, beginning at the current file * position. */ @@ -1625,9 +1624,8 @@ MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags); -MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2_noreopen(mz_zip_archive *pZip, - const char *pFilename, - mz_uint flags); +MINIZ_EXPORT mz_bool mz_zip_writer_init_from_reader_v2_noreopen( + mz_zip_archive *pZip, const char *pFilename, mz_uint flags); /* Adds the contents of a memory buffer to an archive. These functions record * the current local time into the archive. */ @@ -5010,6 +5008,13 @@ static int mz_mkdir(const char *pDirname) { #endif /* #ifdef _MSC_VER */ #endif /* #ifdef MINIZ_NO_STDIO */ +#ifndef CHMOD +// Upon successful completion, a value of 0 is returned. +// Otherwise, a value of -1 is returned and errno is set to indicate the error. +// int chmod(const char *path, mode_t mode); +#define CHMOD(f, m) chmod(f, m) +#endif + #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) /* Various ZIP archive enums. To completely avoid cross platform compiler @@ -5975,9 +5980,10 @@ mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, return MZ_TRUE; } -mz_bool mz_zip_reader_init_file_v2_rpb(mz_zip_archive *pZip, const char *pFilename, - mz_uint flags, mz_uint64 file_start_ofs, - mz_uint64 archive_size) { +mz_bool mz_zip_reader_init_file_v2_rpb(mz_zip_archive *pZip, + const char *pFilename, mz_uint flags, + mz_uint64 file_start_ofs, + mz_uint64 archive_size) { mz_uint64 file_size; MZ_FILE *pFile; @@ -8055,8 +8061,8 @@ mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, } mz_bool mz_zip_writer_init_from_reader_v2_noreopen(mz_zip_archive *pZip, - const char *pFilename, - mz_uint flags) { + const char *pFilename, + mz_uint flags) { mz_zip_internal_state *pState; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) @@ -8368,8 +8374,7 @@ mz_bool mz_zip_writer_add_mem_ex_v2( mz_uint user_extra_data_central_len) { mz_uint16 method = 0, dos_time = 0, dos_date = 0; mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; - mz_uint64 local_dir_header_ofs = 0, - cur_archive_file_ofs = 0, comp_size = 0; + mz_uint64 local_dir_header_ofs = 0, cur_archive_file_ofs = 0, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; tdefl_compressor *pComp = NULL; @@ -8679,8 +8684,8 @@ mz_bool mz_zip_writer_add_read_buf_callback( : MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR; mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0; - mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = 0, - uncomp_size = 0, comp_size = 0; + mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = 0, uncomp_size = 0, + comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; mz_uint8 *pExtra_data = NULL; diff --git a/src/zip.c b/src/zip.c index b5b219b..09b3f89 100644 --- a/src/zip.c +++ b/src/zip.c @@ -66,6 +66,14 @@ } \ } while (0) +#define UNX_IFDIR 0040000 /* Unix directory */ +#define UNX_IFREG 0100000 /* Unix regular file */ +#define UNX_IFSOCK 0140000 /* Unix socket (BSD, not SysV or Amiga) */ +#define UNX_IFLNK 0120000 /* Unix symbolic link (not SysV, Amiga) */ +#define UNX_IFBLK 0060000 /* Unix block special (not Amiga) */ +#define UNX_IFCHR 0020000 /* Unix character special (not Amiga) */ +#define UNX_IFIFO 0010000 /* Unix fifo (BCC, not MSC or Amiga) */ + struct zip_entry_t { int index; char *name; @@ -375,8 +383,8 @@ static int zip_archive_extract(mz_zip_archive *zip_archive, const char *dir, (void)xattr; // unused #else xattr = (info.m_external_attr >> 16) & 0xFFFF; - if (xattr > 0) { - if (chmod(path, (mode_t)xattr) < 0) { + if (xattr > 0 && xattr <= MZ_UINT16_MAX) { + if (CHMOD(path, (mode_t)xattr) < 0) { err = ZIP_ENOPERM; goto out; } @@ -830,7 +838,8 @@ struct zip_t *zip_open(const char *zipname, int level, char mode) { goto cleanup; } if ((mode == 'a' || mode == 'd')) { - if (!mz_zip_writer_init_from_reader_v2_noreopen(&(zip->archive), zipname, 0)) { + if (!mz_zip_writer_init_from_reader_v2_noreopen(&(zip->archive), zipname, + 0)) { mz_zip_reader_end(&(zip->archive)); goto cleanup; } @@ -957,7 +966,7 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) { // UNIX or APPLE #if MZ_PLATFORM == 3 || MZ_PLATFORM == 19 - // regular file with rw-r--r-- persmissions + // regular file with rw-r--r-- permissions zip->entry.external_attr = (mz_uint32)(0100644) << 16; #else zip->entry.external_attr = 0; @@ -1315,6 +1324,7 @@ int zip_entry_fwrite(struct zip_t *zip, const char *filename) { MZ_FILE *stream = NULL; mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE]; struct MZ_FILE_STAT_STRUCT file_stat; + mz_uint16 modes; if (!zip) { // zip_t handler is not initialized @@ -1328,11 +1338,32 @@ int zip_entry_fwrite(struct zip_t *zip, const char *filename) { return ZIP_ENOENT; } - if ((file_stat.st_mode & 0200) == 0) { - // MS-DOS read-only attribute - zip->entry.external_attr |= 0x01; +#if defined(_WIN32) || defined(__WIN32__) + (void)modes; // unused +#else + /* Initialize with permission bits--which are not implementation-optional */ + modes = file_stat.st_mode & + (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); + if (S_ISDIR(file_stat.st_mode)) + modes |= UNX_IFDIR; + if (S_ISREG(file_stat.st_mode)) + modes |= UNX_IFREG; + if (S_ISLNK(file_stat.st_mode)) + modes |= UNX_IFLNK; + if (S_ISBLK(file_stat.st_mode)) + modes |= UNX_IFBLK; + if (S_ISCHR(file_stat.st_mode)) + modes |= UNX_IFCHR; + if (S_ISFIFO(file_stat.st_mode)) + modes |= UNX_IFIFO; + if (S_ISSOCK(file_stat.st_mode)) + modes |= UNX_IFSOCK; + zip->entry.external_attr = (modes << 16) | !(file_stat.st_mode & S_IWRITE); + if ((file_stat.st_mode & S_IFMT) == S_IFDIR) { + zip->entry.external_attr |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; } - zip->entry.external_attr |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16); +#endif + zip->entry.m_time = file_stat.st_mtime; if (!(stream = MZ_FOPEN(filename, "rb"))) { @@ -1440,8 +1471,8 @@ int zip_entry_fread(struct zip_t *zip, const char *filename) { } xattr = (info.m_external_attr >> 16) & 0xFFFF; - if (xattr > 0) { - if (chmod(filename, (mode_t)xattr) < 0) { + if (xattr > 0 && xattr <= MZ_UINT16_MAX) { + if (CHMOD(filename, (mode_t)xattr) < 0) { return ZIP_ENOPERM; } } @@ -1607,6 +1638,7 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) { mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; mz_uint32 ext_attributes = 0; + mz_uint16 modes; if (!zipname || strlen(zipname) < 1) { // zip_t archive name is empty or NULL @@ -1641,11 +1673,32 @@ int zip_create(const char *zipname, const char *filenames[], size_t len) { break; } - if ((file_stat.st_mode & 0200) == 0) { - // MS-DOS read-only attribute - ext_attributes |= 0x01; +#if defined(_WIN32) || defined(__WIN32__) + (void)modes; // unused +#else + + /* Initialize with permission bits--which are not implementation-optional */ + modes = file_stat.st_mode & + (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); + if (S_ISDIR(file_stat.st_mode)) + modes |= UNX_IFDIR; + if (S_ISREG(file_stat.st_mode)) + modes |= UNX_IFREG; + if (S_ISLNK(file_stat.st_mode)) + modes |= UNX_IFLNK; + if (S_ISBLK(file_stat.st_mode)) + modes |= UNX_IFBLK; + if (S_ISCHR(file_stat.st_mode)) + modes |= UNX_IFCHR; + if (S_ISFIFO(file_stat.st_mode)) + modes |= UNX_IFIFO; + if (S_ISSOCK(file_stat.st_mode)) + modes |= UNX_IFSOCK; + ext_attributes = (modes << 16) | !(file_stat.st_mode & S_IWRITE); + if ((file_stat.st_mode & S_IFMT) == S_IFDIR) { + ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG; } - ext_attributes |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16); +#endif if (!mz_zip_writer_add_file(&zip_archive, zip_basename(name), name, "", 0, ZIP_DEFAULT_COMPRESSION_LEVEL, diff --git a/test/test_append.c b/test/test_append.c index d79c4dc..8450322 100644 --- a/test/test_append.c +++ b/test/test_append.c @@ -24,9 +24,7 @@ void test_setup(void) { zip_close(zip); } -void test_teardown(void) { - remove(ZIPNAME); -} +void test_teardown(void) { remove(ZIPNAME); } #define TESTDATA2 "Some test data 2...\0" #define CRC32DATA2 2532008468