From 76d85a10f6cda93eba29dad5372e8160af7289c8 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 27 Feb 2019 22:26:35 +0100 Subject: Use multiple threads to parse --- src/std/file.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 src/std/file.c (limited to 'src/std/file.c') diff --git a/src/std/file.c b/src/std/file.c new file mode 100644 index 0000000..7701be4 --- /dev/null +++ b/src/std/file.c @@ -0,0 +1,152 @@ +#include "../../include/std/file.h" +#include "../../include/std/mem.h" +#include "../../include/std/log.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define SCANDIR_PATH_LENGTH 4096 + +static int scan_dir_recursive_internal(char *dir_path, int path_length, scan_dir_callback_func callback_func, void *userdata) { + DIR *dir; + struct dirent *entry; + struct stat file_stats; + int filename_length; + int path_length_start; + + path_length_start = path_length; + if((dir = opendir(dir_path)) == NULL) { + amal_log_perror("scan_dir_recursive"); + return errno; + } + + while((entry = readdir(dir)) != NULL) { + /* + Skip hidden files. Name will always at least include null terminator + so it's ok to not check filename length. And file names are never empty, right??? + */ + if(entry->d_name[0] == '.') + continue; + + /* Reset path concat, because it's overwritten by recursive call to scan dir */ + path_length = path_length_start; + filename_length = strlen(entry->d_name); + /* current path '/' filename '\0' */ + if(path_length + 1 + filename_length + 1 > SCANDIR_PATH_LENGTH) { + amal_log_error("Filepath too long. Trying to append %s to %s", entry->d_name, dir_path); + return -1; + } + + /* Replace '\0' with '/' */ + dir_path[path_length] = '/'; + ++path_length; + am_memcpy(&dir_path[path_length], entry->d_name, filename_length); + path_length += filename_length; + dir_path[path_length] = '\0'; + + if(stat(dir_path, &file_stats) == -1) { + amal_log_perror("scan_dir_recursive_internal"); + goto cleanup; + } + + if(S_ISDIR(file_stats.st_mode)) { + cleanup_if_error(scan_dir_recursive_internal(dir_path, path_length, callback_func, userdata)); + } else if(S_ISREG(file_stats.st_mode)) { + if(!callback_func(dir_path, path_length, userdata)) + goto cleanup_noerr; + } else if(S_ISLNK(file_stats.st_mode)) { + amal_log_warning("Symlink ignored: %s", entry->d_name); + } else { + /* Ignore block devices and all other types of files */ + } + } + + cleanup_noerr: + closedir(dir); + return 0; + + cleanup: + closedir(dir); + return -1; +} + +int scan_dir_recursive(const char *dir_path, scan_dir_callback_func callback_func, void *userdata) { + char scandir_path[SCANDIR_PATH_LENGTH]; + int dir_path_length = strlen(dir_path) + 1; /* include null terminator */ + am_memcpy(scandir_path, dir_path, dir_path_length); + return scan_dir_recursive_internal(scandir_path, dir_path_length - 1, callback_func, userdata); +} + +static int mapped_file_mode_to_system_file_mode(MappedFileMode file_mode) { + switch(file_mode) { + case MAPPED_FILE_READ: return PROT_READ; + case MAPPED_FILE_WRITE: return PROT_WRITE; + case MAPPED_FILE_READ_WRITE: return PROT_READ | PROT_WRITE; + default: + assert(bool_false); + return PROT_READ; + } +} + +int mapped_file_init(MappedFile *self, const char *filepath, MappedFileMode file_mode) { + struct stat file_stats; + int fd; + const char *memblock; + int map_file_system_mode; + + self->file_data = NULL; + self->file_size = 0; + self->fd = -1; + + fd = open(filepath, O_RDONLY); + if(fd == -1) return errno; + if(fstat(fd, &file_stats) == -1) { + amal_log_perror("map_file_read"); + goto cleanup; + } + + map_file_system_mode = mapped_file_mode_to_system_file_mode(file_mode); + memblock = mmap(NULL, file_stats.st_size, map_file_system_mode, MAP_PRIVATE, fd, 0); + if(memblock == MAP_FAILED) { + amal_log_perror("map_file_read"); + goto cleanup; + } + + self->file_data = memblock; + self->file_size = file_stats.st_size; + self->fd = fd; + return 0; + + cleanup: + close(fd); + return -1; +} + +int mapped_file_deinit(MappedFile *self) { + int result_munmap; + int result_close; + + if(!self->file_data) + return 0; + + result_munmap = munmap((void*)self->file_data, self->file_size); + if(result_munmap == -1) + amal_log_perror("mapped_file_deinit"); + result_close = close(self->fd); + if(result_close == -1) + amal_log_perror("mapped_file_deinit"); + self->file_data = NULL; + self->file_size = 0; + self->fd = 0; + if(result_munmap == -1 || result_close == -1) + return -1; + else + return 0; +} \ No newline at end of file -- cgit v1.2.3