]> git.seodisparate.com - SimpleArchiver/commitdiff
Impl. setup for de/compression
authorStephen Seo <seo.disparate@gmail.com>
Wed, 17 Jul 2024 05:32:39 +0000 (14:32 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 17 Jul 2024 05:32:39 +0000 (14:32 +0900)
Some setup code in preparation of doing the actual file compression when
creating an archive.

src/archiver.c
src/archiver.h
src/helpers.c
src/helpers.h
src/test.c

index 592d121f419885f49483de8e9ae54f75ebd60044..67fa5c2968f25562eb304acaab89328074387c3b 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
+    SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC ||          \
+    SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
+#include <fcntl.h>
+#include <spawn.h>
+#include <unistd.h>
+#endif
+
 #include "helpers.h"
 
 typedef struct SDArchiverInternalToWrite {
@@ -465,3 +473,41 @@ int simple_archiver_print_archive_info(FILE *in_f) {
 
   return 0;
 }
+
+int simple_archiver_de_compress(int pipe_fd_in, int pipe_fd_out,
+                                const char *cmd) {
+  posix_spawn_file_actions_t file_actions;
+  memset(&file_actions, 0, sizeof(file_actions));
+  if (posix_spawn_file_actions_init(&file_actions) != 0) {
+    close(pipe_fd_in);
+    close(pipe_fd_out);
+    return 1;
+  } else if (posix_spawn_file_actions_adddup2(&file_actions, pipe_fd_in, 0) !=
+             0) {
+    posix_spawn_file_actions_destroy(&file_actions);
+    close(pipe_fd_in);
+    close(pipe_fd_out);
+    return 2;
+  } else if (posix_spawn_file_actions_adddup2(&file_actions, pipe_fd_out, 1) !=
+             0) {
+    posix_spawn_file_actions_destroy(&file_actions);
+    close(pipe_fd_in);
+    close(pipe_fd_out);
+    return 3;
+  }
+
+  __attribute__((cleanup(
+      simple_archiver_helper_cmd_string_argv_free_ptr))) char **cmd_argv =
+      simple_archiver_helper_cmd_string_to_argv(cmd);
+
+  pid_t spawned_pid;
+  if (posix_spawnp(&spawned_pid, cmd_argv[0], &file_actions, NULL, cmd_argv,
+                   NULL) != 0) {
+    posix_spawn_file_actions_destroy(&file_actions);
+    return 4;
+  }
+
+  posix_spawn_file_actions_destroy(&file_actions);
+
+  return 0;
+}
index 91ff4e75686acae0a993badaa365141268903419..d0e06970752fceedabead82783a51083a94aadfa 100644 (file)
@@ -55,4 +55,8 @@ int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
 /// Returns zero on success.
 int simple_archiver_print_archive_info(FILE *in_f);
 
+/// Returns zero on success.
+int simple_archiver_de_compress(int pipe_fd_in, int pipe_fd_out,
+                                const char *cmd);
+
 #endif
index 55394489977f1a1d636bfb59092a4de90a76aedd..77a94fb334e439a5f83845052eaae6dc59b55414 100644 (file)
 
 #include "helpers.h"
 
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
 int simple_archiver_helper_is_big_endian(void) {
   union {
     uint32_t i;
@@ -54,3 +58,73 @@ void simple_archiver_helper_64_bit_be(uint64_t *value) {
     }
   }
 }
+
+char **simple_archiver_helper_cmd_string_to_argv(const char *cmd) {
+  unsigned int capacity = 16;
+  unsigned int idx = 0;
+  // Size of every pointer is the same, so using size of (void*) should be ok.
+  char **args = malloc(sizeof(void *) * capacity);
+  memset(args, 0, sizeof(void *) * capacity);
+
+  unsigned int word_capacity = 16;
+  unsigned int word_idx = 0;
+  char *word = malloc(word_capacity);
+  memset(word, 0, word_capacity);
+  for (const char *c = cmd; *c != 0; ++c) {
+    if (isspace(*c)) {
+      if (word_idx > 0) {
+        if (idx >= capacity) {
+          capacity *= 2;
+          args = realloc(args, sizeof(void *) * capacity);
+        }
+        args[idx] = malloc(word_idx + 1);
+        memcpy(args[idx], word, word_idx);
+        args[idx][word_idx] = 0;
+        ++idx;
+        word_idx = 0;
+      }
+    } else {
+      if (word_idx >= word_capacity) {
+        word_capacity *= 2;
+        word = realloc(word, word_capacity);
+      }
+      word[word_idx++] = *c;
+    }
+  }
+  if (word_idx > 0) {
+    if (idx >= capacity) {
+      capacity *= 2;
+      args = realloc(args, sizeof(void *) * capacity);
+    }
+    args[idx] = malloc(word_idx + 1);
+    memcpy(args[idx], word, word_idx);
+    args[idx][word_idx] = 0;
+    ++idx;
+    word_idx = 0;
+  }
+
+  free(word);
+
+  if (idx >= capacity) {
+    args = realloc(args, sizeof(void *) * (capacity + 1));
+    args[capacity] = NULL;
+  }
+
+  return args;
+}
+
+void simple_archiver_helper_cmd_string_argv_free(char **argv_strs) {
+  if (argv_strs) {
+    for (char **iter = argv_strs; *iter != 0; ++iter) {
+      free(*iter);
+    }
+    free(argv_strs);
+  }
+}
+
+void simple_archiver_helper_cmd_string_argv_free_ptr(char ***argv_strs) {
+  if (argv_strs) {
+    simple_archiver_helper_cmd_string_argv_free(*argv_strs);
+    *argv_strs = NULL;
+  }
+}
index cb4c04007d4e1af21542a4a5899c826d00db741d..4643a769f726252026195bdd50a675f1c390fd61 100644 (file)
@@ -35,4 +35,12 @@ void simple_archiver_helper_32_bit_be(uint32_t *value);
 /// Swaps value from/to big-endian. Nop on big-endian systems.
 void simple_archiver_helper_64_bit_be(uint64_t *value);
 
+/// Returns a array of c-strings on success, NULL on error.
+/// The returned array must be free'd with
+/// simple_archiver_helper_cmd_string_argv_free(...).
+char **simple_archiver_helper_cmd_string_to_argv(const char *cmd);
+
+void simple_archiver_helper_cmd_string_argv_free(char **argv_strs);
+void simple_archiver_helper_cmd_string_argv_free_ptr(char ***argv_strs);
+
 #endif
index 6d1dfdba8ea0faf2fe1bbe0c83044793c76b03a2..09a1f9af44f63719f13a7bb0fb9f198f69a1f5a1 100644 (file)
@@ -44,6 +44,15 @@ static int checks_passed = 0;
       ++checks_passed;                                             \
     }                                                              \
   } while (0);
