IO functions

This commit is contained in:
Abdelrahman Said 2023-10-21 18:58:09 +01:00
parent 362b1b33d5
commit d7792998ea
2 changed files with 201 additions and 0 deletions

22
include/io.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef IO_H
#define IO_H
#include "aliases.h"
#include <linux/limits.h>
#include <stdbool.h>
#include <stdio.h>
#define STREQ(S1, S2) (strcmp(S1, S2) == 0)
typedef struct dirwalk dirwalk_t;
typedef struct {
FILE *fp;
bool reading;
char name[NAME_MAX + 1];
} dirwalk_result_t;
u64 get_file_length(FILE *fp);
void read_entire_file(void *dst, u64 length, FILE *fp);
dirwalk_result_t walk_dir(dirwalk_t **dirwalk, const char *filepath);
#endif // !IO_H

179
src/io.c Normal file
View File

@ -0,0 +1,179 @@
#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, u64 length, FILE *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;
}