]> Kevux Git Server - fll/commitdiff
Update: add additional file functions, fix bug with file stat in f_directory
authorKevin Day <thekevinday@gmail.com>
Mon, 18 May 2020 02:49:01 +0000 (21:49 -0500)
committerKevin Day <thekevinday@gmail.com>
Mon, 18 May 2020 02:49:01 +0000 (21:49 -0500)
Add additional f_file functions, move commonly shared code into private f_file files.

The f_directory functions were incorrectly using sizeof().

build/level_0/settings
build/monolithic/settings
level_0/f_directory/c/directory.c
level_0/f_file/c/file.c
level_0/f_file/c/file.h
level_0/f_file/c/private-file.c [new file with mode: 0644]
level_0/f_file/c/private-file.h [new file with mode: 0644]
level_0/f_file/data/build/settings
level_2/fll_directory/c/directory.c

index 5756b24c2a4c262c6f08927f2687e0075548e64f..5f1c31de685378b2757d581b6e22ea7ed67a9788 100644 (file)
@@ -12,7 +12,7 @@ build_linker ar
 build_libraries -lc
 build_libraries_fll
 build_libraries_fll-level
-build_sources_library console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c memory.c path.c pipe.c print.c utf.c private-utf.c
+build_sources_library console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c memory.c path.c pipe.c print.c utf.c private-utf.c
 build_sources_program
 build_sources_headers color.h console.h conversion.h directory.h environment.h file.h fss.h memory.h path_fll.h path_filesystem.h path.h pipe.h print.h serialized.h socket.h status.h string.h type.h type_array.h utf.h
 build_shared yes
