]> git.seodisparate.com - SimpleArchiver/commitdiff
WIP --prefix: Impl --prefix for archive file ver 1
authorStephen Seo <seo.disparate@gmail.com>
Mon, 27 Jan 2025 05:11:27 +0000 (14:11 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Mon, 27 Jan 2025 05:11:27 +0000 (14:11 +0900)
TODO:
    --prefix for extracting file format version 1
    --prefix for archiving/extracting file format versions 2 and 3

src/archiver.c

index e3a62c769b38e4758370bba5c5bdb4dcffcab319..9576aa947b77ee681a71cce29ff0695523552495 100644 (file)
@@ -2523,6 +2523,9 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
 #endif
   }
 
+  const size_t prefix_length = state->parsed->prefix
+                               ? strlen(state->parsed->prefix)
+                               : 0;
   {
     const SDArchiverLLNode *node = symlinks_list->head;
     for (u32 = 0;
@@ -2671,7 +2674,11 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
         return SDAS_FAILED_TO_WRITE;
       }
 
-      size_t len = strlen(node->data);
+      const size_t link_length = strlen(node->data);
+      size_t len = link_length;
+      if (state->parsed->prefix) {
+        len += prefix_length;
+      }
       if (len >= 0xFFFF) {
         fprintf(stderr, "ERROR: Link name is too long!\n");
         return SDAS_INVALID_PARSED_STATE;
@@ -2683,26 +2690,64 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
         return SDAS_FAILED_TO_WRITE;
       }
       simple_archiver_helper_16_bit_be(&u16);
-      if (fwrite(node->data, 1, u16 + 1, out_f) != (size_t)u16 + 1) {
+      if (state->parsed->prefix) {
+        size_t fwrite_ret = fwrite(state->parsed->prefix,
+                                   1,
+                                   prefix_length,
+                                   out_f);
+        fwrite_ret += fwrite(node->data, 1, link_length + 1, out_f);
+        if (fwrite_ret != (size_t)u16 + 1) {
+          return SDAS_FAILED_TO_WRITE;
+        }
+      } else if (fwrite(node->data, 1, u16 + 1, out_f) != (size_t)u16 + 1) {
         return SDAS_FAILED_TO_WRITE;
       }
 
       if (abs_path && (state->parsed->flags & 0x20) == 0 && !is_invalid) {
-        len = strlen(abs_path);
-        if (len >= 0xFFFF) {
-          fprintf(stderr,
-                  "ERROR: Symlink destination absolute path is too long!\n");
-          return SDAS_INVALID_PARSED_STATE;
-        }
+        if (state->parsed->prefix) {
+          __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+          char *abs_path_prefixed =
+            simple_archiver_helper_insert_prefix_in_link_path(
+              state->parsed->prefix, node->data, abs_path);
+          if (!abs_path_prefixed) {
+            fprintf(stderr,
+                    "ERROR: Failed to add prefix to abs symlink!\n");
+            return SDAS_INTERNAL_ERROR;
+          }
+          const size_t abs_path_pref_length = strlen(abs_path_prefixed);
+          if (abs_path_pref_length >= 0xFFFF) {
+            fprintf(stderr,
+                    "ERROR: Symlink destination absolute path with prefix is "
+                    "too long!\n");
+            return SDAS_INVALID_PARSED_STATE;
+          }
 
-        u16 = (uint16_t)len;
-        simple_archiver_helper_16_bit_be(&u16);
-        if (fwrite(&u16, 2, 1, out_f) != 1) {
-          return SDAS_FAILED_TO_WRITE;
-        }
-        simple_archiver_helper_16_bit_be(&u16);
-        if (fwrite(abs_path, 1, u16 + 1, out_f) != (size_t)u16 + 1) {
-          return SDAS_FAILED_TO_WRITE;
+          u16 = (uint16_t)abs_path_pref_length;
+          simple_archiver_helper_16_bit_be(&u16);
+          if (fwrite(&u16, 2, 1, out_f) != 1) {
+            return SDAS_FAILED_TO_WRITE;
+          }
+          simple_archiver_helper_16_bit_be(&u16);
+          if (fwrite(abs_path_prefixed, 1, u16 + 1, out_f) != (size_t)u16 + 1) {
+            return SDAS_FAILED_TO_WRITE;
+          }
+        } else {
+          const size_t abs_path_length = strlen(abs_path);
+          if (abs_path_length >= 0xFFFF) {
+            fprintf(stderr,
+                    "ERROR: Symlink destination absolute path is too long!\n");
+            return SDAS_INVALID_PARSED_STATE;
+          }
+
+          u16 = (uint16_t)abs_path_length;
+          simple_archiver_helper_16_bit_be(&u16);
+          if (fwrite(&u16, 2, 1, out_f) != 1) {
+            return SDAS_FAILED_TO_WRITE;
+          }
+          simple_archiver_helper_16_bit_be(&u16);
+          if (fwrite(abs_path, 1, u16 + 1, out_f) != (size_t)u16 + 1) {
+            return SDAS_FAILED_TO_WRITE;
+          }
         }
       } else {
         u16 = 0;
@@ -2712,21 +2757,50 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
       }
 
       if (rel_path && !is_invalid) {
-        len = strlen(rel_path);
-        if (len >= 0xFFFF) {
-          fprintf(stderr,
-                  "ERROR: Symlink destination relative path is too long!\n");
-          return SDAS_INVALID_PARSED_STATE;
-        }
+        if (state->parsed->prefix) {
+          __attribute__((cleanup(simple_archiver_helper_cleanup_c_string)))
+          char *rel_path_prefixed =
+            simple_archiver_helper_insert_prefix_in_link_path(
+              state->parsed->prefix, node->data, rel_path);
+          if (!rel_path_prefixed) {
+            fprintf(stderr,
+                    "ERROR: Failed to add prefix to relative symlink!\n");
+            return SDAS_INTERNAL_ERROR;
+          }
+          const size_t rel_path_pref_length = strlen(rel_path_prefixed);
+          if (rel_path_pref_length >= 0xFFFF) {
+            fprintf(stderr,
+                    "ERROR: Symlink destination relative path with prefix is "
+                    "too long!\n");
+            return SDAS_INVALID_PARSED_STATE;
+          }
 
-        u16 = (uint16_t)len;
-        simple_archiver_helper_16_bit_be(&u16);
-        if (fwrite(&u16, 2, 1, out_f) != 1) {
-          return SDAS_FAILED_TO_WRITE;
-        }
-        simple_archiver_helper_16_bit_be(&u16);
-        if (fwrite(rel_path, 1, u16 + 1, out_f) != (size_t)u16 + 1) {
-          return SDAS_FAILED_TO_WRITE;
+          u16 = (uint16_t)rel_path_pref_length;
+          simple_archiver_helper_16_bit_be(&u16);
+          if (fwrite(&u16, 2, 1, out_f) != 1) {
+            return SDAS_FAILED_TO_WRITE;
+          }
+          simple_archiver_helper_16_bit_be(&u16);
+          if (fwrite(rel_path_prefixed, 1, u16 + 1, out_f) != (size_t)u16 + 1) {
+            return SDAS_FAILED_TO_WRITE;
+          }
+        } else {
+          len = strlen(rel_path);
+          if (len >= 0xFFFF) {
+            fprintf(stderr,
+                    "ERROR: Symlink destination relative path is too long!\n");
+            return SDAS_INVALID_PARSED_STATE;
+          }
+
+          u16 = (uint16_t)len;
+          simple_archiver_helper_16_bit_be(&u16);
+          if (fwrite(&u16, 2, 1, out_f) != 1) {
+            return SDAS_FAILED_TO_WRITE;
+          }
+          simple_archiver_helper_16_bit_be(&u16);
+          if (fwrite(rel_path, 1, u16 + 1, out_f) != (size_t)u16 + 1) {
+            return SDAS_FAILED_TO_WRITE;
+          }
         }
       } else {
         u16 = 0;
@@ -2843,23 +2917,50 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
       if (non_c_chunk_size) {
         *non_c_chunk_size += file_info_struct->file_size;
       }
-      size_t len = strlen(file_info_struct->filename);
-      if (len >= 0xFFFF) {
-        fprintf(stderr, "ERROR: Filename is too large!\n");
-        return SDAS_INVALID_FILE;
-      }
-      u16 = (uint16_t)len;
-      simple_archiver_helper_16_bit_be(&u16);
-      if (fwrite(&u16, 2, 1, out_f) != 1) {
-        return SDAS_FAILED_TO_WRITE;
+      const size_t filename_len = strlen(file_info_struct->filename);
+      if (state->parsed->prefix) {
+        const size_t total_length = filename_len + prefix_length;
+        if (total_length >= 0xFFFF) {
+          fprintf(stderr, "ERROR: Filename with prefix is too large!\n");
+          return SDAS_INVALID_FILE;
+        }
+        u16 = (uint16_t)total_length;
+        simple_archiver_helper_16_bit_be(&u16);
+        if (fwrite(&u16, 2, 1, out_f) != 1) {
+          return SDAS_FAILED_TO_WRITE;
+        }
+        simple_archiver_helper_16_bit_be(&u16);
+        if (fwrite(state->parsed->prefix, 1, prefix_length, out_f)
+            != prefix_length) {
+          return SDAS_FAILED_TO_WRITE;
+        } else if (fwrite(file_info_struct->filename,
+                          1,
+                          filename_len + 1,
+                          out_f)
+                     != filename_len + 1) {
+          return SDAS_FAILED_TO_WRITE;
+        }
+      } else {
+        if (filename_len >= 0xFFFF) {
+          fprintf(stderr, "ERROR: Filename is too large!\n");
+          return SDAS_INVALID_FILE;
+        }
+        u16 = (uint16_t)filename_len;
+        simple_archiver_helper_16_bit_be(&u16);
+        if (fwrite(&u16, 2, 1, out_f) != 1) {
+          return SDAS_FAILED_TO_WRITE;
+        }
+        simple_archiver_helper_16_bit_be(&u16);
+        if (fwrite(file_info_struct->filename, 1, u16 + 1, out_f) !=
+            (size_t)u16 + 1) {
+          return SDAS_FAILED_TO_WRITE;
+        }
       }
-      simple_archiver_helper_16_bit_be(&u16);
-      if (fwrite(file_info_struct->filename, 1, u16 + 1, out_f) !=
-          (size_t)u16 + 1) {
-        return SDAS_FAILED_TO_WRITE;
-      } else if (fwrite(file_info_struct->bit_flags, 1, 4, out_f) != 4) {
+
+      if (fwrite(file_info_struct->bit_flags, 1, 4, out_f) != 4) {
         return SDAS_FAILED_TO_WRITE;
       }
+
       // UID and GID.
 
       // Forced UID/GID is already handled by "symlinks_and_files_from_files".