182 lines
3.5 KiB
C
182 lines
3.5 KiB
C
#include "io.h"
|
|
#include "aliases.h"
|
|
#include "path_utils.h"
|
|
#include <dirent.h>
|
|
#include <linux/limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
|
|
#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;
|
|
}
|