Fully implement building entries
Including name and full path
This commit is contained in:
79
src/main.c
79
src/main.c
@@ -50,11 +50,57 @@ int compare_library_entries(const void *a, const void *b) {
|
||||
return noh_sv_compare(lea.name, leb.name);
|
||||
}
|
||||
|
||||
#define build_path(first, ...) build_path_((first), __VA_ARGS__, NULL)
|
||||
Noh_String build_path_(SV *first, ...) {
|
||||
va_list args;
|
||||
SV *elem_ = first;
|
||||
va_start(args, first);
|
||||
bool start = true;
|
||||
Noh_String result = {0};
|
||||
|
||||
while (elem_ != NULL) {
|
||||
SV elem = *elem_;
|
||||
while (elem.count > 0) {
|
||||
SV component = noh_sv_chop_by_delim(&elem, '/');
|
||||
if (noh_sv_eq(component, sv(".."))) continue;
|
||||
|
||||
if (component.count > 0) {
|
||||
if (start) start = false; else noh_string_append_cstr(&result, "/");
|
||||
noh_string_append_sv(&result, component);
|
||||
}
|
||||
}
|
||||
|
||||
elem_ = va_arg(args, SV *);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
SV path_to_name(SV path) {
|
||||
while (true) {
|
||||
SV component = noh_sv_chop_by_delim(&path, '/');
|
||||
if (path.count == 0) return component;
|
||||
}
|
||||
}
|
||||
|
||||
void set_modified_time(Library_Entry *entry) {
|
||||
struct stat attr;
|
||||
if (stat(noh_arena_sprintf(&temp, Nsv_Fmt, entry->full_path), &attr) == 0) {
|
||||
struct tm *timeinfo = localtime(&attr.st_mtime);
|
||||
entry->modified_at = *timeinfo;
|
||||
} else {
|
||||
entry->modified_at = (struct tm){0};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Library entry from a dirent structure.
|
||||
*/
|
||||
bool create_entry(struct dirent *dir_entry, const char *parent_path, Library_Entry *result) {
|
||||
SV name = sv(dir_entry->d_name);
|
||||
SV parent_path_sv = sv(parent_path);
|
||||
Noh_String full_path = build_path(&parent_path_sv, &name);
|
||||
int type = dir_entry->d_type;
|
||||
|
||||
// Check if the entry is relevant.
|
||||
@@ -62,24 +108,17 @@ bool create_entry(struct dirent *dir_entry, const char *parent_path, Library_Ent
|
||||
if (noh_sv_eq(name, sv(".")) || noh_sv_eq(name, sv(".."))) return false;
|
||||
if (type == DT_REG && !noh_sv_ends_with_ci(name, sv(".epub"))) return false;
|
||||
|
||||
// Allocate and populate library entry.
|
||||
// Set entry data.
|
||||
result->is_dir = type == DT_DIR;
|
||||
result->full_path = noh_sv_from_string(&full_path);
|
||||
result->name = noh_sv_copy_cstr(&temp, dir_entry->d_name);
|
||||
|
||||
// Load modified time.
|
||||
struct stat attr;
|
||||
if (stat(noh_arena_sprintf(&temp, "%s/"Nsv_Fmt, parent_path, Nsv_Arg(name)), &attr) == 0) {
|
||||
struct tm *timeinfo = localtime(&attr.st_mtime);
|
||||
result->modified_at = *timeinfo;
|
||||
} else {
|
||||
result->modified_at = (struct tm){0};
|
||||
}
|
||||
set_modified_time(result);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char *format_library_entry(Library_Entry entry, char time_buffer[80]) {
|
||||
strftime(time_buffer, 80, "%Y-%m-%d %H:%M:%S", &entry.modified_at);
|
||||
strftime(time_buffer, 80, "%Y-%m-%d %H.%M.%S", &entry.modified_at);
|
||||
|
||||
return noh_arena_sprintf(
|
||||
&temp,
|
||||
@@ -121,29 +160,23 @@ static Noh_String create_feed_response(Library_Entry self_path, Library_Entries
|
||||
}
|
||||
|
||||
static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, SV base_path, SV username) {
|
||||
Noh_String fs_path = {0};
|
||||
noh_string_append_sv(&fs_path, base_path);
|
||||
noh_string_append_cstr(&fs_path, "/");
|
||||
noh_string_append_sv(&fs_path, username);
|
||||
noh_string_append_cstr(&fs_path, "/");
|
||||
noh_string_append_sv(&fs_path, url);
|
||||
noh_string_append_null(&fs_path);
|
||||
noh_arena_save(&temp);
|
||||
Noh_String fs_path = build_path(&base_path, &username, &url);
|
||||
|
||||
Library_Entry self_entry = {
|
||||
.is_dir = true,
|
||||
.full_path = noh_sv_from_string(&fs_path),
|
||||
.name = path_to_name(noh_sv_from_string(&fs_path)),
|
||||
.modified_at = {0},
|
||||
};
|
||||
(void)self_entry;
|
||||
|
||||
noh_log(NOH_INFO, "Physical path: "Nsv_Fmt, Nsv_Arg(self_entry.name));
|
||||
set_modified_time(&self_entry);
|
||||
noh_log(NOH_INFO, "Physical path: "Nsv_Fmt, Nsv_Arg(self_entry.full_path));
|
||||
|
||||
DIR *dir = opendir(fs_path.elems);
|
||||
if (dir) {
|
||||
Library_Entries list = {0};
|
||||
|
||||
// Build up list of entries.
|
||||
noh_arena_save(&temp);
|
||||
struct dirent *entry = noh_arena_alloc(&temp, sizeof(struct dirent));
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
Library_Entry result = {0};
|
||||
@@ -167,10 +200,12 @@ static enum MHD_Result handle_opds(struct MHD_Connection *connection, SV url, SV
|
||||
|
||||
} else if (errno == ENOENT) {
|
||||
closedir(dir);
|
||||
noh_arena_reset(&temp);
|
||||
return send_response(connection, 404, sv(""), false);
|
||||
|
||||
} else {
|
||||
noh_log(NOH_ERROR, "Opening directory failed.");
|
||||
noh_arena_reset(&temp);
|
||||
return send_response(connection, 500, sv(""), false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user