#include "io.h" #include "aliases.h" #include "path_utils.h" #include #include #include #include #include #include #define MAX_DIR_DEPTH PATH_MAX typedef struct stat stat_t; typedef struct dirent dirent_t; struct dirwalk { u64 count; FILE *current_file; DIR *current_dir; char dst[PATH_MAX]; DIR *directories[MAX_DIR_DEPTH]; }; u64 get_file_length(FILE *fp) { u64 current = ftell(fp); fseek(fp, 0, SEEK_END); u64 length = ftell(fp); // Restore the cursor position to where it was fseek(fp, current, SEEK_SET); return length; } void read_entire_file(void *dst, FILE *fp) { u64 length = get_file_length(fp); u64 current = ftell(fp); fseek(fp, 0, SEEK_SET); fread(dst, length, 1, fp); fseek(fp, current, SEEK_SET); } dirwalk_result_t walk_dir(dirwalk_t **dirwalk, const char *filepath) { if (!(*dirwalk)) { *dirwalk = (dirwalk_t *)malloc(sizeof(dirwalk_t)); if (!(*dirwalk)) { return (dirwalk_result_t){0}; } memset((void *)(*dirwalk), 0, sizeof(dirwalk_t)); JOIN_PATH((*dirwalk)->dst, filepath); (*dirwalk)->directories[0] = opendir((*dirwalk)->dst); if (!((*dirwalk)->directories[0])) { goto CLEANUP_WALK_DIR; } (*dirwalk)->current_dir = (*dirwalk)->directories[0]; ++((*dirwalk)->count); } if ((*dirwalk)->current_file) { fclose((*dirwalk)->current_file); (*dirwalk)->current_file = NULL; } dirwalk_t *dw = *dirwalk; char tmp[PATH_MAX] = {0}; dirent_t *ep = NULL; stat_t dirstat = {0}; while ((ep = readdir(dw->current_dir))) { if (STREQ(ep->d_name, ".") || STREQ(ep->d_name, "..")) { continue; } switch (ep->d_type) { case DT_DIR: { JOIN_PATH(dw->dst, ep->d_name); dw->directories[(dw->count)++] = opendir(dw->dst); dw->current_dir = dw->directories[dw->count - 1]; break; } case DT_REG: { JOIN_PATH(tmp, dw->dst, ep->d_name); dw->current_file = fopen(tmp, "rb"); dirwalk_result_t result = {0}; result.reading = true; result.fp = dw->current_file; strncpy(result.name, ep->d_name, NAME_MAX); return result; } case DT_LNK: { JOIN_PATH(tmp, dw->dst, ep->d_name); u64 length = strlen(tmp); stat(tmp, &dirstat); if ((dirstat.st_mode & S_IFDIR) == S_IFDIR) { memset(dw->dst, 0, length); strncpy(dw->dst, tmp, length); dw->directories[(dw->count)++] = opendir(dw->dst); dw->current_dir = dw->directories[dw->count - 1]; } else if ((dirstat.st_mode & S_IFREG) == S_IFREG) { dw->current_file = fopen(tmp, "rb"); dirwalk_result_t result = {0}; result.reading = true; result.fp = dw->current_file; strncpy(result.name, ep->d_name, NAME_MAX); return result; } memset(tmp, 0, length); break; } default: break; } } if (dw->count > 1) { closedir(dw->directories[--(dw->count)]); dw->directories[dw->count] = NULL; dw->current_dir = dw->directories[dw->count - 1]; u64 length = strlen(dw->dst); strncpy(tmp, dw->dst, length); memset(dw->dst, 0, length); DIRNAME(dw->dst, tmp); memset(tmp, 0, length); dirwalk_result_t result = {0}; result.reading = true; return result; } else { dw->current_dir = NULL; } closedir(dw->directories[dw->count]); CLEANUP_WALK_DIR: free(*dirwalk); *dirwalk = NULL; dirwalk_result_t result = {0}; result.reading = false; return result; }