]> Kevux Git Server - fll/commitdiff
Update: new directory related functions, file function updates, status code updates...
authorKevin Day <thekevinday@gmail.com>
Mon, 11 May 2020 01:08:36 +0000 (20:08 -0500)
committerKevin Day <thekevinday@gmail.com>
Mon, 11 May 2020 01:16:46 +0000 (20:16 -0500)
Numerous updates to get the directory functionality better hashed out.
Some of the directory functionality is experimentally added.

25 files changed:
build/level_0/settings
build/level_1/settings
build/level_2/settings
build/monolithic/settings
level_0/f_directory/c/directory.c [new file with mode: 0644]
level_0/f_directory/c/directory.h [new file with mode: 0644]
level_0/f_directory/c/private-directory.c [new file with mode: 0644]
level_0/f_directory/c/private-directory.h [new file with mode: 0644]
level_0/f_directory/data/build/dependencies [moved from level_1/fl_directory/data/build/dependencies with 100% similarity]
level_0/f_directory/data/build/settings [moved from level_1/fl_directory/data/build/settings with 81% similarity]
level_0/f_file/c/file.c
level_0/f_file/c/file.h
level_0/f_status/c/status.h
level_1/fl_directory/c/directory.c [deleted file]
level_1/fl_status/c/status.c
level_1/fl_status/c/status.h
level_2/fll_directory/c/directory.c [new file with mode: 0644]
level_2/fll_directory/c/directory.h [moved from level_1/fl_directory/c/directory.h with 54% similarity]
level_2/fll_directory/data/build/dependencies [new file with mode: 0644]
level_2/fll_directory/data/build/settings [new file with mode: 0644]
level_2/fll_status/c/status.c
level_3/firewall/c/firewall.c
level_3/firewall/c/firewall.h
level_3/firewall/data/build/dependencies
level_3/firewall/data/build/settings

index 134cdb971d772d7bb6390169d3ba130b0fcf1c85..fbb80e74d32d874e5b37af3f1d2ac11927755358 100644 (file)
@@ -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
 
index e32bfcd38a90d917d67f9c94b03e487e46b5a7c0..bc4aba0577b7a75b50c198e16cdfa119e760d517 100644 (file)
@@ -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
 
index bc0aa1ba684e8b6061f95dc1b2cb60b6c582966e..77c35258e45abf6d85c923708b3381b9f54827e3 100644 (file)
@@ -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
 
index e79f99f18062904ba21d7ef802d613a85fd7e048..5482ae34dab6d1320ec52a3c4e158e6b6a57b83b 100644 (file)
@@ -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 (file)
index 0000000..2dbc324
--- /dev/null
@@ -0,0 +1,197 @@
+#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
diff --git a/level_0/f_directory/c/directory.h b/level_0/f_directory/c/directory.h
new file mode 100644 (file)
index 0000000..82a1612
--- /dev/null
@@ -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 <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
diff --git a/level_0/f_directory/c/private-directory.c b/level_0/f_directory/c/private-directory.c
new file mode 100644 (file)
index 0000000..4245232
--- /dev/null
@@ -0,0 +1,17 @@
+#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
diff --git a/level_0/f_directory/c/private-directory.h b/level_0/f_directory/c/private-directory.h
new file mode 100644 (file)
index 0000000..79f80cc
--- /dev/null
@@ -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
similarity index 81%
rename from level_1/fl_directory/data/build/settings
rename to level_0/f_directory/data/build/settings
index 0910a54ca3c16460bffe83445c7e3e8ded9336a4..0f9b9b2efd63c863823e6318f3d5cf818c88db4d 100644 (file)
@@ -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
index 485cd92d4575ffd283fd30746fc67325d65958ef..4edca30e2ef26b1d88445e9b6aa4ab0b85730517 100644 (file)
@@ -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);
index 6e18b5532e30827fd75c62d138203bd5c7efa23e..1d42b58612bd584eb6a851ada8154f89e13d4a27 100644 (file)
@@ -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.
index e3b57d466c8d91690ce719deec2e9cc82a4bad76..e0d03bf7577d559656f2f228307b1a27a5860d9e 100644 (file)
@@ -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 (file)
index 3463eb1..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#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
index 5aef3974cb3b23f359530bf226375d8d4c0877d1..529628def9d8e1e413f43b61c6568e6e37ba99fa 100644 (file)
@@ -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_
index a99fed84be8cff53a3b1dd473fd76163f1083849..f642b849c28370e89edbc037a61b57d97aa9ed3e 100644 (file)
@@ -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 (file)
index 0000000..a0ebf9f
--- /dev/null
@@ -0,0 +1,151 @@
+#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
similarity index 54%
rename from level_1/fl_directory/c/directory.h
rename to level_2/fll_directory/c/directory.h
index c195867d819ba6538e179fde6aa2cfbbfeaeb145..8007d090e5dfaaf31b179e4a2c26501d0fabd9b5 100644 (file)
@@ -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 <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 *).
@@ -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 (file)
index 0000000..d7cea6f
--- /dev/null
@@ -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 (file)
index 0000000..add38a4
--- /dev/null
@@ -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
index 2a7b8e978c422b86c94043581f803d8cbe1399da..e741f4802448dae0929e0cf2daa70db00aefcb7e 100644 (file)
@@ -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_
index d5e32858331846789982392275f281845cf8d659..1c6701d44fce497e51aa95798d37ccc7a81c6ca4 100644 (file)
@@ -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);
index fef1286b9bf6f650c0f02a86ee7a7bd46b338453..bafde6a13995cb4f081a1ac2049271be86f8219f 100644 (file)
@@ -18,6 +18,7 @@
 
 // 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>
@@ -28,7 +29,6 @@
 // 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>
 
index 22893e8f9d68ea73f667ba0d591b89b2a53114f2..74d54e8d0ccc6290dde4058475bcc8f4948e451b 100644 (file)
@@ -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
index 8569e5936328507f6c944364bd390db7d9c57d7f..056c4583d9a202f2bdbaa306a3282f231089e3d5 100644 (file)
@@ -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