+#define CHECK_STREQ(a, b)                                                    \
+  do {                                                                       \
+    ++checks_checked;                                                        \
+    if (strcmp((a), (b)) == 0) {                                             \
+      ++checks_passed;                                                       \
+    } else {                                                                 \
+      printf("CHECK_STREQ at line %u failed: %s != %s\n", __LINE__, #a, #b); \
+    }                                                                        \
+  } while (0);
 
 int main(void) {
   // Test parser.
@@ -170,6 +179,24 @@ int main(void) {
     }
   }
 
+  // Test helpers cmd string to argv.
+  do {
+    const char *cmd = "zstd  --compress --ultra\n -20  derp_file";
+    char **result_argv = simple_archiver_helper_cmd_string_to_argv(cmd);
+    CHECK_TRUE(result_argv);
+    if (!result_argv) {
+      break;
+    }
+    CHECK_STREQ("zstd", result_argv[0]);
+    CHECK_STREQ("--compress", result_argv[1]);
+    CHECK_STREQ("--ultra", result_argv[2]);
+    CHECK_STREQ("-20", result_argv[3]);
+    CHECK_STREQ("derp_file", result_argv[4]);
+    CHECK_TRUE(result_argv[5] == NULL);
+
+    simple_archiver_helper_cmd_string_argv_free(result_argv);
+  } while (0);
+
   printf("Checks checked: %u\n", checks_checked);
   printf("Checks passed:  %u\n", checks_passed);
   return checks_passed == checks_checked ? 0 : 1;