]> git.seodisparate.com - SimpleArchiver/commitdiff
Store/restore file permissions
authorStephen Seo <seo.disparate@gmail.com>
Thu, 18 Jul 2024 05:02:15 +0000 (14:02 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 18 Jul 2024 05:02:15 +0000 (14:02 +0900)
file_format.md
src/archiver.c

index 4bf944f3a9f335b54594b1a07c06d2bb8ec3afc3..608fc3a5c09673f3856e1681c34de36901d83c05 100644 (file)
@@ -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.
index b8a75765bd417147b9b89d9cf2392b9dd7cba150..b65e31538141d367ce43ec2f6d35f90fdf3d7272 100644 (file)
@@ -29,6 +29,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <spawn.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 #include <unistd.h>
 #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 {