]> git.seodisparate.com - SimpleArchiver/commitdiff
Impl force file/dir permissions
authorStephen Seo <seo.disparate@gmail.com>
Mon, 23 Dec 2024 08:40:47 +0000 (17:40 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Mon, 23 Dec 2024 08:41:04 +0000 (17:41 +0900)
Added "--force-file-permissions" and "--force-dir-permissions".

Also added "--force-uid" and "--force-gid".

src/archiver.c
src/parser.c
src/parser.h

index 64869e8c49859562938574080da5a72d43b373b9..0517af1f04dd07c7b68a8993923594a8d56c1f66 100644 (file)
@@ -447,32 +447,37 @@ int write_files_fn(void *data, void *ud) {
         return 1;
       }
 
-      if ((stat_buf.st_mode & S_IRUSR) != 0) {
-        ((uint8_t *)temp_to_write->buf)[0] |= 0x2;
-      }
-      if ((stat_buf.st_mode & S_IWUSR) != 0) {
-        ((uint8_t *)temp_to_write->buf)[0] |= 0x4;
-      }
-      if ((stat_buf.st_mode & S_IXUSR) != 0) {
-        ((uint8_t *)temp_to_write->buf)[0] |= 0x8;
-      }
-      if ((stat_buf.st_mode & S_IRGRP) != 0) {
-        ((uint8_t *)temp_to_write->buf)[0] |= 0x10;
-      }
-      if ((stat_buf.st_mode & S_IWGRP) != 0) {
-        ((uint8_t *)temp_to_write->buf)[0] |= 0x20;
-      }
-      if ((stat_buf.st_mode & S_IXGRP) != 0) {
-        ((uint8_t *)temp_to_write->buf)[0] |= 0x40;
-      }
-      if ((stat_buf.st_mode & S_IROTH) != 0) {
-        ((uint8_t *)temp_to_write->buf)[0] |= 0x80;
-      }
-      if ((stat_buf.st_mode & S_IWOTH) != 0) {
-        ((uint8_t *)temp_to_write->buf)[1] |= 0x1;
-      }
-      if ((stat_buf.st_mode & S_IXOTH) != 0) {
-        ((uint8_t *)temp_to_write->buf)[1] |= 0x2;
+      if (state->parsed->flags & 0x1000) {
+        ((uint8_t *)temp_to_write->buf)[0] |= (state->parsed->file_permissions & 0x7F) << 1;
+        ((uint8_t *)temp_to_write->buf)[1] |= (state->parsed->file_permissions & 0x18) >> 7;
+      } else {
+        if ((stat_buf.st_mode & S_IRUSR) != 0) {
+          ((uint8_t *)temp_to_write->buf)[0] |= 0x2;
+        }
+        if ((stat_buf.st_mode & S_IWUSR) != 0) {
+          ((uint8_t *)temp_to_write->buf)[0] |= 0x4;
+        }
+        if ((stat_buf.st_mode & S_IXUSR) != 0) {
+          ((uint8_t *)temp_to_write->buf)[0] |= 0x8;
+        }
+        if ((stat_buf.st_mode & S_IRGRP) != 0) {
+          ((uint8_t *)temp_to_write->buf)[0] |= 0x10;
+        }
+        if ((stat_buf.st_mode & S_IWGRP) != 0) {
+          ((uint8_t *)temp_to_write->buf)[0] |= 0x20;
+        }
+        if ((stat_buf.st_mode & S_IXGRP) != 0) {
+          ((uint8_t *)temp_to_write->buf)[0] |= 0x40;
+        }
+        if ((stat_buf.st_mode & S_IROTH) != 0) {
+          ((uint8_t *)temp_to_write->buf)[0] |= 0x80;
+        }
+        if ((stat_buf.st_mode & S_IWOTH) != 0) {
+          ((uint8_t *)temp_to_write->buf)[1] |= 0x1;
+        }
+        if ((stat_buf.st_mode & S_IXOTH) != 0) {
+          ((uint8_t *)temp_to_write->buf)[1] |= 0x2;
+        }
       }
 
       simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
@@ -616,6 +621,13 @@ int write_files_fn(void *data, void *ud) {
       ((uint8_t *)temp_to_write->buf)[0] |= 0xE;
 #endif
 
+      if (state->parsed->flags & 0x1000) {
+        ((uint8_t *)temp_to_write->buf)[0] = (uint8_t)((state->parsed->file_permissions & 0x7F) << 1);
+
+        ((uint8_t *)temp_to_write->buf)[1] &= 0xC;
+        ((uint8_t *)temp_to_write->buf)[1] |= (uint8_t)((state->parsed->file_permissions & 0x18) >> 7);
+      }
+
       simple_archiver_list_add(to_write, temp_to_write, free_internal_to_write);
 
       // Write file length.
@@ -1625,17 +1637,21 @@ int symlinks_and_files_from_files(void *data, void *ud) {
   const char *user_cwd = ptr_array[2];
   SDArchiverPHeap *pheap = ptr_array[3];
   SDArchiverLinkedList *dirs_list = ptr_array[4];
+  const SDArchiverState *state = ptr_array[5];
 
   if (file_info->filename) {
     if (file_info->link_dest) {
+      // Is a symbolic link.
       simple_archiver_list_add(
           symlinks_list, file_info->filename,
           simple_archiver_helper_datastructure_cleanup_nop);
     } else if (dirs_list && (file_info->flags & 1) != 0) {
+      // Is a directory.
       simple_archiver_list_add(
           dirs_list, file_info->filename,
           simple_archiver_helper_datastructure_cleanup_nop);
     } else {
+      // Is a file.
       SDArchiverInternalFileInfo *file_info_struct =
           malloc(sizeof(SDArchiverInternalFileInfo));
       file_info_struct->filename = strdup(file_info->filename);
@@ -1699,6 +1715,21 @@ int symlinks_and_files_from_files(void *data, void *ud) {
       file_info_struct->uid = stat_buf.st_uid;
       file_info_struct->gid = stat_buf.st_gid;
 #endif
+      if (state->parsed->flags & 0x1000) {
+        file_info_struct->bit_flags[0] = 0;
+        file_info_struct->bit_flags[1] &= 0xFE;
+
+        file_info_struct->bit_flags[0] |=
+          state->parsed->file_permissions & 0xFF;
+        file_info_struct->bit_flags[1] |=
+          (state->parsed->file_permissions & 0x100) >> 8;
+      }
+      if (state->parsed->flags & 0x400) {
+        file_info_struct->uid = state->parsed->uid;
+      }
+      if (state->parsed->flags & 0x800) {
+        file_info_struct->gid = state->parsed->gid;
+      }
       __attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *fd =
           fopen(file_info_struct->filename, "rb");
       if (!fd) {
@@ -1781,7 +1812,9 @@ void simple_archiver_internal_paths_to_files_map(SDArchiverHashMap *files_map,
 
 int internal_write_dir_entries(void *data, void *ud) {
   const char *dir = data;
-  FILE *out_f = ud;
+  void **ptrs = ud;
+  FILE *out_f = ptrs[0];
+  const SDArchiverState *state = ptrs[1];
 
   fprintf(stderr, "  %s\n", dir);
 
@@ -1820,29 +1853,33 @@ int internal_write_dir_entries(void *data, void *ud) {
 
   uint8_t u8 = 0;
 
-  if ((stat_buf.st_mode & S_IRUSR) != 0) {
-    u8 |= 1;
-  }
-  if ((stat_buf.st_mode & S_IWUSR) != 0) {
-    u8 |= 2;
-  }
-  if ((stat_buf.st_mode & S_IXUSR) != 0) {
-    u8 |= 4;
-  }
-  if ((stat_buf.st_mode & S_IRGRP) != 0) {
-    u8 |= 8;
-  }
-  if ((stat_buf.st_mode & S_IWGRP) != 0) {
-    u8 |= 0x10;
-  }
-  if ((stat_buf.st_mode & S_IXGRP) != 0) {
-    u8 |= 0x20;
-  }
-  if ((stat_buf.st_mode & S_IROTH) != 0) {
-    u8 |= 0x40;
-  }
-  if ((stat_buf.st_mode & S_IWOTH) != 0) {
-    u8 |= 0x80;
+  if (state && state->parsed->flags & 0x2000) {
+    u8 = state->parsed->dir_permissions & 0xFF;
+  } else {
+    if ((stat_buf.st_mode & S_IRUSR) != 0) {
+      u8 |= 1;
+    }
+    if ((stat_buf.st_mode & S_IWUSR) != 0) {
+      u8 |= 2;
+    }
+    if ((stat_buf.st_mode & S_IXUSR) != 0) {
+      u8 |= 4;
+    }
+    if ((stat_buf.st_mode & S_IRGRP) != 0) {
+      u8 |= 8;
+    }
+    if ((stat_buf.st_mode & S_IWGRP) != 0) {
+      u8 |= 0x10;
+    }
+    if ((stat_buf.st_mode & S_IXGRP) != 0) {
+      u8 |= 0x20;
+    }
+    if ((stat_buf.st_mode & S_IROTH) != 0) {
+      u8 |= 0x40;
+    }
+    if ((stat_buf.st_mode & S_IWOTH) != 0) {
+      u8 |= 0x80;
+    }
   }
 
   if(fwrite(&u8, 1, 1, out_f) != 1) {
@@ -1853,8 +1890,12 @@ int internal_write_dir_entries(void *data, void *ud) {
   }
 
   u8 = 0;
-  if ((stat_buf.st_mode & S_IXOTH) != 0) {
-    u8 |= 1;
+  if (state && state->parsed->flags & 0x2000) {
+    u8 = (state->parsed->dir_permissions & 0x100) >> 8;
+  } else {
+    if ((stat_buf.st_mode & S_IXOTH) != 0) {
+      u8 |= 1;
+    }
   }
 
   if (fwrite(&u8, 1, 1, out_f) != 1) {
@@ -1882,6 +1923,20 @@ int internal_write_dir_entries(void *data, void *ud) {
   return 0;
 }
 
+mode_t simple_archiver_internal_permissions_to_mode_t(uint_fast16_t permissions)
+{
+  return
+      ((permissions & 1) ? S_IRUSR : 0)
+    | ((permissions & 2) ? S_IWUSR : 0)
+    | ((permissions & 4) ? S_IXUSR : 0)
+    | ((permissions & 8) ? S_IRGRP : 0)
+    | ((permissions & 0x10) ? S_IWGRP : 0)
+    | ((permissions & 0x20) ? S_IXGRP : 0)
+    | ((permissions & 0x40) ? S_IROTH : 0)
+    | ((permissions & 0x80) ? S_IWOTH : 0)
+    | ((permissions & 0x100) ? S_IXOTH : 0);
+}
+
 char *simple_archiver_error_to_string(enum SDArchiverStateReturns error) {
   switch (error) {
     case SDAS_SUCCESS:
@@ -2137,12 +2192,13 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
           ? simple_archiver_priority_heap_init_less_fn(greater_fn)
           : NULL;
 
-  ptr_array = malloc(sizeof(void *) * 5);
+  ptr_array = malloc(sizeof(void *) * 6);
   ptr_array[0] = symlinks_list;
   ptr_array[1] = files_list;
   ptr_array[2] = (void *)state->parsed->user_cwd;
   ptr_array[3] = files_pheap;
   ptr_array[4] = NULL;
+  ptr_array[5] = state;
 
   if (simple_archiver_list_get(filenames, symlinks_and_files_from_files,
                                ptr_array)) {
@@ -2599,11 +2655,15 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
         return SDAS_FAILED_TO_WRITE;
       }
       // UID and GID.
+
+      // Forced UID/GID is already handled by "symlinks_and_files_from_files".
+
       u32 = file_info_struct->uid;
       simple_archiver_helper_32_bit_be(&u32);
       if (fwrite(&u32, 4, 1, out_f) != 1) {
         return SDAS_FAILED_TO_WRITE;
       }
+
       u32 = file_info_struct->gid;
       simple_archiver_helper_32_bit_be(&u32);
       if (fwrite(&u32, 4, 1, out_f) != 1) {
@@ -2996,12 +3056,13 @@ int simple_archiver_write_v2(FILE *out_f, SDArchiverState *state,
           ? simple_archiver_priority_heap_init_less_fn(greater_fn)
           : NULL;
 
-  ptr_array = malloc(sizeof(void *) * 5);
+  ptr_array = malloc(sizeof(void *) * 6);
   ptr_array[0] = symlinks_list;
   ptr_array[1] = files_list;
   ptr_array[2] = (void *)state->parsed->user_cwd;
   ptr_array[3] = files_pheap;
   ptr_array[4] = dirs_list;
+  ptr_array[5] = state;
 
   if (simple_archiver_list_get(filenames, symlinks_and_files_from_files,
                                ptr_array)) {
@@ -3472,6 +3533,9 @@ int simple_archiver_write_v2(FILE *out_f, SDArchiverState *state,
         return SDAS_FAILED_TO_WRITE;
       }
       // UID and GID.
+
+      // Forced UID/GID is already handled by "symlinks_and_files_from_files".
+
       u32 = file_info_struct->uid;
       simple_archiver_helper_32_bit_be(&u32);
       if (fwrite(&u32, 4, 1, out_f) != 1) {
@@ -3852,9 +3916,17 @@ int simple_archiver_write_v2(FILE *out_f, SDArchiverState *state,
     return SDAS_FAILED_TO_WRITE;
   }
 
-  if (simple_archiver_list_get(dirs_list, internal_write_dir_entries, out_f)) {
+  void **void_ptrs = malloc(sizeof(void*) * 2);
+  void_ptrs[0] = out_f;
+  void_ptrs[1] = state;
+
+  if (simple_archiver_list_get(dirs_list,
+                               internal_write_dir_entries,
+                               void_ptrs)) {
+    free(void_ptrs);
     return SDAS_INTERNAL_ERROR;
   }
+  free(void_ptrs);
 
   return SDAS_SUCCESS;
 }
@@ -4244,6 +4316,15 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
 
 #endif
 
+    if (state && state->parsed->flags & 0x1000 && do_extract) {
+      fprintf(stderr,
+              "NOTICE: Forcing permissions as specified by "
+              "\"--force-file-permissions\"!\n");
+      permissions =
+        simple_archiver_internal_permissions_to_mode_t(
+          state->parsed->file_permissions);
+    }
+
     if ((buf[0] & 1) == 0) {
       // Not a sybolic link.
       if (fread(&u64, 8, 1, in_f) != 1) {
@@ -4268,7 +4349,15 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
       if (do_extract && !skip && !skip_due_to_map) {
         fprintf(stderr, "  Extracting...\n");
 
-        simple_archiver_helper_make_dirs((const char *)out_f_name);
+        simple_archiver_helper_make_dirs_perms(
+          (const char *)out_f_name,
+          (state->parsed->flags & 0x2000)
+            ? simple_archiver_internal_permissions_to_mode_t(
+                state->parsed->dir_permissions)
+            : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH),
+          (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(),
+          (state->parsed->flags & 0x800) ? state->parsed->gid : getgid());
+
         out_f = fopen(out_f_name, "wb");
         if (!out_f) {
           fprintf(stderr,
@@ -4621,7 +4710,14 @@ int simple_archiver_parse_archive_version_0(FILE *in_f, int_fast8_t do_extract,
       }
 
       if (do_extract && !skip) {
-        simple_archiver_helper_make_dirs((const char *)out_f_name);
+        simple_archiver_helper_make_dirs_perms(
+          (const char *)out_f_name,
+          (state->parsed->flags & 0x2000)
+            ? simple_archiver_internal_permissions_to_mode_t(
+                state->parsed->dir_permissions)
+            : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH),
+          (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(),
+          (state->parsed->flags & 0x800) ? state->parsed->gid : getgid());
         if (abs_path && rel_path) {
           if (abs_preferred) {
 #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
@@ -5000,7 +5096,14 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
 #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC ||          \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
-        simple_archiver_helper_make_dirs(link_name);
+        simple_archiver_helper_make_dirs_perms(
+          link_name,
+          (state->parsed->flags & 0x2000)
+            ? simple_archiver_internal_permissions_to_mode_t(
+                state->parsed->dir_permissions)
+            : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH),
+          (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(),
+          (state->parsed->flags & 0x800) ? state->parsed->gid : getgid());
         int_fast8_t link_create_retry = 0;
       V1_SYMLINK_CREATE_RETRY_0:
         ret = symlink(path, link_name);
@@ -5073,7 +5176,14 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
 #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC ||          \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
-        simple_archiver_helper_make_dirs(link_name);
+        simple_archiver_helper_make_dirs_perms(
+          link_name,
+          (state->parsed->flags & 0x2000)
+            ? simple_archiver_internal_permissions_to_mode_t(
+                state->parsed->dir_permissions)
+            : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH),
+          (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(),
+          (state->parsed->flags & 0x800) ? state->parsed->gid : getgid());
         int_fast8_t link_create_retry = 0;
       V1_SYMLINK_CREATE_RETRY_1:
         ret = symlink(path, link_name);
@@ -5114,6 +5224,21 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
                     errno);
           }
         }
+        if (state->parsed->flags & 0x400 || state->parsed->flags & 0x800) {
+          ret = fchownat(
+              AT_FDCWD,
+              link_name,
+              state->parsed->flags & 0x400 ? state->parsed->uid : getuid(),
+              state->parsed->flags & 0x800 ? state->parsed->gid : getgid(),
+              AT_SYMLINK_NOFOLLOW);
+          if (ret == -1) {
+            fprintf(stderr,
+                    "WARNING: Failed to force set UID/GID of symlink \"%s\""
+                    "(errno %d)!\n",
+                    link_name,
+                    errno);
+          }
+        }
         link_extracted = 1;
         fprintf(stderr, "  %s -> %s\n", link_name, path);
       V1_SYMLINK_CREATE_AFTER_1:
@@ -5222,14 +5347,22 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
       }
       memcpy(&u32, buf, 4);
       simple_archiver_helper_32_bit_be(&u32);
-      file_info->uid = u32;
+      if (state && (state->parsed->flags & 0x400)) {
+        file_info->uid = state->parsed->uid;
+      } else {
+        file_info->uid = u32;
+      }
 
       if (fread(buf, 1, 4, in_f) != 4) {
         return SDAS_INVALID_FILE;
       }
       memcpy(&u32, buf, 4);
       simple_archiver_helper_32_bit_be(&u32);
-      file_info->gid = u32;
+      if (state && (state->parsed->flags & 0x800)) {
+        file_info->gid = state->parsed->gid;
+      } else {
+        file_info->gid = u32;
+      }
 
       if (fread(buf, 1, 8, in_f) != 8) {
         return SDAS_INVALID_FILE;
@@ -5388,8 +5521,16 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
 #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC ||          \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
-          mode_t permissions =
-              permissions_from_bits_version_1(file_info->bit_flags, 0);
+          mode_t permissions;
+          if (state->parsed->flags & 0x1000) {
+            permissions =
+              simple_archiver_internal_permissions_to_mode_t(
+                state->parsed->file_permissions);
+          } else {
+            permissions = permissions_from_bits_version_1(
+              file_info->bit_flags,
+              0);
+          }
 #endif
           if ((state->parsed->flags & 8) == 0) {
             // Check if file already exists.
@@ -5411,7 +5552,14 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
             }
           }
 
-          simple_archiver_helper_make_dirs(file_info->filename);
+          simple_archiver_helper_make_dirs_perms(
+            file_info->filename,
+            (state->parsed->flags & 0x2000)
+              ? simple_archiver_internal_permissions_to_mode_t(
+                  state->parsed->dir_permissions)
+              : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH),
+            (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(),
+            (state->parsed->flags & 0x800) ? state->parsed->gid : getgid());
           int ret = read_decomp_to_out_file(
               file_info->filename, pipe_outof_read, (char *)buf,
               SIMPLE_ARCHIVER_BUFFER_SIZE, file_info->file_size,
@@ -5510,8 +5658,18 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
 #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC ||          \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
-          mode_t permissions =
+          mode_t permissions;
+
+          if (state->parsed->flags & 0x1000) {
+            permissions = simple_archiver_internal_permissions_to_mode_t(
+              state->parsed->file_permissions);
+            fprintf(stderr,
+                    "NOTICE: Forcing permissions as specified by "
+                    "\"--force-file-permissions\"!\n");
+          } else {
+            permissions =
               permissions_from_bits_version_1(file_info->bit_flags, 0);
+          }
 #endif
           if ((state->parsed->flags & 8) == 0) {
             // Check if file already exists.
@@ -5530,7 +5688,14 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
               continue;
             }
           }
-          simple_archiver_helper_make_dirs(file_info->filename);
+          simple_archiver_helper_make_dirs_perms(
+            file_info->filename,
+            (state->parsed->flags & 0x2000)
+              ? simple_archiver_internal_permissions_to_mode_t(
+                  state->parsed->dir_permissions)
+              : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH),
+            (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(),
+            (state->parsed->flags & 0x800) ? state->parsed->gid : getgid());
           __attribute__((cleanup(simple_archiver_helper_cleanup_FILE)))
           FILE *out_fd = fopen(file_info->filename, "wb");
           int ret = read_fd_to_out_fd(in_f, out_fd, (char *)buf,
@@ -5544,6 +5709,9 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC ||          \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
           if (chmod(file_info->filename, permissions) == -1) {
+            fprintf(stderr,
+                    "ERROR Failed to set permissions of file \"%s\"!\n",
+                    file_info->filename);
             return SDAS_INTERNAL_ERROR;
           } else if (geteuid() == 0 &&
                      chown(file_info->filename, file_info->uid,
@@ -5708,10 +5876,13 @@ int simple_archiver_parse_archive_version_2(FILE *in_f, int_fast8_t do_extract,
     //fprintf(stderr, "DEBUG: abs_path is \"%s\"!\n", abs_path);
 
     int ret = simple_archiver_helper_make_dirs_perms(
-                abs_path,
-                permissions_from_bits_version_1(perms_flags, 0),
-                uid,
-                gid);
+      abs_path,
+      state && (state->parsed->flags & 0x2000)
+        ? simple_archiver_internal_permissions_to_mode_t(
+            state->parsed->dir_permissions)
+        : (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH),
+      state && (state->parsed->flags & 0x400) ? state->parsed->uid : getuid(),
+      state && (state->parsed->flags & 0x800) ? state->parsed->gid : getgid());
     if (ret != 0) {
       fprintf(stderr, "ERROR: Failed to make dirs (%d)!\n", ret);
       return SDAS_INTERNAL_ERROR;
index 51eb858d95bb6ada723027e696d76926ee12a379..d46e6036e2008f4032cd402affed20ce7274853b 100644 (file)
@@ -193,6 +193,18 @@ void simple_archiver_print_usage(void) {
   fprintf(stderr,
           "--no-preserve-empty-dirs : do NOT preserve empty dirs (only for file"
           " format 2 and onwards)\n");
+  fprintf(stderr,
+          "--force-uid <uid> : Force set UID on archive creation/extraction\n");
+  fprintf(stderr,
+          "--force-gid <gid> : Force set GID on archive creation/extraction\n");
+  fprintf(stderr,
+          "--force-file-permissions <3-octal-values> : Force set permissions "
+          "for files on archive creation/extraction\n"
+          "  Must be three octal characters like \"755\" or \"440\"\n");
+  fprintf(stderr,
+          "--force-dir-permissions <3-octal-values> : Force set permissions "
+          "for directories on archive creation/extraction\n"
+          "  Must be three octal characters like \"755\" or \"440\"\n");
   fprintf(stderr,
           "-- : specifies remaining arguments are files to archive/extract\n");
   fprintf(
@@ -215,6 +227,10 @@ SDArchiverParsed simple_archiver_create_parsed(void) {
   parsed.user_cwd = NULL;
   parsed.write_version = 2;
   parsed.minimum_chunk_size = 4194304;
+  parsed.uid = 0;
+  parsed.gid = 0;
+  parsed.file_permissions = 0;
+  parsed.dir_permissions = 0;
 
   return parsed;
 }
@@ -371,6 +387,116 @@ int simple_archiver_parse_args(int argc, const char **argv,
         out->flags &= 0xFFFFFFBF;
       } else if (strcmp(argv[0], "--no-preserve-empty-dirs") == 0) {
         out->flags |= 0x200;
+      } else if (strcmp(argv[0], "--force-uid") == 0) {
+        if (argc < 2) {
+          fprintf(stderr, "ERROR: --force-uid expects an integer argument!\n");
+          simple_archiver_print_usage();
+          return 1;
+        }
+        unsigned long long uid = strtoull(argv[1], NULL, 10);
+        if (uid == 0 && strcmp(argv[1], "0") != 0) {
+          fprintf(stderr, "ERROR: Failed to parse --force-uid <UID>!\n");
+          simple_archiver_print_usage();
+          return 1;
+        } else if (uid > 0xFFFFFFFF) {
+          fprintf(stderr,
+                  "ERROR: UID Is too large (expecting unsigned 32-bit "
+                  "value)!\n");
+          simple_archiver_print_usage();
+          return 1;
+        }
+        out->uid = (uint32_t)uid;
+        out->flags |= 0x400;
+        --argc;
+        ++argv;
+      } else if (strcmp(argv[0], "--force-gid") == 0) {
+        if (argc < 2) {
+          fprintf(stderr, "ERROR: --force-gid expects an integer argument!\n");
+          simple_archiver_print_usage();
+          return 1;
+        }
+        unsigned long long gid = strtoull(argv[1], NULL, 10);
+        if (gid == 0 && strcmp(argv[1], "0") != 0) {
+          fprintf(stderr, "ERROR: Failed to parse --force-gid <GID>!\n");
+          simple_archiver_print_usage();
+          return 1;
+        } else if (gid > 0xFFFFFFFF) {
+          fprintf(stderr,
+                  "ERROR: GID Is too large (expecting unsigned 32-bit "
+                  "value)!\n");
+          simple_archiver_print_usage();
+          return 1;
+        }
+        out->gid = (uint32_t)gid;
+        out->flags |= 0x800;
+        --argc;
+        ++argv;
+      } else if (strcmp(argv[0], "--force-file-permissions") == 0) {
+        if (argc < 2
+            || strlen(argv[1]) != 3
+            || (!(argv[1][0] >= '0' && argv[1][0] <= '7'))
+            || (!(argv[1][1] >= '0' && argv[1][1] <= '7'))
+            || (!(argv[1][2] >= '0' && argv[1][2] <= '7'))
+              ) {
+          fprintf(stderr,
+                  "ERROR: --force-file-permissions expects 3 octal values "
+                  "(e.g. \"755\" or \"440\")!\n");
+          simple_archiver_print_usage();
+          return 1;
+        }
+
+        uint_fast8_t value = (uint_fast8_t)(argv[1][0] - '0');
+        out->file_permissions |= (value & 4) ? 1 : 0;
+        out->file_permissions |= (value & 2) ? 2 : 0;
+        out->file_permissions |= (value & 1) ? 4 : 0;
+
+        value = (uint_fast8_t)(argv[1][1] - '0');
+        out->file_permissions |= (value & 4) ? 8 : 0;
+        out->file_permissions |= (value & 2) ? 0x10 : 0;
+        out->file_permissions |= (value & 1) ? 0x20 : 0;
+
+        value = (uint_fast8_t)(argv[1][2] - '0');
+        out->file_permissions |= (value & 4) ? 0x40 : 0;
+        out->file_permissions |= (value & 2) ? 0x80 : 0;
+        out->file_permissions |= (value & 1) ? 0x100 : 0;
+
+        out->flags |= 0x1000;
+
+        --argc;
+        ++argv;
+      } else if (strcmp(argv[0], "--force-dir-permissions") == 0) {
+        if (argc < 2
+            || strlen(argv[1]) != 3
+            || (!(argv[1][0] >= '0' && argv[1][0] <= '7'))
+            || (!(argv[1][1] >= '0' && argv[1][1] <= '7'))
+            || (!(argv[1][2] >= '0' && argv[1][2] <= '7'))
+              ) {
+          fprintf(stderr,
+                  "ERROR: --force-dir-permissions expects 3 octal values "
+                  "(e.g. \"755\" or \"440\")!\n");
+          simple_archiver_print_usage();
+          return 1;
+        }
+
+        uint_fast8_t value = (uint_fast8_t)(argv[1][0] - '0');
+        out->dir_permissions |= (value & 4) ? 1 : 0;
+        out->dir_permissions |= (value & 2) ? 2 : 0;
+        out->dir_permissions |= (value & 1) ? 4 : 0;
+
+        value = (uint_fast8_t)(argv[1][1] - '0');
+        out->dir_permissions |= (value & 4) ? 8 : 0;
+        out->dir_permissions |= (value & 2) ? 0x10 : 0;
+        out->dir_permissions |= (value & 1) ? 0x20 : 0;
+
+        value = (uint_fast8_t)(argv[1][2] - '0');
+        out->dir_permissions |= (value & 4) ? 0x40 : 0;
+        out->dir_permissions |= (value & 2) ? 0x80 : 0;
+        out->dir_permissions |= (value & 1) ? 0x100 : 0;
+
+        out->flags |= 0x2000;
+
+        --argc;
+        ++argv;
       } else if (argv[0][0] == '-' && argv[0][1] == '-' && argv[0][2] == 0) {
         is_remaining_args = 1;
       } else if (argv[0][0] != '-') {
index e4d6416d83fb9f41c9bb84f3d46b8e12fc66fdb4..4660f5e1844a8eeaa29e9ae846dfc43d627b64e0 100644 (file)
@@ -39,6 +39,10 @@ typedef struct SDArchiverParsed {
   /// 0b 1xxx xxxx - No safe links.
   /// 0b xxxx xxx1 xxxx xxxx - Preserve symlink target.
   /// 0b xxxx xx1x xxxx xxxx - Ignore empty directories if set.
+  /// 0b xxxx x1xx xxxx xxxx - Force set UID.
+  /// 0b xxxx 1xxx xxxx xxxx - Force set GID.
+  /// 0b xxx1 xxxx xxxx xxxx - Force set file permissions.
+  /// 0b xx1x xxxx xxxx xxxx - Force set directory permissions.
   uint32_t flags;
   /// Null-terminated string.
   char *filename;
@@ -59,6 +63,19 @@ typedef struct SDArchiverParsed {
   uint32_t write_version;
   /// The minimum size of a chunk in bytes (the last chunk may be less).
   uint64_t minimum_chunk_size;
+  uint32_t uid;
+  uint32_t gid;
+  /// 0b xxxx xxxx xxx1 - user read
+  /// 0b xxxx xxxx xx1x - user write
+  /// 0b xxxx xxxx x1xx - user execute
+  /// 0b xxxx xxxx 1xxx - group read
+  /// 0b xxxx xxx1 xxxx - group write
+  /// 0b xxxx xx1x xxxx - group execute
+  /// 0b xxxx x1xx xxxx - other read
+  /// 0b xxxx 1xxx xxxx - other write
+  /// 0b xxx1 xxxx xxxx - other execute
+  uint_fast16_t file_permissions;
+  uint_fast16_t dir_permissions;
 } SDArchiverParsed;
 
 typedef struct SDArchiverFileInfo {