Impl. setup for de/compression
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 4s

Some setup code in preparation of doing the actual file compression when
creating an archive.
This commit is contained in:
Stephen Seo 2024-07-17 14:32:39 +09:00
parent 0299129ea6
commit ea845f2552
5 changed files with 159 additions and 0 deletions

View file

@ -22,6 +22,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.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" #include "helpers.h"
typedef struct SDArchiverInternalToWrite { typedef struct SDArchiverInternalToWrite {
@ -465,3 +473,41 @@ int simple_archiver_print_archive_info(FILE *in_f) {
return 0; 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;
}

View file

@ -55,4 +55,8 @@ int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
/// Returns zero on success. /// Returns zero on success.
int simple_archiver_print_archive_info(FILE *in_f); 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 #endif

View file

@ -18,6 +18,10 @@
#include "helpers.h" #include "helpers.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
int simple_archiver_helper_is_big_endian(void) { int simple_archiver_helper_is_big_endian(void) {
union { union {
uint32_t i; 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;
}
}

View 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. /// Swaps value from/to big-endian. Nop on big-endian systems.
void simple_archiver_helper_64_bit_be(uint64_t *value); 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 #endif

View file

@ -44,6 +44,15 @@ static int checks_passed = 0;
++checks_passed; \ ++checks_passed; \
} \ } \
} while (0); } 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) { int main(void) {
// Test parser. // 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 checked: %u\n", checks_checked);
printf("Checks passed: %u\n", checks_passed); printf("Checks passed: %u\n", checks_passed);
return checks_passed == checks_checked ? 0 : 1; return checks_passed == checks_checked ? 0 : 1;