Compare commits
8 commits
b96d26de81
...
c30f2f3fd2
Author | SHA1 | Date | |
---|---|---|---|
c30f2f3fd2 | |||
4e6b2b8f5a | |||
49bd4b5c76 | |||
4479fdce62 | |||
bdbbf7dc16 | |||
40567d5a3a | |||
c095c40644 | |||
d1609849a1 |
10 changed files with 317 additions and 30 deletions
|
@ -18,6 +18,8 @@ API calls.
|
||||||
-t : examine archive file
|
-t : examine archive file
|
||||||
-f <filename> : filename to work on
|
-f <filename> : filename to work on
|
||||||
Use "-f -" to work on stdout when creating archive or stdin when reading archive
|
Use "-f -" to work on stdout when creating archive or stdin when reading archive
|
||||||
|
NOTICE: "-f" is not affected by "-C"!
|
||||||
|
-C <dir> : Change current working directory before archiving/extracting
|
||||||
--compressor <full_compress_cmd> : requires --decompressor
|
--compressor <full_compress_cmd> : requires --decompressor
|
||||||
--decompressor <full_decompress_cmd> : requires --compressor
|
--decompressor <full_decompress_cmd> : requires --compressor
|
||||||
Specifying "--decompressor" when extracting overrides archive file's stored decompressor cmd
|
Specifying "--decompressor" when extracting overrides archive file's stored decompressor cmd
|
||||||
|
|
|
@ -40,6 +40,8 @@
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#define TEMP_FILENAME_CMP "%s%ssimple_archiver_compressed_%u.tmp"
|
#define TEMP_FILENAME_CMP "%s%ssimple_archiver_compressed_%u.tmp"
|
||||||
|
#define FILE_COUNTS_OUTPUT_FORMAT_STR_0 "\nFile %%%uu of %%%uu.\n"
|
||||||
|
#define FILE_COUNTS_OUTPUT_FORMAT_STR_1 "[%%%uu/%%%uu]\n"
|
||||||
|
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
@ -200,6 +202,19 @@ int write_files_fn(void *data, void *ud) {
|
||||||
fopen(temp_filename, "wb");
|
fopen(temp_filename, "wb");
|
||||||
if (!tmp_fd) {
|
if (!tmp_fd) {
|
||||||
fprintf(stderr, "ERROR: Unable to create temp file for compressing!\n");
|
fprintf(stderr, "ERROR: Unable to create temp file for compressing!\n");
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
__attribute__((cleanup(free_malloced_memory))) void *real_cwd =
|
||||||
|
realpath(".", NULL);
|
||||||
|
if (real_cwd) {
|
||||||
|
fprintf(stderr, "Tried to create temp file(s) in \"%s\"!\n",
|
||||||
|
(char *)real_cwd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
fprintf(stderr,
|
||||||
|
"(Use \"--temp-files-dir <dir>\" to change where to write temp "
|
||||||
|
"files.)\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
__attribute__((cleanup(cleanup_temp_filename_delete))) void **ptrs_array =
|
__attribute__((cleanup(cleanup_temp_filename_delete))) void **ptrs_array =
|
||||||
|
@ -543,6 +558,8 @@ int write_files_fn(void *data, void *ud) {
|
||||||
int stat_fd = open(file_info->filename, O_RDONLY);
|
int stat_fd = open(file_info->filename, O_RDONLY);
|
||||||
if (stat_fd == -1) {
|
if (stat_fd == -1) {
|
||||||
// Error.
|
// Error.
|
||||||
|
fprintf(stderr, "ERROR: Failed to get stat of \"%s\"!\n",
|
||||||
|
file_info->filename);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
int stat_status = fstat(stat_fd, &stat_buf);
|
int stat_status = fstat(stat_fd, &stat_buf);
|
||||||
|
@ -866,16 +883,45 @@ int write_files_fn(void *data, void *ud) {
|
||||||
simple_archiver_list_free(&to_write);
|
simple_archiver_list_free(&to_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "[%10u/%10u]\n", ++(state->count), state->max);
|
char format_str[64];
|
||||||
|
snprintf(format_str, 64, FILE_COUNTS_OUTPUT_FORMAT_STR_1, state->digits,
|
||||||
|
state->digits);
|
||||||
|
fprintf(stderr, format_str, ++(state->count), state->max);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_nop_fn(__attribute__((unused)) void *unused) {}
|
void cleanup_nop_fn(__attribute__((unused)) void *unused) {}
|
||||||
void cleanup_free_fn(void *data) { free(data); }
|
void cleanup_free_fn(void *data) { free(data); }
|
||||||
|
|
||||||
|
void simple_archiver_internal_chdir_back2(char **original) {
|
||||||
|
if (original && *original) {
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN
|
||||||
|
chdir(*original);
|
||||||
|
#endif
|
||||||
|
free(*original);
|
||||||
|
*original = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int filenames_to_abs_map_fn(void *data, void *ud) {
|
int filenames_to_abs_map_fn(void *data, void *ud) {
|
||||||
SDArchiverFileInfo *file_info = data;
|
SDArchiverFileInfo *file_info = data;
|
||||||
SDArchiverHashMap **abs_filenames = ud;
|
void **ptr_array = ud;
|
||||||
|
SDArchiverHashMap **abs_filenames = ptr_array[0];
|
||||||
|
const char *user_cwd = ptr_array[1];
|
||||||
|
__attribute__((
|
||||||
|
cleanup(simple_archiver_internal_chdir_back2))) char *original_cwd = NULL;
|
||||||
|
if (user_cwd) {
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
original_cwd = realpath(".", NULL);
|
||||||
|
if (chdir(user_cwd)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Get combined full path to file.
|
// Get combined full path to file.
|
||||||
char *fullpath = filename_to_absolute_path(file_info->filename);
|
char *fullpath = filename_to_absolute_path(file_info->filename);
|
||||||
|
@ -897,6 +943,7 @@ int filenames_to_abs_map_fn(void *data, void *ud) {
|
||||||
if (!cwd_dirname) {
|
if (!cwd_dirname) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
// fprintf(stderr, "cwd_dirname: %s\n", (char*)cwd_dirname);
|
||||||
|
|
||||||
// Use copy of fullpath to avoid clobbering it.
|
// Use copy of fullpath to avoid clobbering it.
|
||||||
__attribute__((cleanup(free_malloced_memory))) void *fullpath_copy =
|
__attribute__((cleanup(free_malloced_memory))) void *fullpath_copy =
|
||||||
|
@ -947,6 +994,8 @@ char *simple_archiver_error_to_string(enum SDArchiverStateReturns error) {
|
||||||
return "Failed to create set of filenames (internal error)";
|
return "Failed to create set of filenames (internal error)";
|
||||||
case SDAS_FAILED_TO_EXTRACT_SYMLINK:
|
case SDAS_FAILED_TO_EXTRACT_SYMLINK:
|
||||||
return "Failed to extract symlink (internal error)";
|
return "Failed to extract symlink (internal error)";
|
||||||
|
case SDAS_FAILED_TO_CHANGE_CWD:
|
||||||
|
return "Failed to change current working directory";
|
||||||
default:
|
default:
|
||||||
return "Unknown error";
|
return "Unknown error";
|
||||||
}
|
}
|
||||||
|
@ -962,6 +1011,9 @@ SDArchiverState *simple_archiver_init_state(const SDArchiverParsed *parsed) {
|
||||||
state->parsed = parsed;
|
state->parsed = parsed;
|
||||||
state->out_f = NULL;
|
state->out_f = NULL;
|
||||||
state->map = NULL;
|
state->map = NULL;
|
||||||
|
state->count = 0;
|
||||||
|
state->max = 0;
|
||||||
|
state->digits = 10;
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -978,10 +1030,14 @@ int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
|
||||||
// First create a "set" of absolute paths to given filenames.
|
// First create a "set" of absolute paths to given filenames.
|
||||||
__attribute__((cleanup(simple_archiver_hash_map_free)))
|
__attribute__((cleanup(simple_archiver_hash_map_free)))
|
||||||
SDArchiverHashMap *abs_filenames = simple_archiver_hash_map_init();
|
SDArchiverHashMap *abs_filenames = simple_archiver_hash_map_init();
|
||||||
if (simple_archiver_list_get(filenames, filenames_to_abs_map_fn,
|
void **ptr_array = malloc(sizeof(void *) * 2);
|
||||||
&abs_filenames)) {
|
ptr_array[0] = &abs_filenames;
|
||||||
|
ptr_array[1] = (void *)state->parsed->user_cwd;
|
||||||
|
if (simple_archiver_list_get(filenames, filenames_to_abs_map_fn, ptr_array)) {
|
||||||
|
free(ptr_array);
|
||||||
return SDAS_FAILED_TO_CREATE_MAP;
|
return SDAS_FAILED_TO_CREATE_MAP;
|
||||||
}
|
}
|
||||||
|
free(ptr_array);
|
||||||
|
|
||||||
if (fwrite("SIMPLE_ARCHIVE_VER", 1, 18, out_f) != 18) {
|
if (fwrite("SIMPLE_ARCHIVE_VER", 1, 18, out_f) != 18) {
|
||||||
return SDAS_FAILED_TO_WRITE;
|
return SDAS_FAILED_TO_WRITE;
|
||||||
|
@ -1067,8 +1123,24 @@ int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
|
||||||
state->max = filenames->count;
|
state->max = filenames->count;
|
||||||
state->out_f = out_f;
|
state->out_f = out_f;
|
||||||
state->map = abs_filenames;
|
state->map = abs_filenames;
|
||||||
|
state->digits = simple_archiver_helper_num_digits(state->max);
|
||||||
fprintf(stderr, "Begin archiving...\n");
|
fprintf(stderr, "Begin archiving...\n");
|
||||||
fprintf(stderr, "[%10u/%10u]\n", state->count, state->max);
|
__attribute__((
|
||||||
|
cleanup(simple_archiver_internal_chdir_back2))) char *original_cwd = NULL;
|
||||||
|
if (state->parsed->user_cwd) {
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
original_cwd = realpath(".", NULL);
|
||||||
|
if (chdir(state->parsed->user_cwd)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
char format_str[64];
|
||||||
|
snprintf(format_str, 64, FILE_COUNTS_OUTPUT_FORMAT_STR_1, state->digits,
|
||||||
|
state->digits);
|
||||||
|
fprintf(stderr, format_str, state->count, state->max);
|
||||||
if (simple_archiver_list_get(filenames, write_files_fn, state)) {
|
if (simple_archiver_list_get(filenames, write_files_fn, state)) {
|
||||||
// Error occurred.
|
// Error occurred.
|
||||||
fprintf(stderr, "Error ocurred writing file(s) to archive.\n");
|
fprintf(stderr, "Error ocurred writing file(s) to archive.\n");
|
||||||
|
@ -1102,6 +1174,16 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
|
||||||
return SDAS_INVALID_FILE;
|
return SDAS_INVALID_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (do_extract && state->parsed->user_cwd) {
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
if (chdir(state->parsed->user_cwd)) {
|
||||||
|
return SDAS_FAILED_TO_CHANGE_CWD;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
__attribute__((cleanup(free_malloced_memory))) void *decompressor_cmd = NULL;
|
__attribute__((cleanup(free_malloced_memory))) void *decompressor_cmd = NULL;
|
||||||
|
|
||||||
if ((buf[0] & 1) != 0) {
|
if ((buf[0] & 1) != 0) {
|
||||||
|
@ -1166,7 +1248,10 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
|
||||||
simple_archiver_helper_32_bit_be(&u32);
|
simple_archiver_helper_32_bit_be(&u32);
|
||||||
fprintf(stderr, "File count is %u\n", u32);
|
fprintf(stderr, "File count is %u\n", u32);
|
||||||
|
|
||||||
uint32_t size = u32;
|
const uint32_t size = u32;
|
||||||
|
const unsigned int digits = simple_archiver_helper_num_digits(size);
|
||||||
|
char format_str[128];
|
||||||
|
snprintf(format_str, 128, FILE_COUNTS_OUTPUT_FORMAT_STR_0, digits, digits);
|
||||||
int skip = 0;
|
int skip = 0;
|
||||||
__attribute__((cleanup(simple_archiver_hash_map_free)))
|
__attribute__((cleanup(simple_archiver_hash_map_free)))
|
||||||
SDArchiverHashMap *hash_map = NULL;
|
SDArchiverHashMap *hash_map = NULL;
|
||||||
|
@ -1184,7 +1269,7 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (uint32_t idx = 0; idx < size; ++idx) {
|
for (uint32_t idx = 0; idx < size; ++idx) {
|
||||||
fprintf(stderr, "\nFile %10u of %10u.\n", idx + 1, size);
|
fprintf(stderr, format_str, idx + 1, size);
|
||||||
if (feof(in_f) || ferror(in_f)) {
|
if (feof(in_f) || ferror(in_f)) {
|
||||||
return SDAS_INVALID_FILE;
|
return SDAS_INVALID_FILE;
|
||||||
} else if (fread(&u16, 2, 1, in_f) != 1) {
|
} else if (fread(&u16, 2, 1, in_f) != 1) {
|
||||||
|
|
|
@ -34,6 +34,7 @@ typedef struct SDArchiverState {
|
||||||
SDArchiverHashMap *map;
|
SDArchiverHashMap *map;
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
unsigned int max;
|
unsigned int max;
|
||||||
|
unsigned int digits;
|
||||||
} SDArchiverState;
|
} SDArchiverState;
|
||||||
|
|
||||||
enum SDArchiverStateReturns {
|
enum SDArchiverStateReturns {
|
||||||
|
@ -46,7 +47,8 @@ enum SDArchiverStateReturns {
|
||||||
SDAS_INVALID_FILE,
|
SDAS_INVALID_FILE,
|
||||||
SDAS_INTERNAL_ERROR,
|
SDAS_INTERNAL_ERROR,
|
||||||
SDAS_FAILED_TO_CREATE_MAP,
|
SDAS_FAILED_TO_CREATE_MAP,
|
||||||
SDAS_FAILED_TO_EXTRACT_SYMLINK
|
SDAS_FAILED_TO_EXTRACT_SYMLINK,
|
||||||
|
SDAS_FAILED_TO_CHANGE_CWD
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returned pointer must not be freed.
|
/// Returned pointer must not be freed.
|
||||||
|
|
|
@ -191,3 +191,38 @@ int simple_archiver_helper_make_dirs(const char *file_path) {
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *simple_archiver_helper_cut_substr(const char *s, unsigned int start_idx,
|
||||||
|
unsigned int end_idx) {
|
||||||
|
unsigned int s_len = strlen(s);
|
||||||
|
if (start_idx > end_idx || start_idx >= s_len || end_idx > s_len) {
|
||||||
|
return NULL;
|
||||||
|
} else if (end_idx == s_len) {
|
||||||
|
if (start_idx == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
char *new_s = malloc(start_idx + 1);
|
||||||
|
strncpy(new_s, s, start_idx + 1);
|
||||||
|
new_s[start_idx] = 0;
|
||||||
|
return new_s;
|
||||||
|
} else if (start_idx == 0) {
|
||||||
|
char *new_s = malloc(s_len - end_idx + 1);
|
||||||
|
strncpy(new_s, s + end_idx, s_len - end_idx + 1);
|
||||||
|
return new_s;
|
||||||
|
} else {
|
||||||
|
char *new_s = malloc(start_idx + s_len - end_idx + 1);
|
||||||
|
strncpy(new_s, s, start_idx);
|
||||||
|
strncpy(new_s + start_idx, s + end_idx, s_len - end_idx + 1);
|
||||||
|
return new_s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int simple_archiver_helper_num_digits(unsigned int value) {
|
||||||
|
unsigned int digits = 0;
|
||||||
|
do {
|
||||||
|
++digits;
|
||||||
|
value /= 10;
|
||||||
|
} while (value != 0);
|
||||||
|
|
||||||
|
return digits;
|
||||||
|
}
|
||||||
|
|
|
@ -46,4 +46,12 @@ void simple_archiver_helper_cmd_string_argv_free_ptr(char ***argv_strs);
|
||||||
/// Returns zero on success.
|
/// Returns zero on success.
|
||||||
int simple_archiver_helper_make_dirs(const char *file_path);
|
int simple_archiver_helper_make_dirs(const char *file_path);
|
||||||
|
|
||||||
|
/// Returns non-NULL on success.
|
||||||
|
/// Must be free'd with "free()" if non-NULL.
|
||||||
|
/// start_idx is inclusive and end_idx is exclusive.
|
||||||
|
char *simple_archiver_helper_cut_substr(const char *s, unsigned int start_idx,
|
||||||
|
unsigned int end_idx);
|
||||||
|
|
||||||
|
unsigned int simple_archiver_helper_num_digits(unsigned int value);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -70,6 +70,11 @@ int main(int argc, const char **argv) {
|
||||||
__attribute__((cleanup(simple_archiver_list_free)))
|
__attribute__((cleanup(simple_archiver_list_free)))
|
||||||
SDArchiverLinkedList *filenames =
|
SDArchiverLinkedList *filenames =
|
||||||
simple_archiver_parsed_to_filenames(&parsed);
|
simple_archiver_parsed_to_filenames(&parsed);
|
||||||
|
if (!filenames) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"ERROR: Failed to resolve filenames from positional arguments!\n");
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
if (filenames->count > 0) {
|
if (filenames->count > 0) {
|
||||||
fprintf(stderr, "Filenames:\n");
|
fprintf(stderr, "Filenames:\n");
|
||||||
|
|
128
src/parser.c
128
src/parser.c
|
@ -39,7 +39,7 @@
|
||||||
#include "parser_internal.h"
|
#include "parser_internal.h"
|
||||||
|
|
||||||
/// Gets the first non "./"-like character in the filename.
|
/// Gets the first non "./"-like character in the filename.
|
||||||
unsigned int simple_archiver_parser_internal_filename_idx(
|
unsigned int simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
const char *filename) {
|
const char *filename) {
|
||||||
unsigned int idx = 0;
|
unsigned int idx = 0;
|
||||||
unsigned int known_good_idx = 0;
|
unsigned int known_good_idx = 0;
|
||||||
|
@ -103,6 +103,18 @@ void simple_archiver_parser_internal_remove_end_slash(char *filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simple_archiver_internal_chdir_back(char **original) {
|
||||||
|
if (original && *original) {
|
||||||
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN
|
||||||
|
chdir(*original);
|
||||||
|
#endif
|
||||||
|
free(*original);
|
||||||
|
*original = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void simple_archiver_internal_free_file_info_fn(void *data) {
|
void simple_archiver_internal_free_file_info_fn(void *data) {
|
||||||
SDArchiverFileInfo *file_info = data;
|
SDArchiverFileInfo *file_info = data;
|
||||||
if (file_info) {
|
if (file_info) {
|
||||||
|
@ -142,6 +154,10 @@ void simple_archiver_print_usage(void) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" Use \"-f -\" to work on stdout when creating archive or stdin "
|
" Use \"-f -\" to work on stdout when creating archive or stdin "
|
||||||
"when reading archive\n");
|
"when reading archive\n");
|
||||||
|
fprintf(stderr, " NOTICE: \"-f\" is not affected by \"-C\"!\n");
|
||||||
|
fprintf(stderr,
|
||||||
|
"-C <dir> : Change current working directory before "
|
||||||
|
"archiving/extracting\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"--compressor <full_compress_cmd> : requires --decompressor\n");
|
"--compressor <full_compress_cmd> : requires --decompressor\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
|
@ -175,6 +191,7 @@ SDArchiverParsed simple_archiver_create_parsed(void) {
|
||||||
parsed.decompressor = NULL;
|
parsed.decompressor = NULL;
|
||||||
parsed.working_files = NULL;
|
parsed.working_files = NULL;
|
||||||
parsed.temp_dir = NULL;
|
parsed.temp_dir = NULL;
|
||||||
|
parsed.user_cwd = NULL;
|
||||||
|
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
@ -239,6 +256,15 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
}
|
}
|
||||||
--argc;
|
--argc;
|
||||||
++argv;
|
++argv;
|
||||||
|
} else if (strcmp(argv[0], "-C") == 0) {
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "ERROR: -C specified but missing argument!\n");
|
||||||
|
simple_archiver_print_usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
out->user_cwd = argv[1];
|
||||||
|
--argc;
|
||||||
|
++argv;
|
||||||
} else if (strcmp(argv[0], "--compressor") == 0) {
|
} else if (strcmp(argv[0], "--compressor") == 0) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
fprintf(stderr, "--compressor specfied but missing argument!\n");
|
fprintf(stderr, "--compressor specfied but missing argument!\n");
|
||||||
|
@ -286,8 +312,8 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
if (out->working_files == NULL) {
|
if (out->working_files == NULL) {
|
||||||
out->working_files = malloc(sizeof(char *) * 2);
|
out->working_files = malloc(sizeof(char *) * 2);
|
||||||
unsigned int arg_idx =
|
unsigned int arg_idx =
|
||||||
simple_archiver_parser_internal_filename_idx(argv[0]);
|
simple_archiver_parser_internal_get_first_non_current_idx(argv[0]);
|
||||||
int arg_length = strlen(argv[0] + arg_idx) + 1;
|
unsigned int arg_length = strlen(argv[0] + arg_idx) + 1;
|
||||||
out->working_files[0] = malloc(arg_length);
|
out->working_files[0] = malloc(arg_length);
|
||||||
strncpy(out->working_files[0], argv[0] + arg_idx, arg_length);
|
strncpy(out->working_files[0], argv[0] + arg_idx, arg_length);
|
||||||
simple_archiver_parser_internal_remove_end_slash(out->working_files[0]);
|
simple_archiver_parser_internal_remove_end_slash(out->working_files[0]);
|
||||||
|
@ -307,7 +333,7 @@ int simple_archiver_parse_args(int argc, const char **argv,
|
||||||
// Set new actual last element to NULL.
|
// Set new actual last element to NULL.
|
||||||
out->working_files[working_size] = NULL;
|
out->working_files[working_size] = NULL;
|
||||||
unsigned int arg_idx =
|
unsigned int arg_idx =
|
||||||
simple_archiver_parser_internal_filename_idx(argv[0]);
|
simple_archiver_parser_internal_get_first_non_current_idx(argv[0]);
|
||||||
int size = strlen(argv[0] + arg_idx) + 1;
|
int size = strlen(argv[0] + arg_idx) + 1;
|
||||||
// Set last element to the arg.
|
// Set last element to the arg.
|
||||||
out->working_files[working_size - 1] = malloc(size);
|
out->working_files[working_size - 1] = malloc(size);
|
||||||
|
@ -363,19 +389,31 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
|
||||||
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
|
||||||
|
__attribute__((
|
||||||
|
cleanup(simple_archiver_internal_chdir_back))) char *original_cwd = NULL;
|
||||||
|
if (parsed->user_cwd) {
|
||||||
|
original_cwd = realpath(".", NULL);
|
||||||
|
if (chdir(parsed->user_cwd)) {
|
||||||
|
simple_archiver_list_free(&files_list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
|
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
memset(&st, 0, sizeof(struct stat));
|
memset(&st, 0, sizeof(struct stat));
|
||||||
fstatat(AT_FDCWD, *iter, &st, AT_SYMLINK_NOFOLLOW);
|
char *file_path = *iter;
|
||||||
|
fstatat(AT_FDCWD, file_path, &st, AT_SYMLINK_NOFOLLOW);
|
||||||
if ((st.st_mode & S_IFMT) == S_IFREG || (st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFREG || (st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
// Is a regular file or a symbolic link.
|
// Is a regular file or a symbolic link.
|
||||||
int len = strlen(*iter) + 1;
|
int len = strlen(file_path) + 1;
|
||||||
char *filename = malloc(len);
|
char *filename = malloc(len);
|
||||||
strncpy(filename, *iter, len);
|
strncpy(filename, file_path, len);
|
||||||
if (simple_archiver_hash_map_get(hash_map, filename, len - 1) == NULL) {
|
if (simple_archiver_hash_map_get(hash_map, filename, len - 1) == NULL) {
|
||||||
SDArchiverFileInfo *file_info = malloc(sizeof(SDArchiverFileInfo));
|
SDArchiverFileInfo *file_info = malloc(sizeof(SDArchiverFileInfo));
|
||||||
file_info->filename = filename;
|
file_info->filename = filename;
|
||||||
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
|
// Is a symlink.
|
||||||
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
||||||
ssize_t count = readlinkat(AT_FDCWD, filename, file_info->link_dest,
|
ssize_t count = readlinkat(AT_FDCWD, filename, file_info->link_dest,
|
||||||
MAX_SYMBOLIC_LINK_SIZE - 1);
|
MAX_SYMBOLIC_LINK_SIZE - 1);
|
||||||
|
@ -385,13 +423,35 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
file_info->link_dest[count] = 0;
|
file_info->link_dest[count] = 0;
|
||||||
} else {
|
} else {
|
||||||
// Failure.
|
// Failure.
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: Could not get link info for file \"%s\"!\n",
|
||||||
|
file_info->filename);
|
||||||
free(file_info->link_dest);
|
free(file_info->link_dest);
|
||||||
free(file_info);
|
free(file_info);
|
||||||
free(filename);
|
free(filename);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Is a regular file.
|
||||||
file_info->link_dest = NULL;
|
file_info->link_dest = NULL;
|
||||||
|
// Check that the file is readable by opening it. Easier than to
|
||||||
|
// check permissions because that would also require checking if the
|
||||||
|
// current USER can open the file.
|
||||||
|
FILE *readable_file = fopen(file_info->filename, "rb");
|
||||||
|
if (!readable_file) {
|
||||||
|
// Cannot open file, so it must be unreadable (at least by the
|
||||||
|
// current USER).
|
||||||
|
fprintf(stderr, "WARNING: \"%s\" is not readable, skipping!\n",
|
||||||
|
file_info->filename);
|
||||||
|
free(file_info->link_dest);
|
||||||
|
free(file_info);
|
||||||
|
free(filename);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
fclose(readable_file);
|
||||||
|
// fprintf(stderr, "DEBUG: \"%s\" is readable.\n",
|
||||||
|
// file_info->filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
simple_archiver_list_add(files_list, file_info,
|
simple_archiver_list_add(files_list, file_info,
|
||||||
simple_archiver_internal_free_file_info_fn);
|
simple_archiver_internal_free_file_info_fn);
|
||||||
|
@ -405,7 +465,7 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
// Is a directory.
|
// Is a directory.
|
||||||
__attribute__((cleanup(simple_archiver_list_free)))
|
__attribute__((cleanup(simple_archiver_list_free)))
|
||||||
SDArchiverLinkedList *dir_list = simple_archiver_list_init();
|
SDArchiverLinkedList *dir_list = simple_archiver_list_init();
|
||||||
simple_archiver_list_add(dir_list, *iter, container_no_free_fn);
|
simple_archiver_list_add(dir_list, file_path, container_no_free_fn);
|
||||||
char *next;
|
char *next;
|
||||||
while (dir_list->count != 0) {
|
while (dir_list->count != 0) {
|
||||||
simple_archiver_list_get(dir_list, list_get_last_fn, &next);
|
simple_archiver_list_get(dir_list, list_get_last_fn, &next);
|
||||||
|
@ -428,7 +488,8 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
snprintf(combined_path, combined_size, "%s/%s", next,
|
snprintf(combined_path, combined_size, "%s/%s", next,
|
||||||
dir_entry->d_name);
|
dir_entry->d_name);
|
||||||
unsigned int valid_idx =
|
unsigned int valid_idx =
|
||||||
simple_archiver_parser_internal_filename_idx(combined_path);
|
simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
combined_path);
|
||||||
if (valid_idx > 0) {
|
if (valid_idx > 0) {
|
||||||
char *new_path = malloc(combined_size - valid_idx);
|
char *new_path = malloc(combined_size - valid_idx);
|
||||||
strncpy(new_path, combined_path + valid_idx,
|
strncpy(new_path, combined_path + valid_idx,
|
||||||
|
@ -448,6 +509,7 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
malloc(sizeof(SDArchiverFileInfo));
|
malloc(sizeof(SDArchiverFileInfo));
|
||||||
file_info->filename = combined_path;
|
file_info->filename = combined_path;
|
||||||
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
if ((st.st_mode & S_IFMT) == S_IFLNK) {
|
||||||
|
// Is a symlink.
|
||||||
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
file_info->link_dest = malloc(MAX_SYMBOLIC_LINK_SIZE);
|
||||||
ssize_t count =
|
ssize_t count =
|
||||||
readlinkat(AT_FDCWD, combined_path, file_info->link_dest,
|
readlinkat(AT_FDCWD, combined_path, file_info->link_dest,
|
||||||
|
@ -464,7 +526,27 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Is a regular file.
|
||||||
file_info->link_dest = NULL;
|
file_info->link_dest = NULL;
|
||||||
|
// Check that the file is readable by opening it. Easier than
|
||||||
|
// to check permissions because that would also require
|
||||||
|
// checking if the current USER can open the file.
|
||||||
|
FILE *readable_file = fopen(file_info->filename, "rb");
|
||||||
|
if (!readable_file) {
|
||||||
|
// Cannot open file, so it must be unreadable (at least by
|
||||||
|
// the current USER).
|
||||||
|
fprintf(stderr,
|
||||||
|
"WARNING: \"%s\" is not readable, skipping!\n",
|
||||||
|
file_info->filename);
|
||||||
|
free(file_info->link_dest);
|
||||||
|
free(file_info);
|
||||||
|
free(combined_path);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
fclose(readable_file);
|
||||||
|
// fprintf(stderr, "DEBUG: \"%s\" is readable.\n",
|
||||||
|
// file_info->filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
simple_archiver_list_add(
|
simple_archiver_list_add(
|
||||||
files_list, file_info,
|
files_list, file_info,
|
||||||
|
@ -497,12 +579,14 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Remove leading "./" entries from files_list.
|
|
||||||
for (SDArchiverLLNode *iter = files_list->head->next;
|
for (SDArchiverLLNode *iter = files_list->head->next;
|
||||||
iter != files_list->tail; iter = iter->next) {
|
iter != files_list->tail; iter = iter->next) {
|
||||||
SDArchiverFileInfo *file_info = iter->data;
|
SDArchiverFileInfo *file_info = iter->data;
|
||||||
|
|
||||||
|
// Remove leading "./" entries from files_list.
|
||||||
unsigned int idx =
|
unsigned int idx =
|
||||||
simple_archiver_parser_internal_filename_idx(file_info->filename);
|
simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
file_info->filename);
|
||||||
if (idx > 0) {
|
if (idx > 0) {
|
||||||
int len = strlen(file_info->filename) + 1 - idx;
|
int len = strlen(file_info->filename) + 1 - idx;
|
||||||
char *substr = malloc(len);
|
char *substr = malloc(len);
|
||||||
|
@ -510,6 +594,28 @@ SDArchiverLinkedList *simple_archiver_parsed_to_filenames(
|
||||||
free(file_info->filename);
|
free(file_info->filename);
|
||||||
file_info->filename = substr;
|
file_info->filename = substr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove "./" entries inside the file path.
|
||||||
|
int slash_found = 0;
|
||||||
|
int dot_found = 0;
|
||||||
|
for (idx = strlen(file_info->filename); idx-- > 0;) {
|
||||||
|
if (file_info->filename[idx] == '/') {
|
||||||
|
if (dot_found) {
|
||||||
|
char *temp = simple_archiver_helper_cut_substr(file_info->filename,
|
||||||
|
idx + 1, idx + 3);
|
||||||
|
free(file_info->filename);
|
||||||
|
file_info->filename = temp;
|
||||||
|
} else {
|
||||||
|
slash_found = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (file_info->filename[idx] == '.' && slash_found) {
|
||||||
|
dot_found = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
slash_found = 0;
|
||||||
|
dot_found = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return files_list;
|
return files_list;
|
||||||
|
|
|
@ -45,6 +45,8 @@ typedef struct SDArchiverParsed {
|
||||||
/// Determines where to place temporary files. If NULL, temporary files are
|
/// Determines where to place temporary files. If NULL, temporary files are
|
||||||
/// created in the current working directory.
|
/// created in the current working directory.
|
||||||
const char *temp_dir;
|
const char *temp_dir;
|
||||||
|
/// Dir specified by "-C".
|
||||||
|
const char *user_cwd;
|
||||||
} SDArchiverParsed;
|
} SDArchiverParsed;
|
||||||
|
|
||||||
typedef struct SDArchiverFileInfo {
|
typedef struct SDArchiverFileInfo {
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
|
||||||
unsigned int simple_archiver_parser_internal_filename_idx(const char *filename);
|
unsigned int simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
const char *filename);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
61
src/test.c
61
src/test.c
|
@ -57,34 +57,42 @@ static int checks_passed = 0;
|
||||||
int main(void) {
|
int main(void) {
|
||||||
// Test parser.
|
// Test parser.
|
||||||
{
|
{
|
||||||
unsigned int idx = simple_archiver_parser_internal_filename_idx("test");
|
unsigned int idx =
|
||||||
|
simple_archiver_parser_internal_get_first_non_current_idx("test");
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx("./test");
|
||||||
CHECK_TRUE(idx == 2);
|
CHECK_TRUE(idx == 2);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx("././test");
|
||||||
CHECK_TRUE(idx == 4);
|
CHECK_TRUE(idx == 4);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././//././//./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././//././//./test");
|
||||||
CHECK_TRUE(idx == 14);
|
CHECK_TRUE(idx == 14);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("/././//././//./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"/././//././//./test");
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx(".derp/.//././//./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
".derp/.//././//./test");
|
||||||
CHECK_TRUE(idx == 0);
|
CHECK_TRUE(idx == 0);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././/.derp/.///./test");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././/.derp/.///./test");
|
||||||
CHECK_TRUE(idx == 5);
|
CHECK_TRUE(idx == 5);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././/.//.//./");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././/.//.//./");
|
||||||
CHECK_TRUE(idx == 11);
|
CHECK_TRUE(idx == 11);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././/.//.//.");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././/.//.//.");
|
||||||
CHECK_TRUE(idx == 11);
|
CHECK_TRUE(idx == 11);
|
||||||
|
|
||||||
idx = simple_archiver_parser_internal_filename_idx("././/.//.//");
|
idx = simple_archiver_parser_internal_get_first_non_current_idx(
|
||||||
|
"././/.//.//");
|
||||||
CHECK_TRUE(idx == 8);
|
CHECK_TRUE(idx == 8);
|
||||||
|
|
||||||
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
SDArchiverParsed parsed = simple_archiver_create_parsed();
|
||||||
|
@ -197,6 +205,39 @@ int main(void) {
|
||||||
simple_archiver_helper_cmd_string_argv_free(result_argv);
|
simple_archiver_helper_cmd_string_argv_free(result_argv);
|
||||||
} while (0);
|
} while (0);
|
||||||
|
|
||||||
|
// Test helpers cut substr.
|
||||||
|
{
|
||||||
|
const char *s = "one two three.";
|
||||||
|
unsigned int s_len = strlen(s);
|
||||||
|
// Invalid range.
|
||||||
|
char *out = simple_archiver_helper_cut_substr(s, 1, 0);
|
||||||
|
CHECK_FALSE(out);
|
||||||
|
// First idx out of range.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, s_len, s_len + 1);
|
||||||
|
CHECK_FALSE(out);
|
||||||
|
// Second idx out of range.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 1, s_len + 1);
|
||||||
|
CHECK_FALSE(out);
|
||||||
|
// Invalid cut of full string.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 0, s_len);
|
||||||
|
CHECK_FALSE(out);
|
||||||
|
// Cut end of string.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 2, s_len);
|
||||||
|
CHECK_TRUE(out);
|
||||||
|
CHECK_STREQ(out, "on");
|
||||||
|
free(out);
|
||||||
|
// Cut start of string.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 0, s_len - 3);
|
||||||
|
CHECK_TRUE(out);
|
||||||
|
CHECK_STREQ(out, "ee.");
|
||||||
|
free(out);
|
||||||
|
// Cut inside string.
|
||||||
|
out = simple_archiver_helper_cut_substr(s, 4, 8);
|
||||||
|
CHECK_TRUE(out);
|
||||||
|
CHECK_STREQ(out, "one three.");
|
||||||
|
free(out);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
Loading…
Reference in a new issue