]> git.seodisparate.com - SimpleArchiver/commitdiff
Add `--extract-prefer-uid`, `--extract-prefer-gid`
authorStephen Seo <seo.disparate@gmail.com>
Fri, 3 Jan 2025 07:21:02 +0000 (16:21 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Fri, 3 Jan 2025 07:37:33 +0000 (16:37 +0900)
src/archiver.c
src/parser.c
src/parser.h

index b2e512aede73d655452fc901e3b59891671c4df6..bfdd4afb6a80bb68f3602ada8cb4dd296eefda30 100644 (file)
@@ -7433,6 +7433,14 @@ int simple_archiver_parse_archive_version_3(FILE *in_f, int_fast8_t do_extract,
       fprintf(stderr, "  Username does not exist for this link\n");
     }
 
+    uint32_t *username_uid_mapped = NULL;
+    if (state && username) {
+      username_uid_mapped = simple_archiver_hash_map_get(
+        state->parsed->users_infos.UnameToUid,
+        username,
+        u16 + 1);
+    }
+
     if (fread(&u16, 2, 1, in_f) != 1) {
       fprintf(stderr,
               "  ERROR: Failed to read Groupname length for symlink!\n");
@@ -7456,13 +7464,28 @@ int simple_archiver_parse_archive_version_3(FILE *in_f, int_fast8_t do_extract,
       fprintf(stderr, "  Groupname does not exist for this link\n");
     }
 
+    uint32_t *group_gid_mapped = NULL;
+    if (state && groupname) {
+      group_gid_mapped = simple_archiver_hash_map_get(
+        state->parsed->users_infos.GnameToGid,
+        groupname,
+        u16 + 1);
+    }
+
     if (do_extract && link_extracted && geteuid() == 0) {
-      // TODO Be able to set preference between UID/GID and user/group name.
+      uint32_t picked_uid =
+        (state->parsed->flags & 0x4000) || !username_uid_mapped
+        ? uid
+        : *username_uid_mapped;
+      uint32_t picked_gid =
+        (state->parsed->flags & 0x8000) || !group_gid_mapped
+        ? gid
+        : *group_gid_mapped;
       ret = fchownat(
           AT_FDCWD,
           link_name,
-          state->parsed->flags & 0x400 ? state->parsed->uid : uid,
-          state->parsed->flags & 0x800 ? state->parsed->gid : gid,
+          state->parsed->flags & 0x400 ? state->parsed->uid : picked_uid,
+          state->parsed->flags & 0x800 ? state->parsed->gid : picked_gid,
           AT_SYMLINK_NOFOLLOW);
       if (ret == -1) {
         fprintf(stderr,
@@ -7622,6 +7645,30 @@ int simple_archiver_parse_archive_version_3(FILE *in_f, int_fast8_t do_extract,
         groupname = NULL;
       }
 
+      if (state && file_info->username) {
+        uint32_t *username_uid = simple_archiver_hash_map_get(
+          state->parsed->users_infos.UnameToUid,
+          file_info->username,
+          strlen(file_info->username) + 1);
+        if ((state->parsed->flags & 0x400) == 0
+            && (state->parsed->flags & 0x4000) == 0
+            && username_uid) {
+          file_info->uid = *username_uid;
+        }
+      }
+
+      if (state && file_info->groupname) {
+        uint32_t *groupname_gid = simple_archiver_hash_map_get(
+          state->parsed->users_infos.GnameToGid,
+          file_info->groupname,
+          strlen(file_info->groupname) + 1);
+        if ((state->parsed->flags & 0x800) == 0
+            && (state->parsed->flags & 0x8000) == 0
+            && groupname_gid) {
+          file_info->gid = *groupname_gid;
+        }
+      }
+
       if (fread(&u64, 8, 1, in_f) != 1) {
         return SDAS_INVALID_FILE;
       }
@@ -7815,8 +7862,8 @@ int simple_archiver_parse_archive_version_3(FILE *in_f, int_fast8_t do_extract,
               ? 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());
+            (state->parsed->flags & 0x400) ? state->parsed->uid : file_info->uid,
+            (state->parsed->flags & 0x800) ? state->parsed->gid : file_info->gid);
           int ret = read_decomp_to_out_file(
               file_info->filename, pipe_outof_read, (char *)buf,
               SIMPLE_ARCHIVER_BUFFER_SIZE, file_info->file_size,
@@ -7830,7 +7877,8 @@ int simple_archiver_parse_archive_version_3(FILE *in_f, int_fast8_t do_extract,
           if (chmod(file_info->filename, permissions) == -1) {
             return SDAS_INTERNAL_ERROR;
           } else if (geteuid() == 0 &&
-                     chown(file_info->filename, file_info->uid,
+                     chown(file_info->filename,
+                           file_info->uid,
                            file_info->gid) != 0) {
             fprintf(stderr,
                     "    ERROR Failed to set UID/GID of file \"%s\"!\n",
@@ -7961,8 +8009,8 @@ int simple_archiver_parse_archive_version_3(FILE *in_f, int_fast8_t do_extract,
               ? 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());
+            (state->parsed->flags & 0x400) ? state->parsed->uid : file_info->uid,
+            (state->parsed->flags & 0x800) ? state->parsed->gid : file_info->gid);
           __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,
@@ -7981,7 +8029,8 @@ int simple_archiver_parse_archive_version_3(FILE *in_f, int_fast8_t do_extract,
                     file_info->filename);
             return SDAS_INTERNAL_ERROR;
           } else if (geteuid() == 0 &&
-                     chown(file_info->filename, file_info->uid,
+                     chown(file_info->filename,
+                           file_info->uid,
                            file_info->gid) != 0) {
             fprintf(stderr,
                     "    ERROR Failed to set UID/GID of file \"%s\"!\n",
@@ -8124,6 +8173,24 @@ int simple_archiver_parse_archive_version_3(FILE *in_f, int_fast8_t do_extract,
 
     if (do_extract) {
       fprintf(stderr, "Creating dir \"%s\"\n", buf);
+      if ((state->parsed->flags & 0x4000) == 0 && username) {
+        uint32_t *username_uid = simple_archiver_hash_map_get(
+          state->parsed->users_infos.UnameToUid,
+          username,
+          strlen(username) + 1);
+        if (username_uid) {
+          uid = *username_uid;
+        }
+      }
+      if ((state->parsed->flags & 0x8000) == 0 && groupname) {
+        uint32_t *group_gid = simple_archiver_hash_map_get(
+          state->parsed->users_infos.GnameToGid,
+          groupname,
+          strlen(groupname) + 1);
+        if (group_gid) {
+          gid = *group_gid;
+        }
+      }
     } else {
       fprintf(stderr, "Dir entry \"%s\"\n", buf);
       fprintf(stderr, "  Permissions: ");
index 2ed41062f53a462f7cd44372ab149170b3fba942..c0d9419d7b4a0ae5e1d0d11b4ff8b9a5273d03c6 100644 (file)
@@ -212,6 +212,14 @@ void simple_archiver_print_usage(void) {
           "  On archive creation, sets GID for all files/dirs in the archive.\n"
           "  On archive extraction, sets GID for all files/dirs only if EUID is"
           " 0.\n");
+  fprintf(stderr,
+          "--extract-prefer-uid : Prefer UID over Username when extracting\n");
+  fprintf(stderr,
+          "  Note that by default Username is preferred over UID\n");
+  fprintf(stderr,
+          "--extract-prefer-gid : Prefer GID over Group when extracting\n");
+  fprintf(stderr,
+          "  Note that by default Group is preferred over UID\n");
   fprintf(stderr,
           "--force-file-permissions <3-octal-values> : Force set permissions "
           "for files on archive creation/extraction\n"
@@ -481,6 +489,10 @@ int simple_archiver_parse_args(int argc, const char **argv,
         out->flags |= 0x800;
         --argc;
         ++argv;
+      } else if (strcmp(argv[0], "--extract-prefer-uid") == 0) {
+        out->flags |= 0x4000;
+      } else if (strcmp(argv[0], "--extract-prefer-gid") == 0) {
+        out->flags |= 0x8000;
       } else if (strcmp(argv[0], "--force-file-permissions") == 0) {
         if (argc < 2
             || strlen(argv[1]) != 3
index f2a42842662995a1cce0ba7e8f5843ed7fa07ad2..88b69f2aed50680e0bbe1415fcab6c332797cab3 100644 (file)
@@ -44,6 +44,8 @@ typedef struct SDArchiverParsed {
   /// 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.
+  /// 0b x1xx xxxx xxxx xxxx - Prefer UID over Username when extracting.
+  /// 0b 1xxx xxxx xxxx xxxx - Prefer GID over Group when extracting.
   uint32_t flags;
   /// Null-terminated string.
   char *filename;