From 61ade4412d514228557035d603e54cb65dfdc64c Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Thu, 23 Dec 2021 01:20:41 +0100 Subject: [PATCH] unistd, dirent: path manipulation, folder enumeration --- CMakeLists.txt | 7 ++- include/ft/all-tests.h | 16 ++++-- src/dirent/dirent.c | 110 +++++++++++++++++++++++++++++++++++++ src/fcntl/open.c | 3 +- src/main.c | 7 +++ src/unistd/files.c | 119 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 254 insertions(+), 8 deletions(-) create mode 100644 src/dirent/dirent.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f2bec9..98c7058 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,10 +51,13 @@ set(SOURCES # time src/time/clock.c src/time/functions.c - # unistd - src/unistd/files.c + # dirent + src/dirent/dirent.c # fcntl src/fcntl/open.c + # unistd + src/unistd/files.c + ) # fx-9860G-only assets and fx-CG-50-only assets set(ASSETS_fx diff --git a/include/ft/all-tests.h b/include/ft/all-tests.h index fa62c2b..6735014 100644 --- a/include/ft/all-tests.h +++ b/include/ft/all-tests.h @@ -53,13 +53,19 @@ extern ft_test ft_string_strerror; extern ft_test ft_time_clock; extern ft_test ft_time_functions; -/* unistd */ -extern ft_test ft_unistd_simple_write; -extern ft_test ft_unistd_write_odd; -extern ft_test ft_unistd_simple_read; -extern ft_test ft_unistd_seek_patterns; +/* dirent */ +extern ft_test ft_dirent_glob; +extern ft_test ft_dirent_open_folders; /* fcntl */ extern ft_test ft_fcntl_open; +/* unistd */ +extern ft_test ft_unistd_path; +extern ft_test ft_unistd_simple_write; +extern ft_test ft_unistd_write_odd; +extern ft_test ft_unistd_simple_read; +extern ft_test ft_unistd_seek_patterns; +extern ft_test ft_unistd_folders; + #endif /* _FT_ALL_TESTS_H_ */ diff --git a/src/dirent/dirent.c b/src/dirent/dirent.c new file mode 100644 index 0000000..e8e6b59 --- /dev/null +++ b/src/dirent/dirent.c @@ -0,0 +1,110 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern char *fc_to_utf8_alloc(uint16_t const *fc); + +static void _ft_dirent_glob_switch(ft_test *t) +{ + int search_handle, rc; + uint16_t found_file[256]; + struct BFile_FileInfo fileinfo; + char *str; + uint16_t const *path = u"\\\\fls0\\*"; + + DO_E(rc, BFile_FindFirst(path, &search_handle, found_file, &fileinfo), + t, "%d"); + ft_assert(t, rc == 0 || rc == BFile_EntryNotFound); + if(rc < 0) return; + + str = fc_to_utf8_alloc(found_file); + ft_log(t, "Found: %s\n", str); + free(str); + + while(1) { + rc = BFile_FindNext(search_handle, found_file, &fileinfo); + ft_assert(t, rc == 0 || rc == BFile_EnumerateEnd); + if(rc == BFile_EnumerateEnd) + break; + + str = fc_to_utf8_alloc(found_file); + ft_log(t, "Found: %s\n", str); + free(str); + } + + DO_E(rc, BFile_FindClose(search_handle), t, "%d"); + ft_assert(t, rc == 0); +} + +static void _ft_dirent_glob(ft_test *t) +{ + gint_world_switch(GINT_CALL(_ft_dirent_glob_switch, (void *)t)); +} + +ft_test ft_dirent_glob = { + .name = "Glob \\\\fls0\\*", + .function = _ft_dirent_glob, +}; + +static struct dirent *read_ent(ft_test *t, DIR *dp) +{ + int offset = telldir(dp); + struct dirent *ent = readdir(dp); + + if(!ent) { + ft_log(t, "%02d \n", offset); + } + else { + ft_log(t, "%02d %s%s\n", offset, ent->d_name, + ent->d_type == DT_DIR ? "/" : ""); + } + + return ent; +} + +static void _ft_dirent_open_folders_switch(ft_test *t) +{ + DIR *dp; + struct dirent *ent; + int offset; + + DO_E(dp, opendir("/"), t, "%p"); + ft_assert(t, dp != NULL); + if(!dp) return; + + do ent = read_ent(t, dp); + while(ent); + + DO_E(offset, telldir(dp), t, "%d"); + if(offset > 0) offset--; + ft_log(t, "seekdir(dp, %d)\n", offset); + seekdir(dp, offset); + read_ent(t, dp); + + rewinddir(dp); + ft_log(t, "rewinddir(dp)\n"); + read_ent(t, dp); + + closedir(dp); +} + +static void _ft_dirent_open_folders(ft_test *t) +{ + gint_world_switch(GINT_CALL(_ft_dirent_open_folders_switch, (void*)t)); +} + +ft_test ft_dirent_open_folders = { + .name = "Opening folders", + .function = _ft_dirent_open_folders, +}; diff --git a/src/fcntl/open.c b/src/fcntl/open.c index 1f9a338..7eb0641 100644 --- a/src/fcntl/open.c +++ b/src/fcntl/open.c @@ -39,4 +39,5 @@ ft_test ft_fcntl_open = { .function = _ft_fcntl_open, }; -// TODO: Truncation +// TODO: Opening files with different access modes +// TODO: Opening files with O_TRUNC or O_APPEND diff --git a/src/main.c b/src/main.c index 00fd6d9..c4ec792 100644 --- a/src/main.c +++ b/src/main.c @@ -79,15 +79,22 @@ ft_list headers_libc[] = { { NULL } }; ft_list headers_posix[] = { + { "", (ft_test*[]) { + &ft_dirent_glob, + &ft_dirent_open_folders, + NULL, + }}, { "", (ft_test*[]){ &ft_fcntl_open, NULL, }}, { "", (ft_test*[]){ + &ft_unistd_path, &ft_unistd_simple_write, &ft_unistd_write_odd, &ft_unistd_simple_read, &ft_unistd_seek_patterns, + &ft_unistd_folders, NULL, }}, { NULL } diff --git a/src/unistd/files.c b/src/unistd/files.c index 357c3f9..d93c251 100644 --- a/src/unistd/files.c +++ b/src/unistd/files.c @@ -8,9 +8,68 @@ #include #include +#include #include #include +extern char **fs_split_components(char *path, int *count); + +static void log_comps(ft_test *t, char const *path, char const *solution) +{ + ft_log(t, "Splitting: %s\n", path); + char *path_dup = strdup(path); + if(!path_dup) { + ft_log(t, " ENOMEM\n"); + return; + } + + int count; + char **comps = fs_split_components(path_dup, &count); + + for(int i = 0; i < count; i++) { + ft_log(t, " --> %s\n", comps[i]); + } + if(count == 0) { + ft_log(t, " (empty)\n"); + } + + free(path_dup); + free(comps); + + char *norm1 = fs_path_normalize(path); + ft_log(t, "Normalized (UTF-8): %s\n", norm1); + ft_assert(t, !strcmp(norm1, solution)); + free(norm1); + + uint16_t *norm2 = fs_path_normalize_fc(path); + ft_log(t, "Normalized (FC): "); + for(int i = 0; norm2[i]; i++) ft_log(t, "%c", norm2[i]); + ft_log(t, "\n\n"); + free(norm2); +} + +static void _ft_unistd_paths(ft_test *t) +{ + ft_log(t, "\nPath normalization:\n\n"); + log_comps(t, ".", "/"); + log_comps(t, "/", "/"); + log_comps(t, "/*", "/*"); + log_comps(t, "/file.txt", "/file.txt"); + log_comps(t, "file.txt", "/file.txt"); + log_comps(t, "folder/file", "/folder/file"); + log_comps(t, "a/b/c/d", "/a/b/c/d"); + log_comps(t, "/a/b//c", "/a/b/c"); + log_comps(t, "folder////file", "/folder/file"); + log_comps(t, "//folder///file///", "/folder/file"); + log_comps(t, "./../er//e/", "/er/e"); + log_comps(t, "x/../y/z/../t", "/y/t"); +} + +ft_test ft_unistd_path = { + .name = "Path normalization", + .function = _ft_unistd_paths, +}; + static void _ft_unistd_simple_write_switch(ft_test *t) { int fd, rc; @@ -244,3 +303,63 @@ ft_test ft_unistd_seek_patterns = { .name = "Seek patterns", .function = _ft_unistd_seek_patterns, }; + +static void _ft_unistd_folders_switch(ft_test *t) +{ + int rc, fd, type, size; + + /* Create a directory (don't fail if we already ran the test before) */ + DO_E(rc, mkdir("ft_test", 0755), t, "%d"); + ft_assert(t, rc == 0 || (rc == -1 && errno == EEXIST)); + ft_log(t, "note: this folder might already exist\n"); + + /* Remove that directory */ + DO_E(rc, rmdir("ft_test"), t, "%d"); + ft_assert(t, rc == 0); + + /* Create it anew (and empty) */ + DO_E(rc, mkdir("ft_test", 0755), t, "%d"); + ft_assert(t, rc == 0); + DO_E(rc, mkdir("ft_test", 0755), t, "%d"); + ft_assert(t, rc == -1 && errno == EEXIST); + + /* Create a file in that directory, write some stuff and close it */ + DO_E(fd, open("ft_test/file.txt", O_RDWR | O_CREAT | O_TRUNC), t,"%d"); + ft_assert(t, fd >= 0); + DO_E(rc, write(fd, "Some data\n", 10), t, "%d"); + ft_assert(t, rc == 10); + DO_E(rc, close(fd), t, "%d"); + ft_assert(t, rc == 0); + + /* Stat that file */ + rc = BFile_Ext_Stat(u"\\\\fls0\\ft_test\\file.txt", &type, &size); + ft_log(t, "BFile_Ext_Stat()=%d (type=%d, size=%d)\n", rc, type, size); + ft_assert(t, rc == 0 && type == BFile_Type_File && size == 10); + + /* Create a subfolder */ + DO_E(rc, mkdir("ft_test/subfolder", 0755), t, "%d"); + ft_assert(t, rc == 0); + + /* Create a file in the subfolder and stat it again */ + DO_E(fd, open("ft_test/subfolder/file.txt", O_RDWR | O_CREAT + | O_TRUNC), t, "%d"); + ft_assert(t, fd >= 0); + DO_E(rc, write(fd, "Some data for the subfolder\n", 28), t, "%d"); + ft_assert(t, rc == 28); + DO_E(rc, close(fd), t, "%d"); + ft_assert(t, rc == 0); + rc = BFile_Ext_Stat(u"\\\\fls0\\ft_test\\subfolder\\file.txt", + &type, &size); + ft_log(t, "BFile_Ext_Stat()=%d (type=%d, size=%d)\n", rc, type, size); + ft_assert(t, rc == 0 && type == BFile_Type_File && size == 28); +} + +static void _ft_unistd_folders(ft_test *t) +{ + gint_world_switch(GINT_CALL(_ft_unistd_folders_switch, (void *)t)); +} + +ft_test ft_unistd_folders = { + .name = "Using folders", + .function = _ft_unistd_folders, +};