From 4cb4184338f80fb8e0560a444589242503457638 Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Thu, 18 Jul 2024 14:02:15 +0900 Subject: [PATCH] Store/restore file permissions --- file_format.md | 10 +++- src/archiver.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 1 deletion(-) diff --git a/file_format.md b/file_format.md index 4bf944f..608fc3a 100644 --- a/file_format.md +++ b/file_format.md @@ -45,8 +45,16 @@ Following the file-count bytes, the following bytes are added for each file: 3. 4 bytes bit-flags 1. The first byte 1. The first bit is set if the file is a symbolic link. + 2. The second bit is "user read permission". + 3. The third bit is "user write permission". + 4. The fourth bit is "user execute permission". + 5. The fifth bit is "group read permission". + 6. The sixth bit is "group write permission". + 7. The seventh bit is "group execute permission". + 8. The eighth bit is "other read permission". 2. The second byte. - 1. Currently unused. + 1. The first bit is "other write permission". + 2. The second bit is "other execute permission". 3. The third byte. 1. Currently unused. 4. The fourth byte. diff --git a/src/archiver.c b/src/archiver.c index b8a7576..b65e315 100644 --- a/src/archiver.c +++ b/src/archiver.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #endif @@ -264,6 +265,50 @@ int write_files_fn(void *data, void *ud) { for (unsigned int idx = 0; idx < temp_to_write->size; ++idx) { ((unsigned char *)temp_to_write->buf)[idx] = 0; } + + // Get file stats. + struct stat stat_buf; + memset(&stat_buf, 0, sizeof(struct stat)); + int stat_fd = open(file_info->filename, O_RDONLY); + if (stat_fd == -1) { + // Error. + return 1; + } + int stat_status = fstat(stat_fd, &stat_buf); + close(stat_fd); + if (stat_status != 0) { + // Error. + return 1; + } + + if ((stat_buf.st_mode & S_IRUSR) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x2; + } + if ((stat_buf.st_mode & S_IWUSR) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x4; + } + if ((stat_buf.st_mode & S_IXUSR) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x8; + } + if ((stat_buf.st_mode & S_IRGRP) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x10; + } + if ((stat_buf.st_mode & S_IWGRP) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x20; + } + if ((stat_buf.st_mode & S_IXGRP) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x40; + } + if ((stat_buf.st_mode & S_IROTH) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x80; + } + if ((stat_buf.st_mode & S_IWOTH) != 0) { + ((unsigned char *)temp_to_write->buf)[1] |= 0x1; + } + if ((stat_buf.st_mode & S_IXOTH) != 0) { + ((unsigned char *)temp_to_write->buf)[1] |= 0x2; + } + simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write); // Get compressed file length. @@ -347,6 +392,54 @@ int write_files_fn(void *data, void *ud) { for (unsigned int idx = 0; idx < temp_to_write->size; ++idx) { ((unsigned char *)temp_to_write->buf)[idx] = 0; } + +#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ + SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ + SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX + // Get file stats. + struct stat stat_buf; + memset(&stat_buf, 0, sizeof(struct stat)); + int stat_fd = open(file_info->filename, O_RDONLY); + if (stat_fd == -1) { + // Error. + return 1; + } + int stat_status = fstat(stat_fd, &stat_buf); + close(stat_fd); + if (stat_status != 0) { + // Error. + return 1; + } + + if ((stat_buf.st_mode & S_IRUSR) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x2; + } + if ((stat_buf.st_mode & S_IWUSR) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x4; + } + if ((stat_buf.st_mode & S_IXUSR) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x8; + } + if ((stat_buf.st_mode & S_IRGRP) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x10; + } + if ((stat_buf.st_mode & S_IWGRP) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x20; + } + if ((stat_buf.st_mode & S_IXGRP) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x40; + } + if ((stat_buf.st_mode & S_IROTH) != 0) { + ((unsigned char *)temp_to_write->buf)[0] |= 0x80; + } + if ((stat_buf.st_mode & S_IWOTH) != 0) { + ((unsigned char *)temp_to_write->buf)[1] |= 0x1; + } + if ((stat_buf.st_mode & S_IXOTH) != 0) { + ((unsigned char *)temp_to_write->buf)[1] |= 0x2; + } +#endif + simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write); // Write file length. @@ -622,6 +715,7 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract, return SDAS_INVALID_FILE; } simple_archiver_helper_16_bit_be(&u16); + __attribute__((cleanup(free_malloced_memory))) void *out_f_name = NULL; __attribute__((cleanup(free_FILE_helper))) FILE *out_f = NULL; if (u16 < 1024) { if (fread(buf, 1, u16 + 1, in_f) != (size_t)u16 + 1) { @@ -647,6 +741,8 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract, if (!skip) { simple_archiver_helper_make_dirs((const char *)buf); out_f = fopen((const char *)buf, "wb"); + out_f_name = malloc(strlen((const char *)buf) + 1); + memcpy(out_f_name, buf, strlen((const char *)buf) + 1); } } } else { @@ -676,6 +772,8 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract, if (!skip) { simple_archiver_helper_make_dirs((const char *)uc_heap_buf); out_f = fopen((const char *)buf, "wb"); + out_f_name = malloc(strlen((const char *)buf) + 1); + memcpy(out_f_name, buf, strlen((const char *)buf) + 1); } } } @@ -684,6 +782,41 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract, return SDAS_INVALID_FILE; } + unsigned int permissions = 0; +#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ + SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ + SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX + + if ((buf[0] & 0x2) != 0) { + permissions |= S_IRUSR; + } + if ((buf[0] & 0x4) != 0) { + permissions |= S_IWUSR; + } + if ((buf[0] & 0x8) != 0) { + permissions |= S_IXUSR; + } + if ((buf[0] & 0x10) != 0) { + permissions |= S_IRGRP; + } + if ((buf[0] & 0x20) != 0) { + permissions |= S_IWGRP; + } + if ((buf[0] & 0x40) != 0) { + permissions |= S_IXGRP; + } + if ((buf[0] & 0x80) != 0) { + permissions |= S_IROTH; + } + if ((buf[1] & 0x1) != 0) { + permissions |= S_IWOTH; + } + if ((buf[1] & 0x2) != 0) { + permissions |= S_IXOTH; + } + +#endif + if ((buf[0] & 1) == 0) { // Not a sybolic link. if (fread(&u64, 8, 1, in_f) != 1) { @@ -833,6 +966,11 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract, waitpid(decompressor_pid, NULL, 0); + if (chmod((const char *)out_f_name, permissions) == -1) { + // Error. + return 1; + } + fprintf(stderr, " Extracted.\n"); #endif } else {