diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b73cb7..9203554 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,4 +39,7 @@ add_executable(test_simplearchiver src/test.c src/parser.c src/helpers.c + src/algorithms/linear_congruential_gen.c + src/data_structures/linked_list.c + src/data_structures/hash_map.c ) diff --git a/src/data_structures/hash_map.c b/src/data_structures/hash_map.c index d1f04d1..2a5ec6b 100644 --- a/src/data_structures/hash_map.c +++ b/src/data_structures/hash_map.c @@ -89,6 +89,11 @@ unsigned long long simple_archiver_hash_map_internal_key_to_hash( return simple_archiver_algo_lcg_defaults(seed); } +void simple_archiver_hash_map_internal_no_free_fn( + __attribute__((unused)) void *unused) { + return; +} + /// Returns 0 on success. int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap **hash_map) { if (!hash_map || !*hash_map) { @@ -116,7 +121,8 @@ int simple_archiver_hash_map_internal_rehash(SDArchiverHashMap **hash_map) { simple_archiver_hash_map_insert(&new_hash_map, data->value, data->key, data->key_size, data->value_cleanup_fn, data->key_cleanup_fn); - node->data = NULL; + data->key_cleanup_fn = simple_archiver_hash_map_internal_no_free_fn; + data->value_cleanup_fn = simple_archiver_hash_map_internal_no_free_fn; } } } diff --git a/src/data_structures/test.c b/src/data_structures/test.c index e5299a6..5d59156 100644 --- a/src/data_structures/test.c +++ b/src/data_structures/test.c @@ -153,6 +153,19 @@ int main(void) { } simple_archiver_hash_map_free(&hash_map); + + // Rehash test for Memcheck. + hash_map = simple_archiver_hash_map_init(); + for (unsigned int idx = 0; idx < SC_SA_DS_HASH_MAP_START_BUCKET_SIZE + 1; + ++idx) { + unsigned int *copy_value = malloc(sizeof(unsigned int)); + *copy_value = idx; + unsigned int *copy_key = malloc(sizeof(unsigned int)); + *copy_key = idx; + simple_archiver_hash_map_insert(&hash_map, copy_value, copy_key, + sizeof(unsigned int), NULL, NULL); + } + simple_archiver_hash_map_free(&hash_map); } // Test PriorityHeap. diff --git a/src/main.c b/src/main.c index 6bb753c..1b12eee 100644 --- a/src/main.c +++ b/src/main.c @@ -20,6 +20,12 @@ #include "parser.h" +int print_list_fn(void *data, __attribute__((unused)) void *ud) { + const char *cstr = data; + printf(" %s\n", cstr); + return 0; +} + int main(int argc, const char **argv) { simple_archiver_print_usage(); @@ -28,5 +34,12 @@ int main(int argc, const char **argv) { simple_archiver_parse_args(argc, argv, &parsed); + __attribute__((cleanup(simple_archiver_list_free))) + SDArchiverLinkedList *filenames = + simple_archiver_parsed_to_filenames(&parsed); + + puts("Filenames:"); + simple_archiver_list_get(filenames, print_list_fn, NULL); + return 0; } diff --git a/src/parser.c b/src/parser.c index 0a31d3f..409d0b2 100644 --- a/src/parser.c +++ b/src/parser.c @@ -22,7 +22,16 @@ #include #include +#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX +#include +#include +#include +#endif + +#include "data_structures/hash_map.h" +#include "data_structures/linked_list.h" #include "parser_internal.h" +#include "platforms.h" /// Gets the first non "./"-like character in the filename. unsigned int simple_archiver_parser_internal_filename_idx( @@ -75,6 +84,22 @@ unsigned int simple_archiver_parser_internal_filename_idx( return idx; } +int list_get_last_fn(void *data, void *ud) { + char **last = ud; + *last = data; + return 0; +} + +void container_no_free_fn(__attribute__((unused)) void *data) { return; } + +int list_remove_same_str_fn(void *data, void *ud) { + if (strcmp((char *)data, (char *)ud) == 0) { + return 1; + } + + return 0; +} + void simple_archiver_print_usage(void) { puts("Usage flags:"); puts("-c : create archive file"); @@ -216,3 +241,102 @@ void simple_archiver_free_parsed(SDArchiverParsed *parsed) { parsed->working_files = NULL; } } + +SDArchiverLinkedList *simple_archiver_parsed_to_filenames( + const SDArchiverParsed *parsed) { + SDArchiverLinkedList *files_list = simple_archiver_list_init(); + __attribute__((cleanup(simple_archiver_hash_map_free))) + SDArchiverHashMap *hash_map = simple_archiver_hash_map_init(); + int hash_map_sentinel = 1; +#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ + SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX + for (char **iter = parsed->working_files; iter && *iter; ++iter) { + struct stat st; + stat(*iter, &st); + if ((st.st_mode & S_IFMT) == S_IFREG) { + // Is a regular file. + int len = strlen(*iter) + 1; + char *filename = malloc(len); + strncpy(filename, *iter, len); + if (simple_archiver_hash_map_get(hash_map, filename, len - 1) == NULL) { + simple_archiver_list_add(files_list, filename, NULL); + simple_archiver_hash_map_insert(&hash_map, &hash_map_sentinel, filename, + len - 1, container_no_free_fn, + container_no_free_fn); + } else { + free(filename); + } + } else if ((st.st_mode & S_IFMT) == S_IFDIR) { + // Is a directory. TODO handle this. + __attribute__((cleanup(simple_archiver_list_free))) + SDArchiverLinkedList *dir_list = simple_archiver_list_init(); + simple_archiver_list_add(dir_list, *iter, container_no_free_fn); + char *next; + while (dir_list->count != 0) { + simple_archiver_list_get(dir_list, list_get_last_fn, &next); + if (!next) { + break; + } + DIR *dir = opendir(next); + struct dirent *dir_entry; + do { + dir_entry = readdir(dir); + if (dir_entry) { + if (strcmp(dir_entry->d_name, ".") == 0 || + strcmp(dir_entry->d_name, "..") == 0) { + continue; + } + printf("dir entry in %s is %s\n", next, dir_entry->d_name); + int combined_size = strlen(next) + strlen(dir_entry->d_name) + 2; + char *combined_path = malloc(combined_size); + snprintf(combined_path, combined_size, "%s/%s", next, + dir_entry->d_name); + stat(combined_path, &st); + if ((st.st_mode & S_IFMT) == S_IFREG) { + // Is a file. + if (simple_archiver_hash_map_get(hash_map, combined_path, + combined_size - 1) == NULL) { + simple_archiver_list_add(files_list, combined_path, NULL); + simple_archiver_hash_map_insert( + &hash_map, &hash_map_sentinel, combined_path, + combined_size - 1, container_no_free_fn, + container_no_free_fn); + } else { + free(combined_path); + } + } else if ((st.st_mode & S_IFMT) == S_IFDIR) { + // Is a directory. + simple_archiver_list_add_front(dir_list, combined_path, NULL); + } else { + // Unhandled type. + free(combined_path); + } + } + } while (dir_entry != NULL); + closedir(dir); + if (simple_archiver_list_remove(dir_list, list_remove_same_str_fn, + next) == 0) { + break; + } + } + } else { + // Unhandled type. + } + } +#endif + + // Remove leading "./" entries from files_list. + for (SDArchiverLLNode *iter = files_list->head->next; + iter != files_list->tail; iter = iter->next) { + unsigned int idx = simple_archiver_parser_internal_filename_idx(iter->data); + if (idx > 0) { + int len = strlen((char *)iter->data) + 1 - idx; + char *substr = malloc(len); + strncpy(substr, (char *)iter->data + idx, len); + free(iter->data); + iter->data = substr; + } + } + + return files_list; +} diff --git a/src/parser.h b/src/parser.h index 1dc9175..73cc7ca 100644 --- a/src/parser.h +++ b/src/parser.h @@ -19,6 +19,8 @@ #ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_ #define SEODISPARATE_COM_SIMPLE_ARCHIVER_PARSER_H_ +#include "data_structures/linked_list.h" + typedef struct SDArchiverParsed { /// Each bit is a flag. /// 0b0 - is creating. @@ -48,4 +50,7 @@ int simple_archiver_parse_args(int argc, const char **argv, void simple_archiver_free_parsed(SDArchiverParsed *parsed); +SDArchiverLinkedList *simple_archiver_parsed_to_filenames( + const SDArchiverParsed *parsed); + #endif diff --git a/src/platforms.h b/src/platforms.h index c7fd36a..76a3e66 100644 --- a/src/platforms.h +++ b/src/platforms.h @@ -17,6 +17,9 @@ * compiled for. */ +#ifndef SEODISPARATE_COM_SIMPLE_ARCHIVER_PLATFORMS_H_ +#define SEODISPARATE_COM_SIMPLE_ARCHIVER_PLATFORMS_H_ + // Determine platform macros #define SIMPLE_ARCHIVER_PLATFORM_WINDOWS 1 #define SIMPLE_ARCHIVER_PLATFORM_MAC 2 @@ -35,3 +38,5 @@ #else #define SIMPLE_ARCHIVER_PLATFORM SIMPLE_ARCHIVER_PLATFORM_UNKNOWN #endif + +#endif