index ac2e5fc3e8d9ffe13011aae63b6ddcc67bcd22bc..2d894a683ea9dcd411319accd643f447cbf1d16c 100644 (file)
@@ -11,7 +11,7 @@ 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/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/memory.c level_0/path.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_library level_0/console.c level_0/conversion.c level_0/directory.c level_0/private-directory.c level_0/environment.c level_0/private-environment.c level_0/file.c level_0/private-file.c level_0/memory.c level_0/path.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/directory.h level_0/environment.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/path.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
index b8bc17997f484ab214d2cb9c61c3d6befb98fddf..f8cdd96737ebe8bfdff01a3e3848ec1512ea1eb9 100644 (file)
@@ -115,7 +115,7 @@ extern "C" {
   f_return_status f_directory_is(const f_string path) {
     struct stat file_stat;
 
-    memset(&file_stat, 0, sizeof(file_stat));
+    memset(&file_stat, 0, sizeof(struct stat));
 
     if (stat(path, &file_stat) < 0) {
       if (errno == ENAMETOOLONG || errno == EFAULT) {
@@ -153,7 +153,7 @@ extern "C" {
   f_return_status f_directory_is_at(const int file_id, const f_string path, const bool follow) {
     struct stat file_stat;
 
-    memset(&file_stat, 0, sizeof(file_stat));
+    memset(&file_stat, 0, sizeof(struct stat));
 
     if (fstatat(file_id, path, &file_stat, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) {
       if (errno == ENAMETOOLONG || errno == EFAULT) {
index 78f520b3c222dd73f19523c28de5163ca6acfef9..0dedbf3440eff63cb4a274db404aee33b8d75f17 100644 (file)
@@ -1,14 +1,5 @@
-/**
- * FLL - Level 0
- *
- * Project: File
- * API Version: 0.5
- * Licenses: lgplv2.1
- *
- * Provides structures and data types for a file I/O.
- * Provides operations for opening/closing files.
- */
 #include <level_0/file.h>
+#include "private-file.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -51,95 +42,145 @@ extern "C" {
   }
 #endif // _di_f_file_access_
 
-#ifndef _di_f_file_create_
-  f_return_status f_file_create(f_string path, const mode_t mode, const bool exclusive) {
-    int flags = O_CLOEXEC | O_CREAT | O_WRONLY;
+#ifndef _di_f_file_change_owner_
+  f_return_status f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid) {
+    return private_f_file_change_owner(path, uid, gid);
+  }
+#endif // _di_f_file_change_owner_
+
+#ifndef _di_f_file_copy_
+  f_return_status f_file_copy(const f_string source, const f_string destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive) {
+    #ifndef _di_level_0_parameter_checking_
+      if (size_block == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    f_status status = f_none;
+
+    status = private_f_file_create(destination, mode, exclusive);
+    if (f_status_is_error(status)) return status;
 
-    if (exclusive) {
-      flags |= O_EXCL;
+    f_file file_source = f_file_initialize;
+    f_file file_destination = f_file_initialize;
+
+    file_destination.mode = f_file_write_create;
+
+    status = private_f_file_open(&file_source, source);
+    if (f_status_is_error(status)) return status;
+
+    status = private_f_file_open(&file_destination, destination);
+    if (f_status_is_error(status)) {
+      private_f_file_close(&file_source);
+      return status;
     }
 
-    int result = open(path, flags, mode);
+    ssize_t size_read = 0;
+    ssize_t size_write = 0;
+    char *buffer[size_block];
 
-    if (result < 0) {
-      if (errno == EACCES) {
-        return f_status_set_error(f_access_denied);
-      }
-      else if (errno == EDQUOT) {
-        return f_status_set_error(f_filesystem_quota_blocks);
-      }
-      else if (errno == EEXIST) {
-        return f_status_set_error(f_file_found);
-      }
-      else if (errno == ENAMETOOLONG || errno == EFAULT) {
-        return f_status_set_error(f_invalid_name);
-      }
-      else if (errno == EFBIG || errno == EOVERFLOW) {
-        return f_status_set_error(f_number_overflow);
-      }
-      else if (errno == EINTR) {
-        return f_status_set_error(f_interrupted);
-      }
-      else if (errno == EINVAL) {
-        return f_status_set_error(f_invalid_parameter);
-      }
-      else if (errno == ELOOP) {
-        return f_status_set_error(f_loop);
-      }
-      else if (errno == ENFILE) {
-        return f_status_set_error(f_file_max_open);
-      }
-      else if (errno == ENOENT || errno == ENOTDIR) {
-        return f_status_set_error(f_invalid_directory);
-      }
-      else if (errno == ENOMEM) {
-        return f_status_set_error(f_out_of_memory);
-      }
-      else if (errno == ENOSPC) {
-        return f_status_set_error(f_filesystem_quota_reached);
-      }
-      else if (errno == EPERM) {
-        return f_status_set_error(f_prohibited);
-      }
-      else if (errno == EROFS) {
-        return f_status_set_error(f_read_only);
-      }
-      else if (errno == ETXTBSY) {
-        return f_status_set_error(f_busy);
+    memset(buffer, 0, size_block);
+
+    while ((size_read = read(file_source.id, buffer, size_block)) > 0) {
+      size_write = write(file_destination.id, buffer, size_read);
+
+      if (size_write < 0 || size_write != size_read) {
+        private_f_file_close(&file_destination);
+        private_f_file_close(&file_source);
+
+        return f_status_set_error(f_file_error_write);
       }
+    } // while
 
-      return f_status_set_error(f_failure);
-    }
+    private_f_file_close(&file_destination);
+    private_f_file_close(&file_source);
 
-    close(result);
+    if (size_read < 0) return f_status_set_error(f_file_error_read);
 
     return f_none;
   }
-#endif // _di_f_file_create_
+#endif // _di_f_file_copy_
 
-#ifndef _di_f_file_close_
-  f_return_status f_file_close(f_file *file) {
+#ifndef _di_f_file_clone_
+  f_return_status f_file_clone(const f_string source, const f_string destination, const f_number_unsigned size_block, const bool exclusive, const bool roles) {
     #ifndef _di_level_0_parameter_checking_
-      if (file == 0) return f_status_set_error(f_invalid_parameter);
+      if (size_block == 0) return f_status_set_error(f_invalid_parameter);
     #endif // _di_level_0_parameter_checking_
 
-    if (file->address == 0) return f_status_set_error(f_file_not_open);
+    f_status status = f_none;
+    struct stat source_stat;
+
+    memset(&source_stat, 0, sizeof(struct stat));
+
+    status = private_f_file_stat(source, &source_stat);
+    if (f_status_is_error(status)) return status;
+
+    status = private_f_file_create(destination, source_stat.st_mode, exclusive);
+    if (f_status_is_error(status)) return status;
+
+    // guarantee the file mode is updated (create does not set mode for existing files).
+    status = private_f_file_change_mode(destination, source_stat.st_mode);
+    if (f_status_is_error(status)) return status;
 
-    // if we were given a file descriptor as well, make sure to flush all changes to the disk that are not flushed by the 'fflush()' command
-    if (file->id) {
-      // make sure all unfinished data gets completed.
-      if (fsync(file->id) != 0) return f_status_set_error(f_file_error_synchronize);
+    if (roles) {
+      status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid);
+      if (f_status_is_error(status)) return status;
     }
 
-    if (fclose(file->address) == 0) {
-      file->address = 0;
-      return f_none;
+    f_file file_source = f_file_initialize;
+    f_file file_destination = f_file_initialize;
+
+    file_destination.mode = f_file_write_create;
+
+    status = private_f_file_open(&file_source, source);
+    if (f_status_is_error(status)) return status;
+
+    status = private_f_file_open(&file_destination, destination);
+    if (f_status_is_error(status)) {
+      private_f_file_close(&file_source);
+      return status;
     }
 
-    return f_status_set_error(f_file_error_close);
+    ssize_t size_read = 0;
+    ssize_t size_write = 0;
+    char *buffer[size_block];
+
+    memset(buffer, 0, size_block);
+
+    while ((size_read = read(file_source.id, buffer, size_block)) > 0) {
+      size_write = write(file_destination.id, buffer, size_read);
+
+      if (size_write < 0 || size_write != size_read) {
+        private_f_file_close(&file_destination);
+        private_f_file_close(&file_source);
+
+        return f_status_set_error(f_file_error_write);
+      }
+    } // while
+
+    private_f_file_close(&file_destination);
+    private_f_file_close(&file_source);
+
+    if (size_read < 0) return f_status_set_error(f_file_error_read);
+
+    return f_none;
+  }
+#endif // _di_f_file_clone_
+
+#ifndef _di_f_file_close_
+  f_return_status f_file_close(f_file *file) {
+    #ifndef _di_level_0_parameter_checking_
+      if (file == 0) return f_status_set_error(f_invalid_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_file_close(file);
   }
 #endif // _di_f_file_close_
 
+#ifndef _di_f_file_create_
+  f_return_status f_file_create(f_string path, const mode_t mode, const bool exclusive) {
+    return private_f_file_create(path, mode, exclusive);
+  }
+#endif // _di_f_file_create_
+
 #ifndef _di_f_file_exists_at_
   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_
@@ -202,7 +243,7 @@ extern "C" {
   f_return_status f_file_exists(const f_string path) {
     struct stat file_stat;
 
-    memset(&file_stat, 0, sizeof(file_stat));
+    memset(&file_stat, 0, sizeof(struct stat));
 
     if (stat(path, &file_stat) < 0) {
       if (errno == ENAMETOOLONG || errno == EFAULT) {
@@ -238,7 +279,7 @@ extern "C" {
   f_return_status f_file_is(const f_string path, const int type) {
     struct stat file_stat;
 
-    memset(&file_stat, 0, sizeof(file_stat));
+    memset(&file_stat, 0, sizeof(struct stat));
 
     if (stat(path, &file_stat) < 0) {
       if (errno == ENAMETOOLONG || errno == EFAULT) {
@@ -276,7 +317,7 @@ extern "C" {
   f_return_status f_file_is_at(const int file_id, const f_string path, const int type, const bool follow) {
     struct stat file_stat;
 
-    memset(&file_stat, 0, sizeof(file_stat));
+    memset(&file_stat, 0, sizeof(struct stat));
 
     if (fstatat(file_id, path, &file_stat, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) {
       if (errno == ENAMETOOLONG || errno == EFAULT) {
@@ -316,19 +357,7 @@ extern "C" {
       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(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);
-
-    file->id = fileno(file->address);
-
-    if (file->id == -1) return f_status_set_error(f_file_error_descriptor);
-
-    return f_none;
+    return private_f_file_open(file, path);
   }
 #endif // _di_f_file_open_
 
@@ -512,33 +541,7 @@ extern "C" {
 
 #ifndef _di_f_file_stat_
   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);
-      }
-      else if (errno == ENOMEM) {
-        return f_status_set_error(f_out_of_memory);
-      }
-      else if (errno == EOVERFLOW) {
-        return f_status_set_error(f_number_overflow);
-      }
-      else if (errno == ENOTDIR) {
-        return f_status_set_error(f_invalid_directory);
-      }
-      else if (errno == ENOENT) {
-        return f_status_set_error(f_file_not_found);
-      }
-      else if (errno == EACCES) {
-        return f_status_set_error(f_access_denied);
-      }
-      else if (errno == ELOOP) {
-        return f_status_set_error(f_loop);
-      }
-
-      return f_status_set_error(f_file_error_stat);
-    }
-
-    return f_none;
+    return private_f_file_stat(path, file_stat);
   }
 #endif // _di_f_file_stat_
 
index 49e82f3569b924df8619f7788e10aebec2af3120..05018e2f90bc57be43f64a3ece279116ecc96859 100644 (file)
@@ -40,7 +40,6 @@ extern "C" {
 
   #define f_file_default_read_size  8192 // default to 8k read sizes.
   #define f_file_default_write_size 8192 // default to 8k write sizes.
-  #define f_file_max_path_length    1024
 #endif // _di_f_file_types_
 
 /**
@@ -285,6 +284,34 @@ extern "C" {
 #endif // _di_f_macro_file_reset_position_
 
 /**
+ * Change owner and group of a given file at the specified path.
+ *
+ * @param path
+ *   The path file name.
+ * @param uid
+ *   The new user id to use.
+ * @param gid
+ *   The new group id to use.
+ *
+ * @return
+ *   f_true if file exists.
+ *   f_false if file does not exist.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *   f_invalid_name (with error bit) if the filename is too long.
+ *   f_out_of_memory (with error bit) if out of memory.
+ *   f_number_overflow (with error bit) on overflow error.
+ *   f_invalid_directory (with error bit) on invalid directory.
+ *   f_access_denied (with error bit) on access denied.
+ *   f_loop (with error bit) on loop error.
+ *   f_false (with error bit) on unknown/unhandled errors.
+ *
+ * @see chown()
+ */
+#ifndef _di_f_file_change_owner_
+  extern f_return_status f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid);
+#endif // _di_f_file_change_owner_
+
+/**
  * Check if a file can be accessed.
  *
  * @param path
@@ -309,6 +336,111 @@ extern "C" {
 #endif // _di_f_file_access_
 
 /**
+ * Copy a file.
+ *
+ * The paths must not contain NULL except for the terminating NULL.
+ * The paths must be NULL terminated.
+ *
+ * @param source
+ *   The path to the file to copy from.
+ * @param destination
+ *   The path to copy to.
+ * @param mode
+ *   The file mode assigned to the destination file.
+ * @param size_block
+ *   The default number of chunks to read at a time with each chunk being 1-byte.
+ *   Must be greater than 0.
+ * @param exclusive
+ *   If TRUE, will fail when file already exists.
+ *   If FALSE, will not fail if file already exists (existing file will be replaced).
+ *
+ * @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_loop (with error bit) on loop error.
+ *   f_file_found (with error bit) if a file was found while exclusive is TRUE.
+ *   f_out_of_memory (with error bit) if out of memory.
+ *   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 (mkdir()) error.
+ *   f_filesystem_quota_blocks (with error bit) if filesystem's disk blocks or inodes are exhausted.
+ *   f_filesystem_quota_reached (with error bit) quota reached of filesystem is out of space.
+ *   f_file_found (with error bit) of a directory aleady exists at the path.
+ *   f_invalid_name (with error bit) on path name error.
+ *   f_invalid_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   f_number_overflow (with error bit) on overflow error.
+ *   f_interrupted (with error bit) when program received an interrupt signal, halting create.
+ *   f_file_max_open (with error bit) when system-wide max open files is reached.
+ *   f_busy (with error bit) if filesystem is too busy to perforrm write.
+ *   f_file_error_read (with error bit) on file read error.
+ *   f_file_error_write (with error bit) on file write error.
+ *
+ * @see f_file_create()
+ * @see f_file_open()
+ * @see f_file_close()
+ * @see read()
+ */
+#ifndef _di_f_file_copy_
+  extern f_return_status f_file_copy(const f_string source, const f_string destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive);
+#endif // _di_f_file_copy_
+
+/**
+ * Copy a file, as well as its file mode and possibly the owner and group.
+ *
+ * The paths must not contain NULL except for the terminating NULL.
+ * The paths must be NULL terminated.
+ *
+ * @todo provide a return status for when owner/role cannot be assigned.
+ * This will be returned when complete so that caller can decide if this is an error or not.
+ *
+ * @param source
+ *   The path to the file to copy from.
+ * @param destination
+ *   The path to copy to.
+ * @param size_block
+ *   The default number of chunks to read at a time with each chunk being 1-byte.
+ *   Must be greater than 0.
+ * @param exclusive
+ *   If TRUE, will fail when file already exists.
+ *   If FALSE, will not fail if file already exists (existing file will be replaced).
+ * @param roles
+ *   If TRUE, will copy the owner and group ids.
+ *   If FALSE, will not copy the owner and group ids.
+ *   (In both cases the file mode is copied.)
+ *
+ * @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_loop (with error bit) on loop error.
+ *   f_file_found (with error bit) if a file was found while exclusive is TRUE.
+ *   f_out_of_memory (with error bit) if out of memory.
+ *   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 (mkdir()) error.
+ *   f_filesystem_quota_blocks (with error bit) if filesystem's disk blocks or inodes are exhausted.
+ *   f_filesystem_quota_reached (with error bit) quota reached of filesystem is out of space.
+ *   f_file_found (with error bit) of a directory aleady exists at the path.
+ *   f_invalid_name (with error bit) on path name error.
+ *   f_invalid_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   f_number_overflow (with error bit) on overflow error.
+ *   f_interrupted (with error bit) when program received an interrupt signal, halting create.
+ *   f_file_max_open (with error bit) when system-wide max open files is reached.
+ *   f_busy (with error bit) if filesystem is too busy to perforrm write.
+ *   f_file_error_read (with error bit) on file read error.
+ *   f_file_error_write (with error bit) on file write error.
+ *
+ * @see f_file_create()
+ * @see f_file_open()
+ * @see f_file_close()
+ * @see read()
+ */
+#ifndef _di_f_file_clone_
+  extern f_return_status f_file_clone(const f_string source, const f_string destination, const f_number_unsigned size_block, const bool exclusive, const bool roles);
+#endif // _di_f_file_clone_
+
+/**
  * Create a file based on the given path and file mode.
  *
  * The file will not be open after calling this.
@@ -542,6 +674,8 @@ extern "C" {
  *   f_file_not_open (with error bit) if file is not open.
  *   f_file_error_read (with error bit) if file read failed.
  *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see fread()
  */
 #ifndef _di_f_file_read_
   extern f_return_status f_file_read(f_file *file, f_string_dynamic *buffer);
diff --git a/level_0/f_file/c/private-file.c b/level_0/f_file/c/private-file.c
new file mode 100644 (file)
index 0000000..0526fe7
--- /dev/null
@@ -0,0 +1,220 @@
+#include <level_0/file.h>
+#include "private-file.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_)
+  f_return_status private_f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid) {
+    if (chown(path, uid, gid) < 0) {
+      if (errno == EACCES) {
+        return f_status_set_error(f_access_denied);
+      }
+      else if (errno == ENAMETOOLONG || errno == EFAULT) {
+        return f_status_set_error(f_invalid_name);
+      }
+      else if (errno == ELOOP) {
+        return f_status_set_error(f_loop);
+      }
+      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);
+      }
+      else if (errno == EIO) {
+        return f_status_set_error(f_error_input_output);
+      }
+
+      return f_status_set_error(f_failure);
+    }
+
+    return f_none;
+  }
+#endif // !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
+  f_return_status private_f_file_change_mode(const f_string path, const mode_t mode) {
+    if (chmod(path, mode) < 0) {
+      if (errno == EACCES) {
+        return f_status_set_error(f_access_denied);
+      }
+      else if (errno == ENAMETOOLONG || errno == EFAULT) {
+        return f_status_set_error(f_invalid_name);
+      }
+      else if (errno == ELOOP) {
+        return f_status_set_error(f_loop);
+      }
+      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);
+      }
+      else if (errno == EIO) {
+        return f_status_set_error(f_error_input_output);
+      }
+
+      return f_status_set_error(f_failure);
+    }
+
+    return f_none;
+  }
+#endif // !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_close_) || !defined(_di_f_file_copy_)
+  f_return_status private_f_file_close(f_file *file) {
+    if (file->address == 0) return f_status_set_error(f_file_not_open);
+
+    // if given a file descriptor, flush all changes to the disk that are not flushed by the 'fflush()' command.
+    if (file->id) {
+      if (fsync(file->id) != 0) return f_status_set_error(f_file_error_synchronize);
+    }
+
+    if (fclose(file->address) == 0) {
+      file->address = 0;
+      return f_none;
+    }
+
+    return f_status_set_error(f_file_error_close);
+  }
+#endif // !defined(_di_f_file_close_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
+  f_return_status private_f_file_create(f_string path, const mode_t mode, const bool exclusive) {
+    int flags = O_CLOEXEC | O_CREAT | O_WRONLY;
+
+    if (exclusive) {
+      flags |= O_EXCL;
+    }
+
+    int result = open(path, flags, mode);
+
+    if (result < 0) {
+      if (errno == EACCES) {
+        return f_status_set_error(f_access_denied);
+      }
+      else if (errno == EDQUOT) {
+        return f_status_set_error(f_filesystem_quota_blocks);
+      }
+      else if (errno == EEXIST) {
+        return f_status_set_error(f_file_found);
+      }
+      else if (errno == ENAMETOOLONG || errno == EFAULT) {
+        return f_status_set_error(f_invalid_name);
+      }
+      else if (errno == EFBIG || errno == EOVERFLOW) {
+        return f_status_set_error(f_number_overflow);
+      }
+      else if (errno == EINTR) {
+        return f_status_set_error(f_interrupted);
+      }
+      else if (errno == EINVAL) {
+        return f_status_set_error(f_invalid_parameter);
+      }
+      else if (errno == ELOOP) {
+        return f_status_set_error(f_loop);
+      }
+      else if (errno == ENFILE) {
+        return f_status_set_error(f_file_max_open);
+      }
+      else if (errno == ENOENT || errno == ENOTDIR) {
+        return f_status_set_error(f_invalid_directory);
+      }
+      else if (errno == ENOMEM) {
+        return f_status_set_error(f_out_of_memory);
+      }
+      else if (errno == ENOSPC) {
+        return f_status_set_error(f_filesystem_quota_reached);
+      }
+      else if (errno == EPERM) {
+        return f_status_set_error(f_prohibited);
+      }
+      else if (errno == EROFS) {
+        return f_status_set_error(f_read_only);
+      }
+      else if (errno == ETXTBSY) {
+        return f_status_set_error(f_busy);
+      }
+
+      return f_status_set_error(f_failure);
+    }
+
+    close(result);
+
+    return f_none;
+  }
+#endif // !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
+  f_return_status private_f_file_open(f_file *file, const f_string path) {
+    // 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(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);
+
+    file->id = fileno(file->address);
+
+    if (file->id == -1) return f_status_set_error(f_file_error_descriptor);
+
+    return f_none;
+  }
+#endif // !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
+
+#if !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
+  f_return_status private_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);
+      }
+      else if (errno == ENOMEM) {
+        return f_status_set_error(f_out_of_memory);
+      }
+      else if (errno == EOVERFLOW) {
+        return f_status_set_error(f_number_overflow);
+      }
+      else if (errno == ENOTDIR) {
+        return f_status_set_error(f_invalid_directory);
+      }
+      else if (errno == ENOENT) {
+        return f_status_set_error(f_file_not_found);
+      }
+      else if (errno == EACCES) {
+        return f_status_set_error(f_access_denied);
+      }
+      else if (errno == ELOOP) {
+        return f_status_set_error(f_loop);
+      }
+
+      return f_status_set_error(f_file_error_stat);
+    }
+
+    return f_none;
+  }
+#endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_file/c/private-file.h b/level_0/f_file/c/private-file.h
new file mode 100644 (file)
index 0000000..1c27926
--- /dev/null
@@ -0,0 +1,202 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: File
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides structures and data types for a file I/O.
+ * Provides operations for opening/closing files.
+ */
+#ifndef _PRIVATE_F_file_h
+#define _PRIVATE_F_file_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Private implementation of f_file_change_owner().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param path
+ *   The path file name.
+ * @param uid
+ *   The new user id to use.
+ * @param gid
+ *   The new group id to use.
+ *
+ * @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_invalid_name (with error bit) if the filename is too long.
+ *   f_loop (with error bit) on loop error.
+ *   f_file_not_found (with error bit) if file at path was not found.
+ *   f_out_of_memory (with error bit) if out of memory.
+ *   f_invalid_directory (with error bit) on invalid directory.
+ *   f_prohibited (with error bit) if filesystem does not allow for file changes.
+ *   f_read_only (with error bit) if file is read-only.
+ *   f_error_input_output (with error bit) on I/O error.
+ *   f_failure (with error bit) for any other (mkdir()) error.
+ *
+ * @see f_file_change_owner()
+ * @see chown()
+ */
+#if !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_)
+  extern f_return_status private_f_file_change_owner(const f_string path, const uid_t uid, const gid_t gid) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_change_mode().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param path
+ *   The path file name.
+ * @param mode
+ *   The new mode to use.
+ *
+ * @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_invalid_name (with error bit) if the filename is too long.
+ *   f_loop (with error bit) on loop error.
+ *   f_file_not_found (with error bit) if file at path was not found.
+ *   f_out_of_memory (with error bit) if out of memory.
+ *   f_invalid_directory (with error bit) on invalid directory.
+ *   f_prohibited (with error bit) if filesystem does not allow for file changes.
+ *   f_read_only (with error bit) if file is read-only.
+ *   f_error_input_output (with error bit) on I/O error.
+ *   f_failure (with error bit) for any other (mkdir()) error.
+ *
+ * @see f_file_change_mode()
+ * @see chmod()
+ */
+#if !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
+  extern f_return_status private_f_file_change_mode(const f_string path, const mode_t mode) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_create().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param path
+ *   Full path to the file (including entire filename).
+ * @param mode
+ *   The file mode.
+ * @param exclusive
+ *   If TRUE, will fail when file already exists.
+ *   If FALSE, will not fail if file already exists.
+ *
+ * @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_loop (with error bit) on loop error.
+ *   f_file_found (with error bit) if a file was found while exclusive is TRUE.
+ *   f_out_of_memory (with error bit) if out of memory.
+ *   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 (mkdir()) error.
+ *   f_filesystem_quota_blocks (with error bit) if filesystem's disk blocks or inodes are exhausted.
+ *   f_filesystem_quota_reached (with error bit) quota reached of filesystem is out of space.
+ *   f_file_found (with error bit) of a directory aleady exists at the path.
+ *   f_invalid_name (with error bit) on path name error.
+ *   f_invalid_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   f_number_overflow (with error bit) on overflow error.
+ *   f_interrupted (with error bit) when program received an interrupt signal, halting create.
+ *   f_file_max_open (with error bit) when system-wide max open files is reached.
+ *   f_busy (with error bit) if filesystem is too busy to perforrm write.
+ *
+ * @see f_file_create()
+ * @see open()
+ */
+#if !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
+  extern f_return_status private_f_file_create(f_string path, const mode_t mode, const bool exclusive) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_open().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param file
+ *   The data related to the file being opened.
+ *   This will be updated with the file descriptor and file address.
+ * @param path
+ *   The path file name.
+ *
+ * @return
+ *   f_none on success.
+ *   f_file_not_found (with error bit) if the file was not found.
+ *   f_file_error_open (with error bit) if the file is already open.
+ *   f_file_error_descriptor (with error bit) if unable to load the file descriptor (the file pointer may still be valid).
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_file_open()
+ * @see fopen()
+ */
+#if !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
+  extern f_return_status private_f_file_open(f_file *file, const f_string path) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_close().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param file
+ *   The file to close.
+ *
+ * @return
+ *   f_none on success.
+ *   f_file_not_open (with error bit) if the file is not open.
+ *   f_file_error_synchronize (with error bit) on fsync() failure.
+ *   f_file_error_close (with error bit) if fclose() failed.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_file_close()
+ * @see fsync()
+ * @see fclose()
+ */
+#if !defined(_di_f_file_close_) || !defined(_di_f_file_copy_)
+  extern f_return_status private_f_file_close(f_file *file) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_close_) || !defined(_di_f_file_copy_)
+
+/**
+ * Private implementation of f_file_close().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param file_name
+ *   The name of the file.
+ * @param file_stat
+ *   The statistics read.
+ *
+ * @return
+ *   f_none on success.
+ *   f_invalid_name (with error bit) if the name is somehow invalid.
+ *   f_out_of_memory (with error bit) if out of memory.
+ *   f_number_overflow (with error bit) on overflow error.
+ *   f_invalid_directory (with error bit) on invalid directory.
+ *   f_file_not_found (with error bit) if the file was not found.
+ *   f_access_denied (with error bit) if access to the file was denied.
+ *   f_loop (with error bit) if a loop occurred.
+ *   f_invalid_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_file_stat()
+ * @see stat()
+ */
+#if !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
+  extern f_return_status private_f_file_stat(const f_string file_name, struct stat *file_stat) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_F_file_h
index 3ab6c02efd495961743ba9c9acf0f02037c03700..2dba4caf88dbf7d546b82f7200a5036a11438166 100644 (file)
@@ -11,7 +11,7 @@ build_compiler gcc
 build_linker ar
 build_libraries -lc 
 build_libraries_fll
-build_sources_library file.c
+build_sources_library file.c private-file.c
 build_sources_program 
 build_sources_headers file.h
 build_sources_bash
index 6cf90b342390b40cd5f25e4f5c5017014dd5b581..caa0ae08a5dd8b0727f389d2331c2750411c7c76 100644 (file)
@@ -81,7 +81,7 @@ extern "C" {
         continue;
       }
 
-      memset(&file_stat, 0, sizeof(file_stat));
+      memset(&file_stat, 0, sizeof(struct stat));
 
       status = f_file_stat_at(parent_fd, entity[i]->d_name, &file_stat, 0);
       if (f_status_is_error(status)) break;