int filenames_to_abs_map_fn(void *data, void *ud) {
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];
// Get combined full path to file.
char *fullpath = filename_to_absolute_path(file_info->filename);
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
- cwd_dirname = realpath(".", NULL);
+ if (user_cwd) {
+ cwd_dirname = realpath(user_cwd, NULL);
+ } else {
+ cwd_dirname = realpath(".", NULL);
+ }
#endif
if (!cwd_dirname) {
return 1;
}
+ // fprintf(stderr, "cwd_dirname: %s\n", (char*)cwd_dirname);
// Use copy of fullpath to avoid clobbering it.
__attribute__((cleanup(free_malloced_memory))) void *fullpath_copy =
return "Failed to create set of filenames (internal error)";
case SDAS_FAILED_TO_EXTRACT_SYMLINK:
return "Failed to extract symlink (internal error)";
+ case SDAS_FAILED_TO_CHANGE_CWD:
+ return "Failed to change current working directory";
default:
return "Unknown error";
}
// First create a "set" of absolute paths to given filenames.
__attribute__((cleanup(simple_archiver_hash_map_free)))
SDArchiverHashMap *abs_filenames = simple_archiver_hash_map_init();
- if (simple_archiver_list_get(filenames, filenames_to_abs_map_fn,
- &abs_filenames)) {
+ void **ptr_array = malloc(sizeof(void *) * 2);
+ 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;
}
+ free(ptr_array);
if (fwrite("SIMPLE_ARCHIVE_VER", 1, 18, out_f) != 18) {
return SDAS_FAILED_TO_WRITE;
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;
if ((buf[0] & 1) != 0) {
#include "parser_internal.h"
/// 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) {
unsigned int idx = 0;
unsigned int known_good_idx = 0;
fprintf(stderr,
" Use \"-f -\" to work on stdout when creating archive or stdin "
"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,
"--compressor <full_compress_cmd> : requires --decompressor\n");
fprintf(stderr,
parsed.decompressor = NULL;
parsed.working_files = NULL;
parsed.temp_dir = NULL;
+ parsed.user_cwd = NULL;
return parsed;
}
}
--argc;
++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) {
if (argc < 2) {
fprintf(stderr, "--compressor specfied but missing argument!\n");
if (out->working_files == NULL) {
out->working_files = malloc(sizeof(char *) * 2);
unsigned int arg_idx =
- simple_archiver_parser_internal_filename_idx(argv[0]);
- int arg_length = strlen(argv[0] + arg_idx) + 1;
+ simple_archiver_parser_internal_get_first_non_current_idx(argv[0]);
+ unsigned int arg_length = strlen(argv[0] + arg_idx) + 1;
out->working_files[0] = malloc(arg_length);
strncpy(out->working_files[0], argv[0] + arg_idx, arg_length);
simple_archiver_parser_internal_remove_end_slash(out->working_files[0]);
+ if (out->user_cwd) {
+ if (out->user_cwd[strlen(out->user_cwd) - 1] != '/') {
+ char *temp = malloc(strlen(out->user_cwd) + 1 +
+ strlen(out->working_files[0]) + 1);
+ strncpy(temp, out->user_cwd, strlen(out->user_cwd) + 1);
+ temp[strlen(out->user_cwd)] = '/';
+ strncpy(temp + strlen(out->user_cwd) + 1, out->working_files[0],
+ strlen(out->working_files[0]) + 1);
+ free(out->working_files[0]);
+ out->working_files[0] = temp;
+ } else {
+ char *temp = malloc(strlen(out->user_cwd) +
+ strlen(out->working_files[0]) + 1);
+ strncpy(temp, out->user_cwd, strlen(out->user_cwd) + 1);
+ strncpy(temp + strlen(out->user_cwd), out->working_files[0],
+ strlen(out->working_files[0]) + 1);
+ free(out->working_files[0]);
+ out->working_files[0] = temp;
+ }
+ }
out->working_files[1] = NULL;
} else {
int working_size = 1;
// Set new actual last element to NULL.
out->working_files[working_size] = NULL;
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;
// Set last element to the arg.
out->working_files[working_size - 1] = malloc(size);
strncpy(out->working_files[working_size - 1], argv[0] + arg_idx, size);
simple_archiver_parser_internal_remove_end_slash(
out->working_files[working_size - 1]);
+ if (out->user_cwd) {
+ if (out->user_cwd[strlen(out->user_cwd) - 1] != '/') {
+ char *temp =
+ malloc(strlen(out->user_cwd) + 1 +
+ strlen(out->working_files[working_size - 1]) + 1);
+ strncpy(temp, out->user_cwd, strlen(out->user_cwd) + 1);
+ temp[strlen(out->user_cwd)] = '/';
+ strncpy(temp + strlen(out->user_cwd) + 1,
+ out->working_files[working_size - 1],
+ strlen(out->working_files[working_size - 1]) + 1);
+ free(out->working_files[working_size - 1]);
+ out->working_files[working_size - 1] = temp;
+ } else {
+ char *temp =
+ malloc(strlen(out->user_cwd) +
+ strlen(out->working_files[working_size - 1]) + 1);
+ strncpy(temp, out->user_cwd, strlen(out->user_cwd) + 1);
+ strncpy(temp + strlen(out->user_cwd),
+ out->working_files[working_size - 1],
+ strlen(out->working_files[working_size - 1]) + 1);
+ free(out->working_files[working_size - 1]);
+ out->working_files[working_size - 1] = temp;
+ }
+ }
}
}
for (char **iter = parsed->working_files; iter && *iter; ++iter) {
struct stat st;
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) {
// Is a regular file or a symbolic link.
- int len = strlen(*iter) + 1;
+ int len = strlen(file_path) + 1;
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) {
SDArchiverFileInfo *file_info = malloc(sizeof(SDArchiverFileInfo));
file_info->filename = filename;
// Is a directory.
__attribute__((cleanup(simple_archiver_list_free)))
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;
while (dir_list->count != 0) {
simple_archiver_list_get(dir_list, list_get_last_fn, &next);
snprintf(combined_path, combined_size, "%s/%s", next,
dir_entry->d_name);
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) {
char *new_path = malloc(combined_size - valid_idx);
strncpy(new_path, combined_path + valid_idx,
}
#endif
- // Remove leading "./" entries from files_list.
for (SDArchiverLLNode *iter = files_list->head->next;
iter != files_list->tail; iter = iter->next) {
SDArchiverFileInfo *file_info = iter->data;
+
+ // Remove leading "./" entries from files_list.
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) {
int len = strlen(file_info->filename) + 1 - idx;
char *substr = malloc(len);
free(file_info->filename);
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;
int main(void) {
// 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);
- idx = simple_archiver_parser_internal_filename_idx("./test");
+ idx = simple_archiver_parser_internal_get_first_non_current_idx("./test");
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);
- idx = simple_archiver_parser_internal_filename_idx("././//././//./test");
+ idx = simple_archiver_parser_internal_get_first_non_current_idx(
+ "././//././//./test");
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);
- 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);
- 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);
- idx = simple_archiver_parser_internal_filename_idx("././/.//.//./");
+ idx = simple_archiver_parser_internal_get_first_non_current_idx(
+ "././/.//.//./");
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);
- idx = simple_archiver_parser_internal_filename_idx("././/.//.//");
+ idx = simple_archiver_parser_internal_get_first_non_current_idx(
+ "././/.//.//");
CHECK_TRUE(idx == 8);
SDArchiverParsed parsed = simple_archiver_create_parsed();
simple_archiver_helper_cmd_string_argv_free(result_argv);
} 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 passed: %u\n", checks_passed);
return checks_passed == checks_checked ? 0 : 1;