From f9d94a1038820d934cecb97966cdcfe2717474cc Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 10 May 2020 20:08:36 -0500 Subject: [PATCH] Update: new directory related functions, file function updates, status code updates, directory level restructuring Numerous updates to get the directory functionality better hashed out. Some of the directory functionality is experimentally added. --- build/level_0/settings | 4 +- build/level_1/settings | 4 +- build/level_2/settings | 4 +- build/monolithic/settings | 4 +- level_0/f_directory/c/directory.c | 197 ++++++++++++++++ level_0/f_directory/c/directory.h | 249 +++++++++++++++++++++ level_0/f_directory/c/private-directory.c | 17 ++ level_0/f_directory/c/private-directory.h | 50 +++++ .../f_directory}/data/build/dependencies | 0 .../f_directory}/data/build/settings | 6 +- level_0/f_file/c/file.c | 70 +++++- level_0/f_file/c/file.h | 71 +++++- level_0/f_status/c/status.h | 23 ++ level_1/fl_directory/c/directory.c | 89 -------- level_1/fl_status/c/status.c | 69 ++++++ level_1/fl_status/c/status.h | 72 ++++++ level_2/fll_directory/c/directory.c | 151 +++++++++++++ .../fll_directory}/c/directory.h | 39 ++-- level_2/fll_directory/data/build/dependencies | 7 + level_2/fll_directory/data/build/settings | 30 +++ level_2/fll_status/c/status.c | 115 ++++++++++ level_3/firewall/c/firewall.c | 2 +- level_3/firewall/c/firewall.h | 2 +- level_3/firewall/data/build/dependencies | 2 +- level_3/firewall/data/build/settings | 2 +- 25 files changed, 1137 insertions(+), 142 deletions(-) create mode 100644 level_0/f_directory/c/directory.c create mode 100644 level_0/f_directory/c/directory.h create mode 100644 level_0/f_directory/c/private-directory.c create mode 100644 level_0/f_directory/c/private-directory.h rename {level_1/fl_directory => level_0/f_directory}/data/build/dependencies (100%) rename {level_1/fl_directory => level_0/f_directory}/data/build/settings (81%) delete mode 100644 level_1/fl_directory/c/directory.c create mode 100644 level_2/fll_directory/c/directory.c rename {level_1/fl_directory => level_2/fll_directory}/c/directory.h (54%) create mode 100644 level_2/fll_directory/data/build/dependencies create mode 100644 level_2/fll_directory/data/build/settings diff --git a/build/level_0/settings b/build/level_0/settings index 134cdb9..fbb80e7 100644 --- a/build/level_0/settings +++ b/build/level_0/settings @@ -12,9 +12,9 @@ build_linker ar build_libraries -lc build_libraries_fll build_libraries_fll-level -build_sources_library console.c conversion.c file.c memory.c pipe.c print.c utf.c private-utf.c +build_sources_library console.c conversion.c directory.c private-directory.c file.c memory.c pipe.c print.c utf.c private-utf.c build_sources_program -build_sources_headers color.h console.h conversion.h file.h fss.h memory.h path_fll.h path_filesystem.h pipe.h print.h serialized.h socket.h status.h string.h type.h type_array.h utf.h +build_sources_headers color.h console.h conversion.h directory.c file.h fss.h memory.h path_fll.h path_filesystem.h pipe.h print.h serialized.h socket.h status.h string.h type.h type_array.h utf.h build_shared yes build_static yes diff --git a/build/level_1/settings b/build/level_1/settings index e32bfcd..bc4aba0 100644 --- a/build/level_1/settings +++ b/build/level_1/settings @@ -12,9 +12,9 @@ build_linker ar build_libraries -lc build_libraries_fll -lfll_0 build_libraries_fll-level -lfll_0 -build_sources_library color.c console.c directory.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c print.c serialized.c private-serialized.c socket.c status.c string.c private-string.c utf.c private-utf.c utf_file.c +build_sources_library color.c console.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c print.c serialized.c private-serialized.c socket.c status.c string.c private-string.c utf.c private-utf.c utf_file.c build_sources_program -build_sources_headers color.h console.h directory.h file.h fss.h fss_basic.h fss_basic_list.h fss_status.h fss_extended.h fss_extended_list.h fss_macro.h print.h serialized.h socket.h status.h string.h utf.h utf_file.h +build_sources_headers color.h console.h file.h fss.h fss_basic.h fss_basic_list.h fss_status.h fss_extended.h fss_extended_list.h fss_macro.h print.h serialized.h socket.h status.h string.h utf.h utf_file.h build_shared yes build_static yes diff --git a/build/level_2/settings b/build/level_2/settings index bc0aa1b..77c3525 100644 --- a/build/level_2/settings +++ b/build/level_2/settings @@ -12,9 +12,9 @@ build_linker ar build_libraries -lc build_libraries_fll -lfll_0 -lfll_1 build_libraries_fll-level -lfll_0 -lfll_1 -build_sources_library execute.c private-execute.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c program.c status.c +build_sources_library directory.c execute.c private-execute.c file.c fss.c fss_basic.c fss_basic_list.c fss_extended.c fss_extended_list.c fss_status.c program.c status.c build_sources_program -build_sources_headers execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h program.h status.h +build_sources_headers directory.h execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_extended.h fss_extended_list.h fss_status.h program.h status.h build_shared yes build_static yes diff --git a/build/monolithic/settings b/build/monolithic/settings index e79f99f..5482ae3 100644 --- a/build/monolithic/settings +++ b/build/monolithic/settings @@ -11,9 +11,9 @@ build_compiler gcc build_linker ar build_libraries -lc build_libraries_fll -build_sources_library level_0/console.c level_0/conversion.c level_0/file.c level_0/memory.c level_0/pipe.c level_0/print.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/directory.c level_1/file.c level_1/fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/print.c level_1/serialized.c level_1/private-serialized.c level_1/socket.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/program.c level_2/status.c +build_sources_library level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/file.c level_0/memory.c level_0/pipe.c level_0/print.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/file.c level_1/fss.c level_1/fss_basic.c level_1/fss_basic_list.c level_1/fss_extended.c level_1/fss_extended_list.c level_1/print.c level_1/serialized.c level_1/private-serialized.c level_1/socket.c level_1/status.c level_1/string.c level_1/private-string.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_2/directory.c level_2/execute.c level_2/private-execute.c level_2/file.c level_2/fss.c level_2/fss_basic.c level_2/fss_basic_list.c level_2/fss_extended.c level_2/fss_extended_list.c level_2/fss_status.c level_2/program.c level_2/status.c build_sources_program -build_sources_headers level_0/color.h level_0/console.h level_0/conversion.h level_0/file.h level_0/fss.h level_0/memory.h level_0/path_fll.h level_0/path_filesystem.h level_0/pipe.h level_0/print.h level_0/serialized.h level_0/socket.h level_0/status.h level_0/string.h level_0/type.h level_0/type_array.h level_0/utf.h level_1/color.h level_1/console.h level_1/directory.h level_1/file.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_status.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/print.h level_1/serialized.h level_1/socket.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/program.h level_2/status.h +build_sources_headers level_0/color.h level_0/console.h level_0/conversion.h level_0/directory.h level_0/file.h level_0/fss.h level_0/memory.h level_0/path_fll.h level_0/path_filesystem.h level_0/pipe.h level_0/print.h level_0/serialized.h level_0/socket.h level_0/status.h level_0/string.h level_0/type.h level_0/type_array.h level_0/utf.h level_1/color.h level_1/console.h level_1/file.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_status.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_macro.h level_1/print.h level_1/serialized.h level_1/socket.h level_1/status.h level_1/string.h level_1/utf.h level_1/utf_file.h level_2/directory.h level_2/execute.h level_2/file.h level_2/fss.h level_2/fss_basic.h level_2/fss_basic_list.h level_2/fss_extended.h level_2/fss_extended_list.h level_2/fss_status.h level_2/program.h level_2/status.h build_sources_bash build_sources_settings build_shared yes diff --git a/level_0/f_directory/c/directory.c b/level_0/f_directory/c/directory.c new file mode 100644 index 0000000..2dbc324 --- /dev/null +++ b/level_0/f_directory/c/directory.c @@ -0,0 +1,197 @@ +#include +#include "private-directory.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_f_directory_list_ + f_return_status f_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_string_dynamics *names) { + #ifndef _di_level_0_parameter_checking_ + if (names == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + struct dirent **listing = 0; + size_t i = 0; + f_string_length size = 0; + f_status status = f_none; + + const size_t length = scandir(path, &listing, filter, sort); + + if (length == -1) { + if (errno == ENOMEM) return f_status_set_error(f_error_allocation); + else return f_status_set_error(f_failure); + } + + for (; i < length; i++) { + size = strnlen(listing[i]->d_name, f_directory_name_max); + + // There is no reason to include "." and ".." in the directory listing. + if (strncmp(listing[i]->d_name, "..", 3) == 0 || strncmp(listing[i]->d_name, ".", 2) == 0) { + f_memory_delete((void **) & listing[i], sizeof(char *), 1); + continue; + } + + if (names->used >= names->size) { + f_macro_string_dynamics_resize(status, (*names), names->size + f_directory_default_allocation_step); + if (f_status_is_error(status)) break; + } + + f_macro_string_dynamic_new(status, names->array[names->used], size); + if (f_status_is_error(status)) break; + + memcpy(names->array[names->used].string, listing[i]->d_name, size); + names->array[names->used].used = size; + names->used++; + + f_memory_delete((void **) & listing[i], sizeof(char *), 1); + } // for + + for (; i < length; i++) { + f_memory_delete((void **) & listing[i], sizeof(char *), 1); + } // for + + f_memory_delete((void **) & listing, sizeof(struct dirent *), 1); + + if (f_status_is_error(status)) return status; + if (length == 0) return f_no_data; + + return f_none; + } +#endif // _di_f_directory_list_ + +#ifndef _di_f_directory_remove_ + f_return_status f_directory_remove(const f_string path, const int recursion_max, const bool preserve) { + #ifndef _di_level_0_parameter_checking_ + if (recursion_max < 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + int result = 0; + + if (recursion_max) { + result = nftw(path, private_f_directory_remove_recursively, recursion_max, FTW_DEPTH | FTW_PHYS); + + if (result == 0 && !preserve) { + result = remove(path); + } + } + else { + // Not recursively deleting and the path is requested to be preserved, so there is nothing to delete. + if (preserve) return f_none; + + result = remove(path); + } + + // @todo properly handle the correct error codes, this was simply copied over from f_file_remove(). + + if (result < 0) { + if (errno == EACCES) { + return f_status_set_error(f_access_denied); + } + else if (errno == EBUSY) { + return f_status_set_error(f_busy); + } + else if (errno == EIO) { + return f_status_set_error(f_error_input_output); + } + else if (errno == EISDIR) { + return f_status_set_error(f_file_is_type_directory); + } + else if (errno == ELOOP) { + return f_status_set_error(f_loop); + } + else if (errno == ENAMETOOLONG || errno == EFAULT) { + return f_status_set_error(f_invalid_name); + } + else if (errno == ENOENT) { + return f_status_set_error(f_file_not_found); + } + else if (errno == ENOMEM) { + return f_status_set_error(f_out_of_memory); + } + else if (errno == ENOTDIR) { + return f_status_set_error(f_invalid_directory); + } + else if (errno == EPERM) { + return f_status_set_error(f_prohibited); + } + else if (errno == EROFS) { + return f_status_set_error(f_read_only); + } + + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // _di_f_directory_remove_ + +#ifndef _di_f_directory_remove_custom_ + f_return_status f_directory_remove_custom(const f_string path, const int recursion_max, const bool preserve, int (*custom) (const char *, const struct stat *, int, struct FTW *)) { + #ifndef _di_level_0_parameter_checking_ + if (recursion_max < 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_0_parameter_checking_ + + int result = 0; + + if (recursion_max) { + result = nftw(path, custom, recursion_max, FTW_DEPTH | FTW_PHYS); + + if (result == 0 && !preserve) { + result = remove(path); + } + } + else { + // Not recursively deleting and the path is requested to be preserved, so there is nothing to delete. + if (preserve) return f_none; + + result = remove(path); + } + + // @todo properly handle the correct error codes, this was simply copied over from f_file_remove(). + + if (result < 0) { + if (errno == EACCES) { + return f_status_set_error(f_access_denied); + } + else if (errno == EBUSY) { + return f_status_set_error(f_busy); + } + else if (errno == EIO) { + return f_status_set_error(f_error_input_output); + } + else if (errno == EISDIR) { + return f_status_set_error(f_file_is_type_directory); + } + else if (errno == ELOOP) { + return f_status_set_error(f_loop); + } + else if (errno == ENAMETOOLONG || errno == EFAULT) { + return f_status_set_error(f_invalid_name); + } + else if (errno == ENOENT) { + return f_status_set_error(f_file_not_found); + } + else if (errno == ENOMEM) { + return f_status_set_error(f_out_of_memory); + } + else if (errno == ENOTDIR) { + return f_status_set_error(f_invalid_directory); + } + else if (errno == EPERM) { + return f_status_set_error(f_prohibited); + } + else if (errno == EROFS) { + return f_status_set_error(f_read_only); + } + + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // _di_f_directory_remove_custom_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_directory/c/directory.h b/level_0/f_directory/c/directory.h new file mode 100644 index 0000000..82a1612 --- /dev/null +++ b/level_0/f_directory/c/directory.h @@ -0,0 +1,249 @@ +/** + * FLL - Level 0 + * + * Project: Directory + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * Provides operations for directory handling. + */ +#ifndef _F_directory_h +#define _F_directory_h + +// libc includes +#include +#include +#include +#include +#include +#include + +// work-around for out-dated systems. +#ifndef __USE_XOPEN_EXTENDED + #define __USE_XOPEN_EXTENDED + #include + #undef __USE_XOPEN_EXTENDED +#else + #include +#endif // __USE_XOPEN_EXTENDED + +// fll-0 includes +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Provide limitations and related defines. + * + * The name max 255 because the directory name size is 256. + * The last 1 is for the NULL character. + */ +#ifndef _di_f_directory_limitations_ + #define f_directory_default_allocation_step f_memory_default_allocation_step + + #define f_directory_name_max 255 +#endif // _di_f_directory_limitations_ + +/** + * A structure representing a listing of paths found within a directory. + * + * Each property represents a set of paths grouped by directory entity file type. + */ +#ifndef _di_f_directory_listing_ + typedef struct { + f_string_dynamics block; // S_IFBLK + f_string_dynamics character; // S_IFCHR + f_string_dynamics directory; // S_IFDIR + f_string_dynamics file; // S_IFREG + f_string_dynamics link; // S_IFLNK + f_string_dynamics pipe; // S_IFIFO + f_string_dynamics socket; // S_IFSOCK + f_string_dynamics unknown; + } f_directory_listing; + + #define f_directory_listing_initialize { \ + f_string_dynamics_initialize, \ + f_string_dynamics_initialize, \ + f_string_dynamics_initialize, \ + f_string_dynamics_initialize, \ + f_string_dynamics_initialize, \ + f_string_dynamics_initialize, \ + f_string_dynamics_initialize, \ + f_string_dynamics_initialize, \ + } + + #define f_macro_directory_listing_delete(status, listing) \ + f_macro_string_dynamics_delete(status, listing.block) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_delete(status, listing.character) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_delete(status, listing.directory) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_delete(status, listing.file) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_delete(status, listing.link) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_delete(status, listing.pipe) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_delete(status, listing.socket) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_delete(status, listing.unknown) + + #define f_macro_directory_listing_destroy(status, listing) \ + f_macro_string_dynamics_destroy(status, listing.block) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_destroy(status, listing.character) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_destroy(status, listing.directory) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_destroy(status, listing.file) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_destroy(status, listing.link) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_destroy(status, listing.pipe) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_destroy(status, listing.socket) \ + if (!f_status_is_error(status)) f_macro_string_dynamics_delete(status, listing.unknown) + + #define f_macro_directory_listing_delete_simple(listing) \ + f_macro_string_dynamics_delete_simple(listing.block) \ + f_macro_string_dynamics_delete_simple(listing.character) \ + f_macro_string_dynamics_delete_simple(listing.directory) \ + f_macro_string_dynamics_delete_simple(listing.file) \ + f_macro_string_dynamics_delete_simple(listing.link) \ + f_macro_string_dynamics_delete_simple(listing.pipe) \ + f_macro_string_dynamics_delete_simple(listing.socket) \ + f_macro_string_dynamics_delete_simple(listing.unknown) + + #define f_macro_directory_listing_destroy_simple(listing) \ + f_macro_string_dynamics_destroy_simple(listing.block) \ + f_macro_string_dynamics_destroy_simple(listing.character) \ + f_macro_string_dynamics_destroy_simple(listing.directory) \ + f_macro_string_dynamics_destroy_simple(listing.file) \ + f_macro_string_dynamics_destroy_simple(listing.link) \ + f_macro_string_dynamics_destroy_simple(listing.pipe) \ + f_macro_string_dynamics_destroy_simple(listing.socket) \ + f_macro_string_dynamics_destroy_simple(listing.unknown) +#endif // _di_f_directory_listing_ + +/** + * A structure representing a directory. + */ +#ifndef _di_f_directory_ + typedef struct { + struct dirent entity; + int descriptor; + f_directory_listing content; + } f_directory; + + #define f_directory_initialize { \ + { 0, 0, 0, 0, 0 }, \ + 0, \ + f_directory_listing_initialize, \ + } +#endif // _di_f_directory_ + +/** + * For some given path, print the names of each file and/or directory inside the directory. + * + * Allows specifying a custom filter and custom sort. + * + * @param path + * Filesystem path to the directory. + * @param filter + * A filter function of the form: int xxx(const struct direct *). + * Set to 0 to not use (NULL). + * @param sort + * A sort function of the form: int xxx(const struct direct *, const struct direct *). + * Set to 0 to not use (NULL). + * There are two pre-made libc functions available for this: alphasort() and versionsort(). + * @param names + * Will be populated with the names of each file and/or directory inside path. + * + * @return + * f_none on success. + * f_no_data if directory is empty (@fixme: unlikely due to '.' and '..' probably always being returned.). + * f_failure (with error bit) if failed to read directory information. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_error_reallocation (with error bit) on memory reallocation error. + * + * @see alphasort() + * @see scandir() + * @see versionsort() + */ +#ifndef _di_f_directory_list_ + extern f_return_status f_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_string_dynamics *names); +#endif // _di_f_directory_list_ + +/** + * Remove a directory and possibly its contents. + * + * @param path + * The path file name. + * @param recursion_max + * Represents the max recursion depth, set to 0 to disable recursive delete. + * @param preserve + * When recursion_max > 0, this designates whether or not to preserve the directory at path. + * If TRUE, then only the content within the directory is deleted. + * If FALSE, then the directory at path and its content are deleted. + * When recursion_max is 0, then this should only be FALSE (setting this to TRUE would be a no-op). + * + * @return + * f_none on success. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_access_denied (with error bit) on access denied. + * f_busy (with error bit) if file is busy. + * f_error_input_output (with error bit) if an I/O error occurred. + * f_file_is_type_directory (with error bit) file is a directory (directories cannot be removed via this function). + * f_loop (with error bit) on loop error. + * f_invalid_name (with error bit) on path name error. + * f_file_not_found (with error bit) if file not found. + * f_out_of_memory (with error bit) if out of memory. + * f_invalid_directory (with error bit) if a supposed directory in path is not actually a directory. + * f_prohibited (with error bit) if filesystem does not allow for removing. + * f_read_only (with error bit) if file is read-only. + * f_failure (with error bit) for any other (unlink()) error. + * + * @see nftw() + * @see remove() + */ +#ifndef _di_f_directory_remove_ + extern f_return_status f_directory_remove(const f_string path, const int recursion_max, const bool preserve); +#endif // _di_f_directory_remove_ + +/** + * Remove a directory and possibly its contents. + * + * @param path + * The path file name. + * @param recursion_max + * Represents the max recursion depth, set to 0 to disable recursive delete. + * @param preserve + * When recursion_max > 0, this designates whether or not to preserve the directory at path. + * If TRUE, then only the content within the directory is deleted. + * If FALSE, then the directory at path and its content are deleted. + * When recursion_max is 0, then this should only be FALSE (setting this to TRUE would be a no-op). + * @param custom + * A custom function to pass to nftw() instead of using the internal one. + * Such as a custom function for verbose printing of removed files. + * + * @return + * f_none on success. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_access_denied (with error bit) on access denied. + * f_busy (with error bit) if file is busy. + * f_error_input_output (with error bit) if an I/O error occurred. + * f_file_is_type_directory (with error bit) file is a directory (directories cannot be removed via this function). + * f_loop (with error bit) on loop error. + * f_invalid_name (with error bit) on path name error. + * f_file_not_found (with error bit) if file not found. + * f_out_of_memory (with error bit) if out of memory. + * f_invalid_directory (with error bit) if a supposed directory in path is not actually a directory. + * f_prohibited (with error bit) if filesystem does not allow for removing. + * f_read_only (with error bit) if file is read-only. + * f_failure (with error bit) for any other (unlink()) error. + * + * @see nftw() + * @see remove() + */ +#ifndef _di_f_directory_remove_custom_ + extern f_return_status f_directory_remove_custom(const f_string path, const int recursion_max, const bool preserve, int (*custom) (const char *, const struct stat *, int, struct FTW *)); +#endif // _di_f_directory_remove_custom_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _F_directory_h diff --git a/level_0/f_directory/c/private-directory.c b/level_0/f_directory/c/private-directory.c new file mode 100644 index 0000000..4245232 --- /dev/null +++ b/level_0/f_directory/c/private-directory.c @@ -0,0 +1,17 @@ +#include +#include "private-directory.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_di_f_directory_remove_) + int private_f_directory_remove_recursively(const char *path, const struct stat *file_stat, int type, struct FTW *entity) { + if (entity->level == 0) return 0; + return remove(path); + } +#endif // !defined(_di_f_directory_remove_) + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_0/f_directory/c/private-directory.h b/level_0/f_directory/c/private-directory.h new file mode 100644 index 0000000..79f80cc --- /dev/null +++ b/level_0/f_directory/c/private-directory.h @@ -0,0 +1,50 @@ +/** + * FLL - Level 0 + * + * Project: Directory + * API Version: 0.5 + * Licenses: lgplv2.1 + * + * Provides operations for directory handling. + */ +#ifndef _PRIVATE_F_directory_h +#define _PRIVATE_F_directory_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A special function intended to be used directly by nftw(). + * + * This is intended to be used by the specified function as a function pointer and therefore follows the required structure. + * + * This is essentially a wrapper to remove(). + * + * @param path + * The file path. + * @param file_stat + * The file stat. + * @param type + * The file type. + * @param entity + * The FTW entity. + * + * @return + * 0 on success. + * -1 on failure. + * Check errno for details. + * + * @see f_directory_remove() + * @see nftw() + * @see remove() + */ +#if !defined(_di_f_directory_remove_) + extern int private_f_directory_remove_recursively(const char *path, const struct stat *file_stat, int type, struct FTW *entity) f_gcc_attribute_visibility_internal; +#endif // !defined(_di_f_directory_remove_) + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _PRIVATE_F_directory_h diff --git a/level_1/fl_directory/data/build/dependencies b/level_0/f_directory/data/build/dependencies similarity index 100% rename from level_1/fl_directory/data/build/dependencies rename to level_0/f_directory/data/build/dependencies diff --git a/level_1/fl_directory/data/build/settings b/level_0/f_directory/data/build/settings similarity index 81% rename from level_1/fl_directory/data/build/settings rename to level_0/f_directory/data/build/settings index 0910a54..0f9b9b2 100644 --- a/level_1/fl_directory/data/build/settings +++ b/level_0/f_directory/data/build/settings @@ -1,7 +1,7 @@ # fss-0000 -project_name fl_directory -project_level 1 +project_name f_directory +project_level 0 version_major 0 version_minor 5 @@ -11,7 +11,7 @@ build_compiler gcc build_linker ar build_libraries -lc build_libraries_fll -lf_memory -build_sources_library directory.c +build_sources_library directory.c private-directory.c build_sources_program build_sources_headers directory.h build_sources_bash diff --git a/level_0/f_file/c/file.c b/level_0/f_file/c/file.c index 485cd92..4edca30 100644 --- a/level_0/f_file/c/file.c +++ b/level_0/f_file/c/file.c @@ -15,7 +15,7 @@ extern "C" { #endif #ifndef _di_f_file_open_ - f_return_status f_file_open(f_file *file, const f_string file_name) { + f_return_status f_file_open(f_file *file, const f_string path) { #ifndef _di_level_0_parameter_checking_ if (file == 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ @@ -23,7 +23,7 @@ extern "C" { // if file->mode is unset, then this may cause a segfault. if (file->mode == 0) return f_status_set_error(f_invalid_parameter); - file->address = fopen(file_name, file->mode); + file->address = fopen(path, file->mode); if (file->address == 0) return f_status_set_error(f_file_not_found); if (ferror(file->address) != 0) return f_status_set_error(f_file_error_open); @@ -60,12 +60,12 @@ extern "C" { #endif // _di_f_file_close_ #ifndef _di_f_file_exists_ - f_return_status f_file_exists(const f_string file_name) { + f_return_status f_file_exists(const f_string path) { #ifndef _di_level_0_parameter_checking_ - if (file_name == 0) return f_status_set_error(f_invalid_parameter); + if (path == 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ - if (access(file_name, F_OK)) { + if (access(path, F_OK)) { if (errno == ENOENT) { return f_false; } @@ -97,13 +97,13 @@ extern "C" { #endif // _di_f_file_exists_ #ifndef _di_f_file_exists_at_ - f_return_status f_file_exists_at(const int directory_file_descriptor, const f_string file_name, const int flags) { + f_return_status f_file_exists_at(const int directory_file_descriptor, const f_string path, const int flags) { #ifndef _di_level_0_parameter_checking_ if (directory_file_descriptor == 0) return f_status_set_error(f_invalid_parameter); - if (file_name == 0) return f_status_set_error(f_invalid_parameter); + if (path == 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ - if (faccessat(directory_file_descriptor, file_name, F_OK, flags)) { + if (faccessat(directory_file_descriptor, path, F_OK, flags)) { if (errno == ENOENT) { return f_false; } @@ -288,9 +288,53 @@ extern "C" { } #endif // _di_f_file_read_until_ +#ifndef _di_f_file_remove_ + f_return_status f_file_remove(const f_string path) { + if (unlink(path) < 0) { + if (errno == EACCES) { + return f_status_set_error(f_access_denied); + } + else if (errno == EBUSY) { + return f_status_set_error(f_busy); + } + else if (errno == EIO) { + return f_status_set_error(f_error_input_output); + } + else if (errno == EISDIR) { + return f_status_set_error(f_file_is_type_directory); + } + else if (errno == ELOOP) { + return f_status_set_error(f_loop); + } + else if (errno == ENAMETOOLONG || errno == EFAULT) { + return f_status_set_error(f_invalid_name); + } + else if (errno == ENOENT) { + return f_status_set_error(f_file_not_found); + } + else if (errno == ENOMEM) { + return f_status_set_error(f_out_of_memory); + } + else if (errno == ENOTDIR) { + return f_status_set_error(f_invalid_directory); + } + else if (errno == EPERM) { + return f_status_set_error(f_prohibited); + } + else if (errno == EROFS) { + return f_status_set_error(f_read_only); + } + + return f_status_set_error(f_failure); + } + + return f_none; + } +#endif // _di_f_file_remove_ + #ifndef _di_f_file_stat_ - f_return_status f_file_stat(const f_string file_name, struct stat *file_stat) { - if (stat(file_name, file_stat) < 0) { + f_return_status f_file_stat(const f_string path, struct stat *file_stat) { + if (stat(path, file_stat) < 0) { if (errno == ENAMETOOLONG || errno == EFAULT) { return f_status_set_error(f_invalid_name); } @@ -321,12 +365,13 @@ extern "C" { #endif // _di_f_file_stat_ #ifndef _di_f_file_stat_at_ - f_return_status f_file_stat_at(const int file_id, const f_string file_name, struct stat *file_stat, const int flags) { + f_return_status f_file_stat_at(const int file_id, const f_string path, struct stat *file_stat, const int flags) { #ifndef _di_level_0_parameter_checking_ if (file_id <= 0) return f_status_set_error(f_invalid_parameter); #endif // _di_level_0_parameter_checking_ - int result = fstatat(file_id, file_name, file_stat, flags); + int result = fstatat(file_id, path, file_stat, flags); + if (result < 0) { if (errno == ENAMETOOLONG || errno == EFAULT) { return f_status_set_error(f_invalid_name); @@ -364,6 +409,7 @@ extern "C" { #endif // _di_level_0_parameter_checking_ int result = fstat(file_id, file_stat); + if (result < 0) { if (errno == ENAMETOOLONG || errno == EFAULT) { return f_status_set_error(f_invalid_name); diff --git a/level_0/f_file/c/file.h b/level_0/f_file/c/file.h index 6e18b55..1d42b58 100644 --- a/level_0/f_file/c/file.h +++ b/level_0/f_file/c/file.h @@ -75,6 +75,31 @@ extern "C" { #endif // _di_f_file_seeks_ /** + * Provide file type macros. + */ +#ifndef _di_f_file_type_ + #define f_file_type_mask S_IFMT + + #define f_file_type_pipe S_IFIFO + #define f_file_type_character S_IFCHR + #define f_file_type_directory S_IFDIR + #define f_file_type_block S_IFBLK + #define f_file_type_file S_IFREG + #define f_file_type_link S_IFLNK + #define f_file_type_socket S_IFSOCK + + #define f_macro_file_type_is(mode) f_file_type_mask & S_IFIFO + + #define f_macro_file_type_is_pipe(mode) f_macro_file_type_is(mode) == f_file_type_pipe + #define f_macro_file_type_is_character(mode) f_macro_file_type_is(mode) == f_file_type_character + #define f_macro_file_type_is_directory(mode) f_macro_file_type_is(mode) == f_file_type_directory + #define f_macro_file_type_is_block(mode) f_macro_file_type_is(mode) == f_file_type_block + #define f_macro_file_type_is_file(mode) f_macro_file_type_is(mode) == f_file_type_file + #define f_macro_file_type_is_link(mode) f_macro_file_type_is(mode) == f_file_type_link + #define f_macro_file_type_is_socket(mode) f_macro_file_type_is(mode) == f_file_type_socket +#endif // _di_f_file_type_ + +/** * Commonly used file related properties. * * id: File descriptor. @@ -248,8 +273,8 @@ extern "C" { * @param file * The data related to the file being opened. * This will be updated with the file descriptor and file address. - * @param file_name - * The name of the file to be opened. + * @param path + * The path file name. * * @return * f_none on success. @@ -259,7 +284,7 @@ extern "C" { * f_invalid_parameter (with error bit) if a parameter is invalid. */ #ifndef _di_f_file_open_ - extern f_return_status f_file_open(f_file *file, const f_string file_name); + extern f_return_status f_file_open(f_file *file, const f_string path); #endif // _di_f_file_open_ /** @@ -287,8 +312,8 @@ extern "C" { /** * Check if a file exists. * - * @param file_name - * The file name. + * @param path + * The path file name. * * @return * f_true if file exists. @@ -303,7 +328,7 @@ extern "C" { * f_false (with error bit) on unknown/unhandled errors. */ #ifndef _di_f_file_exists_ - extern f_return_status f_file_exists(const f_string file_name); + extern f_return_status f_file_exists(const f_string path); #endif // _di_f_file_exists_ /** @@ -311,8 +336,8 @@ extern "C" { * * @param directory_file_descriptor * The file descriptor of the directory. - * @param file_name - * The file name. + * @param path + * The path file name. * @param flags * Additional flags to pass, such as AT_EACCESS or AT_SYMLINK_NOFOLLOW. * @@ -329,7 +354,7 @@ extern "C" { * f_false (with error bit) on unknown/unhandled errors. */ #ifndef _di_f_file_exists_at_ - extern f_return_status f_file_exists_at(const int directory_file_descriptor, const f_string file_name, const int flags); + extern f_return_status f_file_exists_at(const int directory_file_descriptor, const f_string path, const int flags); #endif // _di_f_file_exists_at_ /** @@ -431,6 +456,34 @@ extern "C" { #endif // _di_f_file_read_until_ /** + * Remove a file. + * + * @param path + * The path file name. + * + * @return + * f_none on success. + * f_invalid_parameter (with error bit) if a parameter is invalid. + * f_access_denied (with error bit) on access denied. + * f_busy (with error bit) if file is busy. + * f_error_input_output (with error bit) if an I/O error occurred. + * f_file_is_type_directory (with error bit) file is a directory (directories cannot be removed via this function). + * f_loop (with error bit) on loop error. + * f_invalid_name (with error bit) on path name error. + * f_file_not_found (with error bit) if file not found. + * f_out_of_memory (with error bit) if out of memory. + * f_invalid_directory (with error bit) if a supposed directory in path is not actually a directory. + * f_prohibited (with error bit) if filesystem does not allow for removing. + * f_read_only (with error bit) if file is read-only. + * f_failure (with error bit) for any other (unlink()) error. + * + * @see unlink() + */ +#ifndef _di_f_file_remove_ + extern f_return_status f_file_remove(const f_string path); +#endif // _di_f_file_remove_ + +/** * Read statistics of a file. * * This will not re-read the file statistics., file_status must not be allocated. diff --git a/level_0/f_status/c/status.h b/level_0/f_status/c/status.h index e3b57d4..e0d03bf 100644 --- a/level_0/f_status/c/status.h +++ b/level_0/f_status/c/status.h @@ -148,9 +148,12 @@ extern "C" { f_not_connected, f_no_data, f_out_of_memory, + f_prohibited, + f_read_only, f_unknown, f_unsupported, f_warn, + f_write_only, #endif // _di_f_status_basic_ #ifndef _di_f_status_invalid_ @@ -279,9 +282,27 @@ extern "C" { f_file_error_write, f_file_found, f_file_is_empty, + f_file_is_type_block, + f_file_is_type_character, + f_file_is_type_directory, + f_file_is_type_file, + f_file_is_type_link, + f_file_is_type_pipe, + f_file_is_type_socket, + f_file_is_type_unknown, f_file_not_found, f_file_not_open, + f_file_not_type_block, + f_file_not_type_character, + f_file_not_type_directory, + f_file_not_type_file, + f_file_not_type_link, + f_file_not_type_pipe, + f_file_not_type_socket, + f_file_not_type_unknown, f_file_not_utf, + f_file_max_descriptors, + f_file_max_open, #endif // _di_f_status_file_ // Most of these are a guess until I get around to researching & implementing linux directory I/O. @@ -295,7 +316,9 @@ extern "C" { f_directory_error_purge, f_directory_error_read, f_directory_error_reallocation, + f_directory_error_stream, f_directory_error_synchronize, + f_directory_error_unsupported, f_directory_error_write, f_directory_is_empty, f_directory_not_found, diff --git a/level_1/fl_directory/c/directory.c b/level_1/fl_directory/c/directory.c deleted file mode 100644 index 3463eb1..0000000 --- a/level_1/fl_directory/c/directory.c +++ /dev/null @@ -1,89 +0,0 @@ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _di_fl_directory_list_ - f_return_status fl_directory_list(const f_string directory_path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_string_dynamics *names) { - #ifndef _di_level_1_parameter_checking_ - if (names == 0) return f_status_set_error(f_invalid_parameter); - #endif // _di_level_1_parameter_checking_ - - struct dirent **listing = 0; - int length = 0; - int i = 0; - f_string_length size = 0; - f_status status = f_none; - - length = scandir(directory_path, &listing, filter, sort); - - for (; i < length; i++) { - size = strnlen(listing[i]->d_name, fl_directory_name_max); - - // There is no reason to include "." and ".." in the directory listing. - if (strncmp(listing[i]->d_name, "..", 3) == 0 || strncmp(listing[i]->d_name, ".", 2) == 0) { - f_memory_delete((void **) & listing[i], sizeof(char *), 1); - continue; - } - - if (names->used >= names->size) { - f_macro_string_dynamics_resize(status, (*names), names->size + fl_directory_default_allocation_step); - - if (f_status_is_error(status)) { - for (int j = i; j < length; j++) { - f_memory_delete((void **) & listing[i], sizeof(char *), 1); - } // for - - f_macro_string_dynamics_delete_simple((*names)); - f_memory_delete((void **) & listing, sizeof(struct dirent *), 1); - - return status; - } - } - - f_macro_string_dynamic_new(status, names->array[names->used], size); - - if (f_status_is_error(status)) { - for (int j = i; j < length; j++) { - f_memory_delete((void **) & listing[i], sizeof(char *), 1); - } // for - - f_macro_string_dynamics_delete_simple((*names)); - f_memory_delete((void **) & listing, sizeof(struct dirent *), 1); - - return status; - } - - memcpy(names->array[names->used].string, listing[i]->d_name, size); - names->array[names->used].used = size; - names->used++; - - f_memory_delete((void **) & listing[i], sizeof(char *), 1); - } // for - - for (int j = i; j < length; j++) { - f_memory_delete((void **) & listing[i], sizeof(char *), 1); - } - - f_memory_delete((void **) & listing, sizeof(struct dirent *), 1); - - if (length == 0) { - return f_no_data; - } - else if (length == -1) { - if (errno == ENOMEM) { - return f_status_set_error(f_error_allocation); - } - else { - return f_status_set_error(f_failure); - } - } - - return f_none; - } -#endif // _di_fl_directory_list_ - -#ifdef __cplusplus -} // extern "C" -#endif diff --git a/level_1/fl_status/c/status.c b/level_1/fl_status/c/status.c index 5aef397..529628d 100644 --- a/level_1/fl_status/c/status.c +++ b/level_1/fl_status/c/status.c @@ -243,6 +243,12 @@ extern "C" { case f_out_of_memory: *string = fl_status_string_out_of_memory; break; + case f_prohibited: + *string = fl_status_string_prohibited; + break; + case f_read_only: + *string = fl_status_string_read_only; + break; case f_error_input: *string = fl_status_string_input_error; break; @@ -270,6 +276,9 @@ extern "C" { case f_incomplete: *string = fl_status_string_incomplete; break; + case f_write_only: + *string = fl_status_string_write_only; + break; #endif // _di_fl_status_basic_ #ifndef _di_fl_status_invalid_ @@ -594,9 +603,57 @@ extern "C" { case f_file_is_empty: *string = fl_status_string_file_is_empty; break; + case f_file_is_type_block: + *string = fl_status_string_file_is_type_block; + break; + case f_file_is_type_character: + *string = fl_status_string_file_is_type_character; + break; + case f_file_is_type_directory: + *string = fl_status_string_file_is_type_directory; + break; + case f_file_is_type_file: + *string = fl_status_string_file_is_type_file; + break; + case f_file_is_type_link: + *string = fl_status_string_file_is_type_link; + break; + case f_file_is_type_pipe: + *string = fl_status_string_file_is_type_pipe; + break; + case f_file_is_type_socket: + *string = fl_status_string_file_is_type_socket; + break; + case f_file_is_type_unknown: + *string = fl_status_string_file_is_type_unknown; + break; case f_file_not_open: *string = fl_status_string_file_not_open; break; + case f_file_not_type_block: + *string = fl_status_string_file_not_type_block; + break; + case f_file_not_type_character: + *string = fl_status_string_file_not_type_character; + break; + case f_file_not_type_directory: + *string = fl_status_string_file_not_type_directory; + break; + case f_file_not_type_file: + *string = fl_status_string_file_not_type_file; + break; + case f_file_not_type_link: + *string = fl_status_string_file_not_type_link; + break; + case f_file_not_type_pipe: + *string = fl_status_string_file_not_type_pipe; + break; + case f_file_not_type_socket: + *string = fl_status_string_file_not_type_socket; + break; + case f_file_not_type_unknown: + *string = fl_status_string_file_not_type_unknown; + break; case f_file_error_allocation: *string = fl_status_string_file_allocation_error; break; @@ -615,6 +672,12 @@ extern "C" { case f_file_not_utf: *string = fl_status_string_file_not_utf; break; + case f_file_max_descriptors: + *string = fl_status_string_file_max_descriptors; + break; + case f_file_max_open: + *string = fl_status_string_file_max_open; + break; #endif // _di_fl_status_file_ #ifndef _di_fl_status_directory_ @@ -663,6 +726,12 @@ extern "C" { case f_directory_not_utf: *string = fl_status_string_directory_not_utf; break; + case f_directory_error_unsupported: + *string = fl_status_string_directory_error_unsupported; + break; + case f_directory_error_stream: + *string = fl_status_string_directory_error_stream; + break; #endif // _di_fl_status_directory_ #ifndef _di_fl_status_socket_ diff --git a/level_1/fl_status/c/status.h b/level_1/fl_status/c/status.h index a99fed8..f642b84 100644 --- a/level_1/fl_status/c/status.h +++ b/level_1/fl_status/c/status.h @@ -251,6 +251,12 @@ extern "C" { #define fl_status_string_out_of_memory "f_out_of_memory" #define fl_status_string_out_of_memory_length 15 + #define fl_status_string_prohibited "f_prohibited" + #define fl_status_string_prohibited_length 12 + + #define fl_status_string_read_only "f_read_only" + #define fl_status_string_read_only_length 11 + #define fl_status_string_input_error "f_error_input" #define fl_status_string_input_error_length 13 @@ -277,6 +283,9 @@ extern "C" { #define fl_status_string_incomplete "f_incomplete" #define fl_status_string_incomplete_length 12 + + #define fl_status_string_write_only "f_write_only" + #define fl_status_string_write_only_length 12 #endif // _di_fl_status_basic_ #ifndef _di_fl_status_invalid_ @@ -591,12 +600,63 @@ extern "C" { #define fl_status_string_file_found "f_file_found" #define fl_status_string_file_found_length 12 + #define fl_status_string_file_is "f_file_is" + #define fl_status_string_file_is_length 9 + #define fl_status_string_file_is_empty "f_file_is_empty" #define fl_status_string_file_is_empty_length 15 + #define fl_status_string_file_is_type_block "f_file_is_type_block" + #define fl_status_string_file_is_type_block_length 20 + + #define fl_status_string_file_is_type_character "f_file_is_type_character" + #define fl_status_string_file_is_type_character_length 24 + + #define fl_status_string_file_is_type_directory "f_file_is_type_directory" + #define fl_status_string_file_is_type_directory_length 24 + + #define fl_status_string_file_is_type_file "f_file_is_type_file" + #define fl_status_string_file_is_type_file_length 19 + + #define fl_status_string_file_is_type_link "f_file_is_type_link" + #define fl_status_string_file_is_type_link_length 19 + + #define fl_status_string_file_is_type_pipe "f_file_is_type_pipe" + #define fl_status_string_file_is_type_pipe_length 19 + + #define fl_status_string_file_is_type_socket "f_file_is_type_socket" + #define fl_status_string_file_is_type_socket_length 21 + + #define fl_status_string_file_is_type_unknown "f_file_is_type_unknown" + #define fl_status_string_file_is_type_unknown_length 22 + #define fl_status_string_file_not_open "f_file_not_open" #define fl_status_string_file_not_open_length 15 + #define fl_status_string_file_not_type_block "f_file_not_type_block" + #define fl_status_string_file_not_type_block_length 21 + + #define fl_status_string_file_not_type_character "f_file_not_type_character" + #define fl_status_string_file_not_type_character_length 25 + + #define fl_status_string_file_not_type_directory "f_file_not_type_directory" + #define fl_status_string_file_not_type_directory_length 25 + + #define fl_status_string_file_not_type_file "f_file_not_type_file" + #define fl_status_string_file_not_type_file_length 20 + + #define fl_status_string_file_not_type_link "f_file_not_type_link" + #define fl_status_string_file_not_type_link_length 20 + + #define fl_status_string_file_not_type_pipe "f_file_not_type_pipe" + #define fl_status_string_file_not_type_pipe_length 20 + + #define fl_status_string_file_not_type_socket "f_file_not_type_socket" + #define fl_status_string_file_not_type_socket_length 22 + + #define fl_status_string_file_not_type_unknown "f_file_not_type_unknown" + #define fl_status_string_file_not_type_unknown_length 23 + #define fl_status_string_file_allocation_error "f_file_error_allocation" #define fl_status_string_file_allocation_error_length 23 @@ -614,6 +674,12 @@ extern "C" { #define fl_status_string_file_not_utf "f_file_not_utf" #define fl_status_string_file_not_utf_length 14 + + #define fl_status_string_file_max_descriptors "f_file_max_descriptors" + #define fl_status_string_file_max_descriptors_length 22 + + #define fl_status_string_file_max_open "f_file_max_open" + #define fl_status_string_file_max_open_length 15 #endif // _di_fl_status_file_ #ifndef _di_fl_status_directory_ @@ -661,6 +727,12 @@ extern "C" { #define fl_status_string_directory_not_utf "f_directory_not_utf" #define fl_status_string_directory_not_utf_length 19 + + #define fl_status_string_directory_error_unsupported "f_directory_error_unsupported" + #define fl_status_string_directory_error_unsupported_length 19 + + #define fl_status_string_directory_error_stream "f_directory_error_stream" + #define fl_status_string_directory_error_stream_length 19 #endif // _di_fl_status_directory_ #ifndef _di_fl_status_socket_ diff --git a/level_2/fll_directory/c/directory.c b/level_2/fll_directory/c/directory.c new file mode 100644 index 0000000..a0ebf9f --- /dev/null +++ b/level_2/fll_directory/c/directory.c @@ -0,0 +1,151 @@ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_fll_directory_list_ + f_return_status fll_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing) { + #ifndef _di_level_2_parameter_checking_ + if (listing == 0) return f_status_set_error(f_invalid_parameter); + #endif // _di_level_2_parameter_checking_ + + struct dirent **entity = 0; + + f_string_length size = 0; + f_status status = f_none; + + DIR *parent = opendir(path); + + if (parent == 0) { + if (errno == ENOMEM) { + return f_status_set_error(f_out_of_memory); + } + else if (errno == ENOMEM) { + return f_status_set_error(f_out_of_memory); + } + else if (errno == EMFILE) { + return f_status_set_error(f_file_max_descriptors); + } + else if (errno == ENFILE) { + return f_status_set_error(f_file_max_open); + } + else if (errno == ENOTDIR) { + return f_status_set_error(f_invalid_directory); + } + else if (errno == ENOENT) { + return f_status_set_error(f_directory_not_found); + } + else if (errno == EACCES) { + return f_status_set_error(f_access_denied); + } + + return f_status_set_error(f_directory_error_open); + } + + int parent_fd = dirfd(parent); + + if (parent_fd < 0) { + closedir(parent); + + if (errno == EINVAL) { + return f_status_set_error(f_directory_error_stream); + } + else if (errno == ENOTSUP) { + return f_status_set_error(f_directory_error_unsupported); + } + + return f_status_set_error(f_directory_error_descriptor); + } + + const size_t length = scandir(path, &entity, filter, sort); + + if (length == -1) { + closedir(parent); + + if (errno == ENOMEM) return f_status_set_error(f_error_allocation); + else return f_status_set_error(f_failure); + } + + f_string_dynamics *names = 0; + struct stat file_stat; + int mode = 0; + size_t i = 0; + + for (; i < length; i++) { + size = strnlen(entity[i]->d_name, f_directory_name_max); + + // There is no reason to include "." and ".." in the directory listing. + if (strncmp(entity[i]->d_name, "..", 3) == 0 || strncmp(entity[i]->d_name, ".", 2) == 0) { + f_memory_delete((void **) & entity[i], sizeof(char *), 1); + continue; + } + + memset(&file_stat, 0, sizeof(file_stat)); + + status = f_file_stat_at(parent_fd, entity[i]->d_name, &file_stat, 0); + if (f_status_is_error(status)) break; + + mode = f_macro_file_type_is(file_stat.d_type); + + if (mode == f_file_type_block) { + names = &listing->block; + } + else if (mode == f_file_type_character) { + names = &listing->character; + } + else if (mode == f_file_type_directory) { + names = &listing->directory; + } + else if (mode == f_file_type_file) { + names = &listing->file; + } + else if (mode == f_file_type_link) { + names = &listing->link; + } + else if (mode == f_file_type_pipe) { + names = &listing->pipe; + } + else if (mode == f_file_type_socket) { + names = &listing->socket; + } + else { + names = &listing->unknown; + } + + if (names->used >= names->size) { + f_macro_string_dynamics_resize(status, (*names), names->size + f_directory_default_allocation_step); + if (f_status_is_error(status)) break; + } + + f_macro_string_dynamic_new(status, names->array[names->used], size); + if (f_status_is_error(status)) break; + + fl_string_dynamic_terminate(&names->array[names->used]); + if (f_status_is_error(status)) break; + + memcpy(names->array[names->used].string, entity[i]->d_name, size); + names->array[names->used].used = size; + names->used++; + + f_memory_delete((void **) & entity[i], sizeof(char *), 1); + } // for + + closedir(parent); + + for (; i < length; i++) { + f_memory_delete((void **) & entity[i], sizeof(char *), 1); + } // for + + f_memory_delete((void **) & entity, sizeof(struct dirent *), 1); + + if (f_status_is_error(status)) return status; + if (length == 0) return f_no_data; + + return f_none; + } +#endif // _di_fll_directory_list_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/level_1/fl_directory/c/directory.h b/level_2/fll_directory/c/directory.h similarity index 54% rename from level_1/fl_directory/c/directory.h rename to level_2/fll_directory/c/directory.h index c195867..8007d09 100644 --- a/level_1/fl_directory/c/directory.h +++ b/level_2/fll_directory/c/directory.h @@ -1,5 +1,5 @@ /** - * FLL - Level 1 + * FLL - Level 2 * * Project: Directory * API Version: 0.5 @@ -7,8 +7,8 @@ * * Provides operations for directory handling. */ -#ifndef _FL_directory_h -#define _FL_directory_h +#ifndef _FLL_directory_h +#define _FLL_directory_h // libc includes #include @@ -23,23 +23,22 @@ #include #include #include +#include +#include + +// fll-1 includes +#include #ifdef __cplusplus extern "C" { #endif -#ifndef _di_fl_directory_limitations_ - #define fl_directory_default_allocation_step f_memory_default_allocation_step - - #define fl_directory_name_max 255 -#endif // _di_fl_directory_limitations_ - /** - * Print the names of each file and/or directory inside the given directory. + * For some given path, print the names of each file and/or directory inside the directory, stored as a directory listing. * * Allows specifying a custom filter and custom sort. * - * @param directory_path + * @param path * Filesystem path to the directory. * @param filter * A filter function of the form: int xxx(const struct direct *). @@ -48,8 +47,8 @@ extern "C" { * A sort function of the form: int xxx(const struct direct *, const struct direct *). * Set to 0 to not use (NULL). * There are two pre-made libc functions available for this: alphasort() and versionsort(). - * @param names - * Will be populated with the names of each file and/or directory inside the names parameter. + * @param listing + * Will be populated with the names of all top-level paths found within the given directory. * * @return * f_none on success. @@ -57,15 +56,21 @@ extern "C" { * f_failure (with error bit) if failed to read directory information. * f_invalid_parameter (with error bit) if a parameter is invalid. * f_error_reallocation (with error bit) on memory reallocation error. + * f_directory_error_open (with error bit) on directory open error. + * f_directory_error_descriptor (with error bit) on directory file descriptor error. + * f_directory_error_stream (with error bit) on directory stream error. + * f_directory_error_unsupported (with error bit) on directory file descriptor not supported. * + * @see alphasort() * @see scandir() + * @see versionsort() */ -#ifndef _di_fl_directory_list_ - extern f_return_status fl_directory_list(const f_string directory_path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_string_dynamics *names); -#endif // _di_fl_directory_list_ +#ifndef _di_fll_directory_list_ + extern f_return_status fll_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), f_directory_listing *listing); +#endif // _di_fll_directory_list_ #ifdef __cplusplus } // extern "C" #endif -#endif // _FL_directory_h +#endif // _FLL_directory_h diff --git a/level_2/fll_directory/data/build/dependencies b/level_2/fll_directory/data/build/dependencies new file mode 100644 index 0000000..d7cea6f --- /dev/null +++ b/level_2/fll_directory/data/build/dependencies @@ -0,0 +1,7 @@ +f_type +f_status +f_memory +f_string +f_directory +f_file +fl_string diff --git a/level_2/fll_directory/data/build/settings b/level_2/fll_directory/data/build/settings new file mode 100644 index 0000000..add38a4 --- /dev/null +++ b/level_2/fll_directory/data/build/settings @@ -0,0 +1,30 @@ +# fss-0000 + +project_name fll_directory +project_level 2 + +version_major 0 +version_minor 5 +version_micro 0 + +build_compiler gcc +build_linker ar +build_libraries -lc +build_libraries_fll -lfl_string -lf_directory -lf_memory -lf_file +build_sources_library directory.c +build_sources_program +build_sources_headers directory.h +build_sources_bash +build_sources_settings +build_shared yes +build_static yes + +defines_all +defines_static +defines_shared + +flags_all -z now -g +flags_shared +flags_static +flags_library -fPIC +flags_program -fPIE diff --git a/level_2/fll_status/c/status.c b/level_2/fll_status/c/status.c index 2a7b8e9..e741f48 100644 --- a/level_2/fll_status/c/status.c +++ b/level_2/fll_status/c/status.c @@ -406,6 +406,16 @@ extern "C" { return f_none; } + if (fl_string_compare(string, fl_status_string_prohibited, length, fl_status_string_prohibited_length) == f_equal_to) { + *code = f_prohibited; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_read_only, length, fl_status_string_read_only_length) == f_equal_to) { + *code = f_read_only; + return f_none; + } + if (fl_string_compare(string, fl_status_string_input_error, length, fl_status_string_input_error_length) == f_equal_to) { *code = f_error_input; return f_none; @@ -450,6 +460,11 @@ extern "C" { *code = f_incomplete; return f_none; } + + if (fl_string_compare(string, fl_status_string_write_only, length, fl_status_string_write_only_length) == f_equal_to) { + *code = f_write_only; + return f_none; + } #endif // _di_fll_status_basic_ #ifndef _di_fll_status_invalid_ @@ -967,11 +982,91 @@ extern "C" { return f_none; } + if (fl_string_compare(string, fl_status_string_file_is_type_block, length, fl_status_string_file_is_type_block_length) == f_equal_to) { + *code = f_file_is_type_block; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_is_type_character, length, fl_status_string_file_is_type_character_length) == f_equal_to) { + *code = f_file_is_type_character; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_is_type_directory, length, fl_status_string_file_is_type_directory_length) == f_equal_to) { + *code = f_file_is_type_directory; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_is_type_file, length, fl_status_string_file_is_type_file_length) == f_equal_to) { + *code = f_file_is_type_file; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_is_type_link, length, fl_status_string_file_is_type_link_length) == f_equal_to) { + *code = f_file_is_type_link; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_is_type_pipe, length, fl_status_string_file_is_type_pipe_length) == f_equal_to) { + *code = f_file_is_type_pipe; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_is_type_socket, length, fl_status_string_file_is_type_socket_length) == f_equal_to) { + *code = f_file_is_type_socket; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_is_type_unknown, length, fl_status_string_file_is_type_unknown_length) == f_equal_to) { + *code = f_file_is_type_unknown; + return f_none; + } + if (fl_string_compare(string, fl_status_string_file_not_open, length, fl_status_string_file_not_open_length) == f_equal_to) { *code = f_file_not_open; return f_none; } + if (fl_string_compare(string, fl_status_string_file_not_type_block, length, fl_status_string_file_not_type_block_length) == f_equal_to) { + *code = f_file_not_type_block; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_not_type_character, length, fl_status_string_file_not_type_character_length) == f_equal_to) { + *code = f_file_not_type_character; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_not_type_directory, length, fl_status_string_file_not_type_directory_length) == f_equal_to) { + *code = f_file_not_type_directory; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_not_type_file, length, fl_status_string_file_not_type_file_length) == f_equal_to) { + *code = f_file_not_type_file; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_not_type_link, length, fl_status_string_file_not_type_link_length) == f_equal_to) { + *code = f_file_not_type_link; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_not_type_pipe, length, fl_status_string_file_not_type_pipe_length) == f_equal_to) { + *code = f_file_not_type_pipe; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_not_type_socket, length, fl_status_string_file_not_type_socket_length) == f_equal_to) { + *code = f_file_not_type_socket; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_not_type_unknown, length, fl_status_string_file_not_type_unknown_length) == f_equal_to) { + *code = f_file_not_type_unknown; + return f_none; + } + if (fl_string_compare(string, fl_status_string_file_allocation_error, length, fl_status_string_file_allocation_error_length) == f_equal_to) { *code = f_file_error_allocation; return f_none; @@ -1001,6 +1096,16 @@ extern "C" { *code = f_file_not_utf; return f_none; } + + if (fl_string_compare(string, fl_status_string_file_max_descriptors, length, fl_status_string_file_max_descriptors_length) == f_equal_to) { + *code = f_file_max_descriptors; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_file_max_open, length, fl_status_string_file_max_open_length) == f_equal_to) { + *code = f_file_max_open; + return f_none; + } #endif // _di_fll_status_file_ #ifndef _di_fll_status_directory_ @@ -1078,6 +1183,16 @@ extern "C" { *code = f_directory_not_utf; return f_none; } + + if (fl_string_compare(string, fl_status_string_directory_error_unsupported, length, fl_status_string_directory_error_unsupported_length) == f_equal_to) { + *code = f_directory_error_unsupported; + return f_none; + } + + if (fl_string_compare(string, fl_status_string_directory_error_stream, length, fl_status_string_directory_error_stream_length) == f_equal_to) { + *code = f_directory_error_stream; + return f_none; + } #endif // _di_fll_status_directory_ #ifndef _di_fll_status_socket_ diff --git a/level_3/firewall/c/firewall.c b/level_3/firewall/c/firewall.c index d5e3285..1c6701d 100644 --- a/level_3/firewall/c/firewall.c +++ b/level_3/firewall/c/firewall.c @@ -315,7 +315,7 @@ extern "C" { } // load all network devices - status = fl_directory_list((f_string) network_devices, 0, alphasort, &data->devices); + status = f_directory_list((f_string) network_devices, 0, alphasort, &data->devices); if (f_status_is_error(status)) { status = f_status_set_fine(status); diff --git a/level_3/firewall/c/firewall.h b/level_3/firewall/c/firewall.h index fef1286..bafde6a 100644 --- a/level_3/firewall/c/firewall.h +++ b/level_3/firewall/c/firewall.h @@ -18,6 +18,7 @@ // fll-0 includes #include +#include #include #include #include @@ -28,7 +29,6 @@ // fll-1 includes #include #include -#include #include #include diff --git a/level_3/firewall/data/build/dependencies b/level_3/firewall/data/build/dependencies index 22893e8..74d54e8 100644 --- a/level_3/firewall/data/build/dependencies +++ b/level_3/firewall/data/build/dependencies @@ -4,13 +4,13 @@ f_memory f_string f_color f_console +f_directory f_fss f_pipe f_print f_utf fl_color fl_console -fl_directory fl_file fl_fss fl_status diff --git a/level_3/firewall/data/build/settings b/level_3/firewall/data/build/settings index 8569e59..056c458 100644 --- a/level_3/firewall/data/build/settings +++ b/level_3/firewall/data/build/settings @@ -10,7 +10,7 @@ version_micro 0 build_compiler gcc build_linker ar build_libraries -lc -build_libraries_fll -lfll_program -lfll_fss -lfll_execute -lfl_string -lfl_status -lfl_fss -lf_conversion -lfl_file -lfl_directory -lfl_console -lfl_color -lf_file -lf_utf -lf_print -lf_pipe -lf_console -lf_memory +build_libraries_fll -lfll_program -lfll_fss -lfll_execute -lfl_string -lfl_status -lfl_fss -lf_conversion -lfl_file -lfl_console -lfl_color -lf_file -lf_utf -lf_print -lf_pipe -lf_directory -lf_console -lf_memory build_libraries_fll-level -lfll_2 -lfll_1 -lfll_0 build_libraries_fll-monolithic -lfll build_sources_library firewall.c private-firewall.c -- 1.8.3.1