Numerous updates to get the directory functionality better hashed out.
Some of the directory functionality is experimentally added.
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
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
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
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
--- /dev/null
+#include <level_0/directory.h>
+#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
--- /dev/null
+/**
+ * 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 <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+// work-around for out-dated systems.
+#ifndef __USE_XOPEN_EXTENDED
+ #define __USE_XOPEN_EXTENDED
+ #include <ftw.h>
+ #undef __USE_XOPEN_EXTENDED
+#else
+ #include <ftw.h>
+#endif // __USE_XOPEN_EXTENDED
+
+// fll-0 includes
+#include <level_0/status.h>
+#include <level_0/memory.h>
+#include <level_0/string.h>
+#include <level_0/type.h>
+
+#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
--- /dev/null
+#include <level_0/directory.h>
+#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
--- /dev/null
+/**
+ * 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
# fss-0000
-project_name fl_directory
-project_level 1
+project_name f_directory
+project_level 0
version_major 0
version_minor 5
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
#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_
// 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);
#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;
}
#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;
}
}
#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);
}
#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);
#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);
#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.
* @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.
* 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_
/**
/**
* Check if a file exists.
*
- * @param file_name
- * The file name.
+ * @param path
+ * The path file name.
*
* @return
* f_true if file exists.
* 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_
/**
*
* @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.
*
* 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_
/**
#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.
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_
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.
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,
+++ /dev/null
-#include <level_1/directory.h>
-
-#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
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;
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_
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;
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_
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_
#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
#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_
#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
#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_
#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_
--- /dev/null
+#include <level_2/directory.h>
+
+#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
/**
- * FLL - Level 1
+ * FLL - Level 2
*
* Project: Directory
* API Version: 0.5
*
* Provides operations for directory handling.
*/
-#ifndef _FL_directory_h
-#define _FL_directory_h
+#ifndef _FLL_directory_h
+#define _FLL_directory_h
// libc includes
#include <dirent.h>
#include <level_0/memory.h>
#include <level_0/string.h>
#include <level_0/type.h>
+#include <level_0/directory.h>
+#include <level_0/file.h>
+
+// fll-1 includes
+#include <level_1/string.h>
#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 *).
* 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.
* 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
--- /dev/null
+f_type
+f_status
+f_memory
+f_string
+f_directory
+f_file
+fl_string
--- /dev/null
+# 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
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;
*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_
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;
*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_
*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_
}
// 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);
// fll-0 includes
#include <level_0/console.h>
+#include <level_0/directory.h>
#include <level_0/file.h>
#include <level_0/pipe.h>
#include <level_0/print.h>
// fll-1 includes
#include <level_1/color.h>
#include <level_1/console.h>
-#include <level_1/directory.h>
#include <level_1/file.h>
#include <level_1/string.h>
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
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