]> Kevux Git Server - fll/commitdiff
Progress: add more directory and file related functions, other changes
authorKevin Day <thekevinday@gmail.com>
Fri, 29 May 2020 00:23:59 +0000 (19:23 -0500)
committerKevin Day <thekevinday@gmail.com>
Fri, 29 May 2020 00:27:51 +0000 (19:27 -0500)
This was started with the intention of providing all of the *_at() functions.
However, the POSIX spec seems to fall short in many areas making this more difficult than this should be.
I partially rolled back some of the planned changes and this changeset is the result.

I have observed that the function return documentation needs to be updated, but this will be done at a later time.
There will need to be some intensive testing later on but for now I am committing and moving forward.

17 files changed:
level_0/f_directory/c/directory.c
level_0/f_directory/c/directory.h
level_0/f_file/c/file.c
level_0/f_file/c/file.h
level_0/f_file/c/private-file.c
level_0/f_file/c/private-file.h
level_0/f_status/c/status.h
level_1/fl_directory/c/directory.c
level_1/fl_directory/c/directory.h
level_1/fl_directory/c/private-directory.c
level_1/fl_directory/c/private-directory.h
level_1/fl_status/c/status.c
level_1/fl_status/c/status.h
level_2/fll_status/c/status.c
level_3/fss_basic_list_write/c/fss_basic_list_write.c
level_3/fss_basic_write/c/fss_basic_write.c
level_3/fss_extended_write/c/fss_extended_write.c

index dd36634555372ab18dd56bcf81b6673ccf90e4b0..e90d673b0e23cfedd3b41ac12ee52288a3adba3e 100644 (file)
@@ -43,7 +43,7 @@ extern "C" {
       if (errno == EEXIST) return F_status_set_error(F_file_found);
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
-      if (errno == EINVAL || errno == EBADF) return F_status_set_error(F_parameter);
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
       if (errno == ELOOP) return F_status_set_error(F_loop);
       if (errno == EMLINK) return F_status_set_error(F_directory_link_max);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
@@ -52,6 +52,7 @@ extern "C" {
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
 
       return F_status_set_error(F_failure);
     }
@@ -85,6 +86,32 @@ extern "C" {
   }
 #endif // _di_f_directory_exists_
 
+#ifndef _di_f_directory_exists_at_
+  f_return_status f_directory_exists_at(const int at_id, const f_string path, const int flag) {
+    struct stat file_stat;
+
+    memset(&file_stat, 0, sizeof(struct stat));
+
+    if (fstatat(at_id, path, &file_stat, flag) < 0) {
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+      if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
+      if (errno == ENOTDIR) return F_false;
+      if (errno == ENOENT) return F_file_found_not;
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+
+      return F_status_set_error(F_file_stat);
+    }
+
+    if ((file_stat.st_mode & S_IFMT) == S_IFDIR) return F_true;
+
+    return F_false;
+  }
+#endif // _di_f_directory_exists_at_
+
 #ifndef _di_f_directory_is_
   f_return_status f_directory_is(const f_string path) {
     struct stat file_stat;
@@ -111,12 +138,12 @@ extern "C" {
 #endif // _di_f_directory_is_
 
 #ifndef _di_f_directory_is_at_
-  f_return_status f_directory_is_at(const int file_id, const f_string path, const bool follow) {
+  f_return_status f_directory_is_at(const int at_id, const f_string path, const int flag) {
     struct stat file_stat;
 
     memset(&file_stat, 0, sizeof(struct stat));
 
-    if (fstatat(file_id, path, &file_stat, follow ? 0 : AT_SYMLINK_NOFOLLOW) < 0) {
+    if (fstatat(at_id, path, &file_stat, flag) < 0) {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
@@ -125,6 +152,7 @@ extern "C" {
       if (errno == ENOENT) return F_file_found_not;
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
 
       return F_status_set_error(F_file_stat);
     }
@@ -190,6 +218,82 @@ extern "C" {
   }
 #endif // _di_f_directory_list_
 
+#ifndef _di_f_directory_open_
+  f_return_status f_directory_open(const f_string path, const bool dereference, int *id) {
+    #ifndef _di_level_0_parameter_checking_
+      if (id == 0) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    int flag = f_directory_flag_directory | f_directory_flag_close_execute | f_directory_flag_path;
+
+    if (dereference) {
+      flag |= f_directory_flag_no_follow;
+    }
+
+    *id = open(path, flag);
+
+    if (*id < 0) {
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == EFBIG || errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
+      if (errno == EINTR) return F_status_set_error(F_interrupted);
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+      if (errno == ENOENT) return F_status_set_error(F_directory_found_not);
+      if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+      if (errno == ENOSPC) return F_status_set_error(F_space_not);
+      if (errno == EPERM) return F_status_set_error(F_prohibited);
+      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_open_
+
+#ifndef _di_f_directory_open_at_
+  f_return_status f_directory_open_at(const int at_id, const f_string path, const bool dereference, int *id) {
+    #ifndef _di_level_0_parameter_checking_
+      if (at_id <= 0) return F_status_set_error(F_parameter);
+      if (id == 0) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    int flag = f_directory_flag_directory | f_directory_flag_close_execute | f_directory_flag_path;
+
+    if (dereference) {
+      flag |= f_directory_flag_no_follow;
+    }
+
+    *id = openat(at_id, path, flag);
+
+    if (*id < 0) {
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == EFBIG || errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
+      if (errno == EINTR) return F_status_set_error(F_interrupted);
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+      if (errno == ENOENT) return F_status_set_error(F_directory_found_not);
+      if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_out);
+      if (errno == ENOSPC) return F_status_set_error(F_space_not);
+      if (errno == EPERM) return F_status_set_error(F_prohibited);
+      if (errno == EROFS) return F_status_set_error(F_read_only);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // _di_f_directory_open_at_
+
 #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_
index 8b84d43546502edafcefd63efab010cc7b4b4d84..1a4075a0f701fd7a8d61de4135a8fbc37fefa294 100644 (file)
@@ -41,18 +41,59 @@ extern "C" {
 #endif
 
 /**
+ * Directory AT_* define related functionality.
+ */
+#ifndef _di_f_directory_at_
+  #define f_directory_at_current_working    -100
+  #define f_directory_at_symlink_follow     0x400
+  #define f_directory_at_symlink_follow_no  0x100
+  #define f_directory_at_remove_directory   0x200
+  #define f_directory_at_automount_no       0x800
+  #define f_directory_at_path_empty         0x1000
+  #define f_directory_at_statx_sync_type    0x6000
+  #define f_directory_at_statx_sync_as_stat 0x0000
+  #define f_directory_at_statx_sync_force   0x2000
+  #define f_directory_at_statx_sync_no      0x4000
+#endif // _di_f_directory_at_
+
+/**
+ * Directory flag related functionality.
+ */
+#ifndef _di_f_directory_flag_
+
+  // directory open flags
+  #define f_directory_flag_append             O_APPEND
+  #define f_directory_flag_asynchronous       O_ASYNC
+  #define f_directory_flag_create             O_CREAT
+  #define f_directory_flag_close_execute      O_CLOEXEC
+  #define f_directory_flag_direct             O_DIRECT
+  #define f_directory_flag_directory          O_DIRECTORY
+  #define f_directory_flag_exclusive          O_EXCL
+  #define f_directory_flag_large_file         O_LARGEFILE
+  #define f_directory_flag_no_access_time     O_NOATIME
+  #define f_directory_flag_no_follow          O_NOFOLLOW
+  #define f_directory_flag_no_tty             O_NOCTTY
+  #define f_directory_flag_non_blocking       O_NONBLOCK
+  #define f_directory_flag_path               010000000
+  #define f_directory_flag_read_only          O_RDONLY
+  #define f_directory_flag_read_write         O_RDWR
+  #define f_directory_flag_synchronous        O_SYNC
+  #define f_directory_flag_synchronous_direct O_DSYNC
+  #define f_directory_flag_temporary          O_TMPFILE
+  #define f_directory_flag_truncate           O_TRUNC
+  #define f_directory_flag_write_only         O_WRONLY
+#endif // _di_f_directory_flag_
+
+/**
  * Provide limitations and related defines.
  *
- * The name max 255 because the directory name size is 256.
- * The last 1 is for the NULL character.
- *
  * The directory max descriptors is more of a default than a rule.
  * This is generally used for nftw() recursive operations to reduce the number of open file descriptors during recursion.
  */
 #ifndef _di_f_directory_limitations_
   #define f_directory_default_allocation_step f_memory_default_allocation_step
 
-  #define f_directory_name_max        255
+  #define f_directory_name_max        NAME_MAX
   #define f_directory_descriptors_max 255
 #endif // _di_f_directory_limitations_
 
@@ -91,7 +132,7 @@ extern "C" {
  * Create a directory at the given path within the directories specified by the file descriptor.
  *
  * @param at_id
- *   The file descriptor in which the directory will be created within.
+ *   The parent directory, as an open directory file descriptor, in which path is relative to.
  * @param path
  *   The path file name.
  * @param mode
@@ -113,8 +154,9 @@ extern "C" {
  *   F_name (with error bit) on path name error.
  *   F_directory_link_max (with error bit) max links limit reached or exceeded.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
- * @see mkdir()
+ * @see mkdirat()
  */
 #ifndef _di_f_directory_create_at_
   extern f_return_status f_directory_create_at(const int at_id, const f_string path, const mode_t mode);
@@ -137,13 +179,41 @@ extern "C" {
  *   F_loop (with error bit) if a loop occurred.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
- * @see fstat()
+ * @see stat()
  */
 #ifndef _di_f_directory_exists_
   extern f_return_status f_directory_exists(const f_string path);
 #endif // _di_f_directory_exists_
 
 /**
+ * Identify whether or not a file exists at the given path and if that file is a directory or a symlink to a directory.
+ *
+ * @param at_id
+ *   The parent directory, as an open directory file descriptor, in which path is relative to.
+ * @param path
+ *   The path file name.
+ * @param flag
+ *   Any valid flag, such as f_directory_at_path_empty, f_directory_at_automount_no, or f_directory_at_symlink_follow_no.
+ *
+ * @return
+ *   F_true if path was found and path is a directory (or a symlink to a directory).
+ *   F_false if path was found and path is not a directory.
+ *   F_file_found_not if the path was not found.
+ *   F_name (with error bit) if the name is somehow invalid.
+ *   F_memory_out (with error bit) if out of memory.
+ *   F_number_overflow (with error bit) on overflow error.
+ *   F_access_denied (with error bit) if access to the file was denied.
+ *   F_loop (with error bit) if a loop occurred.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
+ *
+ * @see fstatat()
+ */
+#ifndef _di_f_directory_exists_at_
+  extern f_return_status f_directory_exists_at(const int at_id, const f_string path, const int flag);
+#endif // _di_f_directory_exists_at_
+
+/**
  * Identify whether or not a file exists at the given path and if that file is a directory.
  *
  * @param path
@@ -160,7 +230,7 @@ extern "C" {
  *   F_loop (with error bit) if a loop occurred.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
- * @see fstat()
+ * @see stat()
  */
 #ifndef _di_f_directory_is_
   extern f_return_status f_directory_is(const f_string path);
@@ -169,13 +239,12 @@ extern "C" {
 /**
  * Identify whether or not a file exists at the given path within the parent directory and if that file is a directory.
  *
- * @param file_id
- *   The file descriptor representing the parent directory to search within.
+ * @param at_id
+ *   The parent directory, as an open directory file descriptor, in which path is relative to.
  * @param path
  *   The path file name.
- * @param follow
- *   Set to TRUE to follow symbolic links when determining if path is a file.
- *   Set to FALSE to not follow.
+ * @param flag
+ *   Any valid flag, such as f_directory_at_path_empty, f_directory_at_automount_no, or f_directory_at_symlink_follow_no.
  *
  * @return
  *   F_true if path was found and path is a directory.
@@ -187,11 +256,12 @@ extern "C" {
  *   F_access_denied (with error bit) if access to the file was denied.
  *   F_loop (with error bit) if a loop occurred.
  *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
  * @see fstatat()
  */
 #ifndef _di_f_directory_is_at_
-  extern f_return_status f_directory_is_at(const int file_id, const f_string path, const bool follow);
+  extern f_return_status f_directory_is_at(const int at_id, const f_string path, const int flag);
 #endif // _di_f_directory_is_at_
 
 /**
@@ -227,6 +297,58 @@ extern "C" {
 #endif // _di_f_directory_list_
 
 /**
+ * Open the directory specified by path.
+ *
+ * This opens with O_PATH and O_CLOEXEC.
+ *
+ * @param path
+ *   The path file name.
+ * @param dereference
+ *   Set to TRUE to dereferenc symlinks (often is what is desired).
+ *   Set to FALSE to operate on the symlink itself.
+ * @param id
+ *   The file descriptor.
+ *   This is updated with the result of open() or openat().
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) if failed to read directory information.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see open()
+ */
+#ifndef _di_f_directory_open_
+  extern f_return_status private_f_directory_open(const f_string path, const bool dereference, int *id) f_gcc_attribute_visibility_internal;
+#endif // _di_f_directory_open_
+
+/**
+ * Open the directory specified by path.
+ *
+ * This opens with O_PATH and O_CLOEXEC.
+ *
+ * @param at_id
+ *   The parent directory, as an open directory file descriptor, in which path is relative to.
+ * @param path
+ *   The path file name.
+ * @param dereference
+ *   Set to TRUE to dereferenc symlinks (often is what is desired).
+ *   Set to FALSE to operate on the symlink itself.
+ * @param id
+ *   The file descriptor.
+ *   This is updated with the result of open() or openat().
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) if failed to read directory information.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see openat()
+ */
+#ifndef _di_f_directory_open_at_
+  extern f_return_status private_f_directory_open_at(const int at_id, const f_string path, const bool dereference, int *id) f_gcc_attribute_visibility_internal;
+#endif // _di_f_directory_open_at_
+
+/**
  * Remove a directory and possibly its contents.
  *
  * @param path
index c60e7dab206de0c7ac4985d022b851a45b5485cb..dfb1678a2dd38d563264cd887e7976f297340e91 100644 (file)
@@ -31,23 +31,93 @@ extern "C" {
 #endif // _di_f_file_change_mode_
 
 #ifndef _di_f_file_change_mode_at_
-  f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode, const int flags) {
-    return private_f_file_change_mode_at(at_id, path, mode, flags);
+  f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode) {
+    return private_f_file_change_mode_at(at_id, path, mode);
   }
 #endif // _di_f_file_change_mode_at_
 
 #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, const bool dereference) {
+    #ifndef _di_level_0_parameter_checking_
+      if (uid < 0 && gid < 0) return F_status_set_error(F_parameter);
+      if (uid < -1 || gid < -1) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
     return private_f_file_change_owner(path, uid, gid, dereference);
   }
 #endif // _di_f_file_change_owner_
 
 #ifndef _di_f_file_change_owner_at_
-  f_return_status f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flags) {
-    return private_f_file_change_owner_at(at_id, path, uid, gid, flags);
+  f_return_status f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) {
+    #ifndef _di_level_0_parameter_checking_
+      if (uid < 0 && gid < 0) return F_status_set_error(F_parameter);
+      if (uid < -1 || gid < -1) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_file_change_owner_at(at_id, path, uid, gid, flag);
   }
 #endif // _di_f_file_change_owner_at_
 
+#ifndef _di_f_file_clone_
+  f_return_status f_file_clone(const f_string source, const f_string destination, const bool role, const f_number_unsigned size_block, const bool exclusive) {
+    f_status status = F_none;
+    struct stat source_stat;
+
+    memset(&source_stat, 0, sizeof(struct stat));
+
+    status = private_f_file_stat(source, F_false, &source_stat);
+    if (F_status_is_error(status)) return status;
+
+    if (f_macro_file_type_is_regular(source_stat.st_mode)) {
+      status = private_f_file_create(destination, source_stat.st_mode, exclusive);
+      if (F_status_is_error(status)) return status;
+
+      if (!exclusive) {
+        status = private_f_file_change_mode(destination, source_stat.st_mode);
+        if (F_status_is_error(status)) return status;
+      }
+
+      if (role) {
+        status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_false);
+        if (F_status_is_error(status)) return status;
+      }
+
+      return private_f_file_copy_content(source, destination, size_block == 0 ? f_file_default_read_size : size_block);
+    }
+    else if (f_macro_file_type_is_link(source_stat.st_mode)) {
+      status = private_f_file_link(destination, source);
+      if (F_status_set_fine(status) == F_file_found) {
+        if (exclusive) return status;
+      }
+      else if (F_status_is_error(status)) {
+        return status;
+      }
+
+      status = private_f_file_change_mode(destination, source_stat.st_mode);
+      if (F_status_is_error(status)) return status;
+
+      if (role) {
+        status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_false);
+        if (F_status_is_error(status)) return status;
+      }
+
+      return F_none;
+    }
+
+    return F_unsupported;
+  }
+#endif // _di_f_file_clone_
+
+#ifndef _di_f_file_close_
+  f_return_status f_file_close(int *id) {
+    #ifndef _di_level_0_parameter_checking_
+      if (id == 0) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
+    return private_f_file_close(id);
+  }
+#endif // _di_f_file_close_
+
 #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) {
     f_status status = F_none;
@@ -154,66 +224,6 @@ extern "C" {
   }
 #endif // _di_f_file_copy_
 
-#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) {
-    f_status status = F_none;
-    struct stat source_stat;
-
-    memset(&source_stat, 0, sizeof(struct stat));
-
-    status = private_f_file_stat(source, F_false, &source_stat);
-    if (F_status_is_error(status)) return status;
-
-    if (f_macro_file_type_is_regular(source_stat.st_mode)) {
-      status = private_f_file_create(destination, source_stat.st_mode, exclusive);
-      if (F_status_is_error(status)) return status;
-
-      if (!exclusive) {
-        status = private_f_file_change_mode(destination, source_stat.st_mode);
-        if (F_status_is_error(status)) return status;
-      }
-
-      if (roles) {
-        status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_false);
-        if (F_status_is_error(status)) return status;
-      }
-
-      return private_f_file_copy_content(source, destination, size_block == 0 ? f_file_default_read_size : size_block);
-    }
-    else if (f_macro_file_type_is_link(source_stat.st_mode)) {
-      status = private_f_file_link(destination, source);
-      if (F_status_set_fine(status) == F_file_found) {
-        if (exclusive) return status;
-      }
-      else if (F_status_is_error(status)) {
-        return status;
-      }
-
-      status = private_f_file_change_mode(destination, source_stat.st_mode);
-      if (F_status_is_error(status)) return status;
-
-      if (roles) {
-        status = private_f_file_change_owner(destination, source_stat.st_uid, source_stat.st_gid, F_false);
-        if (F_status_is_error(status)) return status;
-      }
-
-      return F_none;
-    }
-
-    return F_unsupported;
-  }
-#endif // _di_f_file_clone_
-
-#ifndef _di_f_file_close_
-  f_return_status f_file_close(int *id) {
-    #ifndef _di_level_0_parameter_checking_
-      if (id == 0) return F_status_set_error(F_parameter);
-    #endif // _di_level_0_parameter_checking_
-
-    return private_f_file_close(id);
-  }
-#endif // _di_f_file_close_
-
 #ifndef _di_f_file_create_
   f_return_status f_file_create(const f_string path, const mode_t mode, const bool exclusive) {
     return private_f_file_create(path, mode, exclusive);
@@ -320,6 +330,7 @@ extern "C" {
       if (errno == ENOENT) return F_file_found_not;
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
 
       return F_status_set_error(F_file_stat);
     }
@@ -375,9 +386,9 @@ extern "C" {
 #endif // _di_f_file_link_hard_
 
 #ifndef _di_f_file_link_hard_at_
-  f_return_status f_file_link_hard_at(const int at_id_target, const int at_id_point, const f_string target, const f_string point, const int flags) {
+  f_return_status f_file_link_hard_at(const int at_id_target, const int at_id_point, const f_string target, const f_string point, const int flag) {
 
-    if (linkat(at_id_target, target, at_id_point, point, flags) < 0) {
+    if (linkat(at_id_target, target, at_id_point, point, flag) < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
       if (errno == EEXIST) return F_status_set_error(F_file_found);
@@ -389,7 +400,7 @@ extern "C" {
       if (errno == ELOOP) return F_status_set_error(F_loop);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
@@ -465,6 +476,7 @@ extern "C" {
       if (errno == ENOENT) return F_file_found_not;
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
 
       return F_status_set_error(F_file_stat);
     }
@@ -681,9 +693,9 @@ extern "C" {
 #endif // _di_f_file_remove_
 
 #ifndef _di_f_file_remove_at_
-  f_return_status f_file_remove_at(const int at_id, const f_string path, const int flags) {
+  f_return_status f_file_remove_at(const int at_id, const f_string path, const int flag) {
 
-    if (unlinkat(at_id, path, flags) < 0) {
+    if (unlinkat(at_id, path, flag) < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == EBUSY) return F_status_set_error(F_busy);
       if (errno == EIO) return F_status_set_error(F_input_output);
@@ -696,6 +708,7 @@ extern "C" {
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
 
       return F_status_set_error(F_failure);
     }
@@ -800,13 +813,13 @@ extern "C" {
 #endif // _di_f_file_stat_
 
 #ifndef _di_f_file_stat_at_
-  f_return_status f_file_stat_at(const int at_id, const f_string path, const int flags, struct stat *file_stat) {
+  f_return_status f_file_stat_at(const int at_id, const f_string path, const int flag, struct stat *file_stat) {
     #ifndef _di_level_0_parameter_checking_
       if (at_id <= 0) return F_status_set_error(F_parameter);
       if (file_stat == 0) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
-    return private_f_file_stat_at(at_id, path, flags, file_stat);
+    return private_f_file_stat_at(at_id, path, flag, file_stat);
   }
 #endif // _di_f_file_stat_at_
 
index 87914dc75cdc86ad394b185fcafddee4271b2d40..b18c04a09119687ce5e77cbf6c18d90d3e5e0f4a 100644 (file)
@@ -97,25 +97,41 @@ extern "C" {
  * Commonly used file related properties.
  *
  * id: File descriptor.
- * flags: Flags used for opening the file.
+ * flag: Flags used for opening the file.
  * size_read: The default number of 1-byte characters to read at a time and is often used for the read buffer size.
  * size_write: The default number of 1-byte characters to read at a time and is often used for the write buffer size.
  */
 #ifndef _di_f_file_
   typedef struct {
     int    id;
-    int    flags;
+    int    flag;
     size_t size_read;
     size_t size_write;
   } f_file;
 
-  #define f_file_initialize { 0, O_RDONLY, f_file_default_read_size, f_file_default_write_size }
+  #define f_file_initialize { 0, f_file_flag_read_only, f_file_default_read_size, f_file_default_write_size }
 #endif // _di_f_file_
 
 /**
- * File mode relation functionality.
+ * File AT_* define related functionality.
  */
-#ifndef _di_f_file_modes_
+#ifndef _di_f_file_at_
+  #define f_file_at_current_working    -100
+  #define f_file_at_symlink_follow     0x400
+  #define f_file_at_symlink_follow_no  0x100
+  #define f_file_at_remove_directory   0x200
+  #define f_file_at_automount_no       0x800
+  #define f_file_at_path_empty         0x1000
+  #define f_file_at_statx_sync_type    0x6000
+  #define f_file_at_statx_sync_as_stat 0x0000
+  #define f_file_at_statx_sync_force   0x2000
+  #define f_file_at_statx_sync_no      0x4000
+#endif // _di_f_file_at_
+
+/**
+ * File flag related functionality.
+ */
+#ifndef _di_f_file_flag_
 
   // file open flags
   #define f_file_flag_append             O_APPEND
@@ -130,7 +146,7 @@ extern "C" {
   #define f_file_flag_no_follow          O_NOFOLLOW
   #define f_file_flag_no_tty             O_NOCTTY
   #define f_file_flag_non_blocking       O_NONBLOCK
-  #define f_file_flag_path               O_PATH
+  #define f_file_flag_path               010000000
   #define f_file_flag_read_only          O_RDONLY
   #define f_file_flag_read_write         O_RDWR
   #define f_file_flag_synchronous        O_SYNC
@@ -213,6 +229,12 @@ extern "C" {
   #define f_file_flag_large_async_create_new_ro (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_RDONLY)
   #define f_file_flag_large_async_create_new_wo (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_WRONLY)
   #define f_file_flag_large_async_create_new_rw (O_LARGEFILE | O_ASYNC | O_CREAT | O_EXCL | O_RDRW)
+#endif // _di_f_file_flag_
+
+/**
+ * File mode related functionality.
+ */
+#ifndef _di_f_file_mode_
 
   // file permission modes.
   #define f_file_mode_owner_rwx S_IRWXU
@@ -257,7 +279,7 @@ extern "C" {
   #define f_file_mode_user_file      (f_file_mode_owner_rw | f_file_mode_group_rw)
   #define f_file_mode_user_program   (f_file_mode_owner_rx | f_file_mode_group_rx)
   #define f_file_mode_user_protected (f_file_mode_owner_r | f_file_mode_group_r)
-#endif // _di_f_file_modes_
+#endif // _di_f_file_mode_
 
 /**
  * Check if a file can be accessed.
@@ -326,10 +348,6 @@ extern "C" {
  *   The path file name.
  * @param mode
  *   The new mode to use.
- * @param flags
- *   Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
- *   Warning: chmod on a symolic link is currently not supported in POSIX.
- *   Therefore AT_SYMLINK_NO_FOLLOW does nothing at this time and is assumed to always be TRUE.
  *
  * @return
  *   F_none on success.
@@ -345,10 +363,10 @@ extern "C" {
  *   F_input_output (with error bit) on I/O error.
  *   F_failure (with error bit) for any other (mkdir()) error.
  *
- * @see chmod()
+ * @see fchmodat()
  */
 #ifndef _di_f_file_change_mode_at_
-  extern f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode, const int flags);
+  extern f_return_status f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode);
 #endif // _di_f_file_change_mode_at_
 
 /**
@@ -365,18 +383,23 @@ extern "C" {
  *   Set to FALSE to operate on the symlink itself.
  *
  * @return
- *   F_true if file exists.
- *   F_false if file does not exist.
+ *   F_none on success.
  *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_access_denied (with error bit) on access denied.
  *   F_name (with error bit) if the filename is too long.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_loop (with error bit) on loop error.
+ *   F_file_found_not (with error bit) if file at path was not found.
  *   F_memory_out (with error bit) if out of memory.
- *   F_number_overflow (with error bit) on overflow error.
  *   F_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.
+ *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
+ *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_failure (with error bit) for any other (chown() or lchown()) error.
  *
  * @see chown()
+ * @see lchown()
  */
 #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, const bool dereference);
@@ -393,29 +416,34 @@ extern "C" {
  *   The new user id to use.
  * @param gid
  *   The new group id to use.
- * @param flags
- *   Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
+ * @param flag
+ *   Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no.
  *
  * @return
- *   F_true if file exists.
- *   F_false if file does not exist.
+ *   F_none on success.
  *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_access_denied (with error bit) on access denied.
  *   F_name (with error bit) if the filename is too long.
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_loop (with error bit) on loop error.
+ *   F_file_found_not (with error bit) if file at path was not found.
  *   F_memory_out (with error bit) if out of memory.
- *   F_number_overflow (with error bit) on overflow error.
  *   F_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.
+ *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
+ *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
+ *   F_read_only (with error bit) if file is read-only.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
+ *   F_failure (with error bit) for any other (chown() or lchown()) error.
  *
- * @see chown()
+ * @see fchownat()
  */
 #ifndef _di_f_file_change_owner_at_
-  extern f_return_status f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flags);
+  extern f_return_status f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag);
 #endif // _di_f_file_change_owner_at_
 
 /**
- * Copy a file.
+ * 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.
@@ -424,15 +452,17 @@ extern "C" {
  *
  * This does not copy unknown file types.
  *
- * This does not set mode based on umask(), be sure to apply umask if so desired.
- * (such as: mode & ~mask).
+ * @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 mode
- *   The file mode assigned to the destination file.
+ * @param role
+ *   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.)
  * @param size_block
  *   The default number of chunks to read at a time with each chunk being 1-byte.
  *   Set to 0 to use default block read size.
@@ -463,12 +493,37 @@ extern "C" {
  *   F_file_read (with error bit) on file read error.
  *   F_file_write (with error bit) on file write error.
  */
-#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_
+#ifndef _di_f_file_clone_
+  extern f_return_status f_file_clone(const f_string source, const f_string destination, const bool role, const f_number_unsigned size_block, const bool exclusive);
+#endif // _di_f_file_clone_
 
 /**
- * Copy a file, as well as its file mode and possibly the owner and group.
+ * Close an open file.
+ *
+ * Will flush before closing.
+ *
+ * @param id
+ *   The file descriptor.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_file_descriptor (with error bit) if file descriptor is invalid.
+ *   F_interrupted (with error bit) if interrupt was received.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted.
+ *   F_space_not (with error bit) if filesystem is out of space (or filesystem quota is reached).
+ *   F_file_synchronize (with error bit) on flush failure.
+ *   F_file_close (with error bit) if fclose() failed for any other reason.
+ *
+ * @see fclose()
+ */
+#ifndef _di_f_file_close_
+  extern f_return_status f_file_close(int *id);
+#endif // _di_f_file_close_
+
+/**
+ * Copy a file.
  *
  * The paths must not contain NULL except for the terminating NULL.
  * The paths must be NULL terminated.
@@ -477,23 +532,21 @@ extern "C" {
  *
  * This does not copy unknown file types.
  *
- * @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.
+ * This does not set mode based on umask(), be sure to apply umask if so desired.
+ * (such as: mode & ~mask).
  *
  * @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.
  *   Set to 0 to use default block read size.
  * @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.
@@ -518,34 +571,9 @@ extern "C" {
  *   F_file_read (with error bit) on file read error.
  *   F_file_write (with error bit) on file write error.
  */
-#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_
-
-/**
- * Close an open file.
- *
- * Will flush before closing.
- *
- * @param id
- *   The file descriptor.
- *
- * @return
- *   F_none on success.
- *   F_parameter (with error bit) if a parameter is invalid.
- *   F_file_descriptor (with error bit) if file descriptor is invalid.
- *   F_interrupted (with error bit) if interrupt was received.
- *   F_input_output (with error bit) on I/O error.
- *   F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted.
- *   F_space_not (with error bit) if filesystem is out of space (or filesystem quota is reached).
- *   F_file_synchronize (with error bit) on flush failure.
- *   F_file_close (with error bit) if fclose() failed for any other reason.
- *
- * @see fclose()
- */
-#ifndef _di_f_file_close_
-  extern f_return_status f_file_close(int *id);
-#endif // _di_f_file_close_
+#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_
 
 /**
  * Create a file based on the given path and file mode.
@@ -699,7 +727,7 @@ extern "C" {
  *   F_name (with error bit) on path name error.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
  *   F_unsupported (with error bit) for unsupported file types.
- *   F_file_descriptor (with error bit) for bad file descriptor.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
  * @see makedev()
  * @see mknodat()
@@ -763,7 +791,7 @@ extern "C" {
  *   F_name (with error bit) on path name error.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
  *   F_unsupported (with error bit) for unsupported file types.
- *   F_file_descriptor (with error bit) for bad file descriptor.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
  * @see mkfifoat()
  */
@@ -832,7 +860,7 @@ extern "C" {
  *   F_name (with error bit) on path name error.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
  *   F_unsupported (with error bit) for unsupported file types.
- *   F_file_descriptor (with error bit) for bad file descriptor.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
  * @see mknodat()
  */
@@ -876,8 +904,8 @@ extern "C" {
  *   The parent directory, as an open directory file descriptor, in which path is relative to.
  * @param path
  *   The path file name.
- * @param flags
- *   Additional flags to pass, such as AT_EACCESS or AT_SYMLINK_NOFOLLOW.
+ * @param flag
+ *   Additional flag to pass, such as AT_EACCESS or AT_SYMLINK_NOFOLLOW.
  *
  * @return
  *   F_true if file exists.
@@ -1045,7 +1073,7 @@ extern "C" {
  *   F_prohibited (with error bit) if filesystem does not allow for creating or linking.
  *   F_read_only (with error bit) if filesystem is read-only.
  *   F_busy (with error bit) if filesystem is too busy to perforrm write.
- *   F_file_descriptor (with error bit) if file descriptor is invalid.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *   F_failure (with error bit) for any other (symlinkat()) error.
  *
  * @see symlinkat()
@@ -1102,8 +1130,8 @@ extern "C" {
  *   A path that the link points to.
  * @param point
  *   A path to the link that does the pointing.
- * @param flags
- *   Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
+ * @param flag
+ *   Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no.
  *
  * @return
  *   F_none on success.
@@ -1122,13 +1150,13 @@ extern "C" {
  *   F_prohibited (with error bit) if filesystem does not allow for creating or linking.
  *   F_read_only (with error bit) if filesystem is read-only.
  *   F_busy (with error bit) if filesystem is too busy to perforrm write.
- *   F_file_descriptor (with error bit) if file descriptor is invalid.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *   F_failure (with error bit) for any other (linkat()) error.
  *
  * @see linkat()
  */
 #ifndef _di_f_file_link_hard_at_
-  extern f_return_status f_file_link_hard_at(const int at_id_target, const int at_id_point, const f_string target, const f_string point, const int flags);
+  extern f_return_status f_file_link_hard_at(const int at_id_target, const int at_id_point, const f_string target, const f_string point, const int flag);
 #endif // _di_f_file_link_hard_at_
 
 /**
@@ -1193,7 +1221,7 @@ extern "C" {
  *   F_file_found_not (with error bit) if the file at path was not found.
  *   F_memory_out (with error bit) if out of memory.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
- *   F_file_descriptor (with error bit) if file descriptor is invalid.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *   F_failure (with error bit) for any other (readlinkat()) error.
  *
  * @see readlinkat()
@@ -1249,7 +1277,7 @@ extern "C" {
  *   F_none on success.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_file_open (with error bit) if the file is already open.
- *   F_file_descriptor (with error bit) if unable to load the file descriptor (the file pointer may still be valid).
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
  * @see openat()
@@ -1387,8 +1415,8 @@ extern "C" {
  *   The parent directory, as an open directory file descriptor, in which path is relative to.
  * @param path
  *   The path file name.
- * @param flags
- *   Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
+ * @param flag
+ *   Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no.
  *
  * @return
  *   F_none on success.
@@ -1409,7 +1437,7 @@ extern "C" {
  * @see unlinkat()
  */
 #ifndef _di_f_file_remove_at_
-  extern f_return_status f_file_remove_at(const int at_id, const f_string path, const int flags);
+  extern f_return_status f_file_remove_at(const int at_id, const f_string path, const int flag);
 #endif // _di_f_file_remove_at_
 
 /**
@@ -1558,8 +1586,8 @@ extern "C" {
  *   The parent directory, as an open directory file descriptor, in which path is relative to.
  * @param path
  *   The path to the file.
- * @param flags
- *   Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
+ * @param flag
+ *   Any valid flag, such as f_file_at_path_empty, f_file_at_automount_no, or f_file_at_symlink_follow_no.
  * @param file_stat
  *   The statistics read.
  *
@@ -1577,7 +1605,7 @@ extern "C" {
  * @see fstatat()
  */
 #ifndef _di_f_file_stat_at_
-  extern f_return_status f_file_stat_at(const int at_id, const f_string path, const int flags, struct stat *file_stat);
+  extern f_return_status f_file_stat_at(const int at_id, const f_string path, const int flag, struct stat *file_stat);
 #endif // _di_f_file_stat_at_
 
 /**
index 493089de42c3c32e6b341f2724097bf31ac02c76..482610b0a8e3a31fcab51e721c2f7a1cfa12863c 100644 (file)
@@ -28,9 +28,9 @@ extern "C" {
 #endif // !defined(_di_f_file_change_mode_) || !defined(_di_f_file_copy_)
 
 #if !defined(_di_f_file_change_mode_at_) || !defined(_di_f_file_copy_at_)
-  f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode, const int flags) {
+  f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode) {
 
-    if (fchmodat(at_id, path, mode, flags) < 0) {
+    if (fchmodat(at_id, path, mode, 0) < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
@@ -38,7 +38,7 @@ extern "C" {
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
       if (errno == EIO) return F_status_set_error(F_input_output);
@@ -52,8 +52,36 @@ extern "C" {
 
 #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, const bool dereference) {
+    int result = 0;
+
+    if (dereference) {
+      if (uid != -1) {
+        result = chown(path, uid, -1);
+
+        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
+      }
+
+      if (result == 0 && gid != -1) {
+        result = chown(path, -1, gid);
 
-    if ((dereference ? chown(path, uid, gid) : lchown(path, uid, gid)) < 0) {
+        if (errno == EPERM) return F_status_set_error(F_access_group);
+      }
+    }
+    else {
+      if (uid != -1) {
+        result = lchown(path, uid, -1);
+
+        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
+      }
+
+      if (gid != -1) {
+        result = lchown(path, -1, gid);
+
+        if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group);
+      }
+    }
+
+    if (result < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
@@ -61,7 +89,6 @@ extern "C" {
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
       if (errno == EIO) return F_status_set_error(F_input_output);
 
@@ -73,9 +100,22 @@ extern "C" {
 #endif // !defined(_di_f_file_change_owner_) || !defined(_di_f_file_copy_)
 
 #if !defined(_di_f_file_change_owner_at_) || !defined(_di_f_file_copy_at_)
-  f_return_status private_f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flags) {
+  f_return_status private_f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) {
+    int result = 0;
 
-    if (fchownat(at_id, path, uid, gid, flags) < 0) {
+    if (uid != -1) {
+      result = fchownat(at_id, path, uid, -1, flag);
+
+      if (result < 0 && errno == EPERM) return F_status_set_error(F_access_owner);
+    }
+
+    if (gid != -1) {
+      result = fchownat(at_id, path, -1, gid, flag);
+
+      if (result < 0 && errno == EPERM) return F_status_set_error(F_access_group);
+    }
+
+    if (result < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
@@ -83,8 +123,7 @@ extern "C" {
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
-      if (errno == EPERM) return F_status_set_error(F_prohibited);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == EROFS) return F_status_set_error(F_read_only);
       if (errno == EIO) return F_status_set_error(F_input_output);
 
@@ -100,7 +139,7 @@ extern "C" {
     if (F_status_is_error(private_f_file_flush(*id))) return F_status_set_error(F_file_synchronize);
 
     if (close(*id) < 0) {
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == EINTR) return F_status_set_error(F_interrupted);
       if (errno == EIO) return F_status_set_error(F_input_output);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
@@ -119,8 +158,8 @@ extern "C" {
     f_file file_source = f_file_initialize;
     f_file file_destination = f_file_initialize;
 
-    file_source.flags = f_file_flag_read_only;
-    file_destination.flags = f_file_flag_write_only | f_file_flag_no_follow;
+    file_source.flag = f_file_flag_read_only;
+    file_destination.flag = f_file_flag_write_only | f_file_flag_no_follow;
 
     f_status status = private_f_file_open(source, 0, &file_source);
     if (F_status_is_error(status)) return status;
@@ -157,14 +196,57 @@ extern "C" {
   }
 #endif // !defined(_di_f_file_copy_) || !defined(_di_f_file_clone_)
 
+#if !defined(_di_f_file_copy_at_) || !defined(_di_f_file_clone_at_)
+  f_return_status private_f_file_copy_content_at(const int at_id, const f_string source, const f_string destination, const f_number_unsigned size_block) {
+    f_file file_source = f_file_initialize;
+    f_file file_destination = f_file_initialize;
+
+    file_source.flag = f_file_flag_read_only;
+    file_destination.flag = f_file_flag_write_only | f_file_flag_no_follow;
+
+    f_status status = private_f_file_open_at(at_id, source, 0, &file_source);
+    if (F_status_is_error(status)) return status;
+
+    status = private_f_file_open_at(at_id, destination, 0, &file_destination);
+    if (F_status_is_error(status)) {
+      private_f_file_close(&file_source.id);
+      return status;
+    }
+
+    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.id);
+        private_f_file_close(&file_source.id);
+
+        return F_status_set_error(F_file_write);
+      }
+    } // while
+
+    private_f_file_close(&file_destination.id);
+    private_f_file_close(&file_source.id);
+
+    if (size_read < 0) return F_status_set_error(F_file_read);
+
+    return F_none;
+  }
+#endif // !defined(_di_f_file_copy_at_) || !defined(_di_f_file_clone_at_)
+
 #if !defined(_di_f_file_create_) || !defined(_di_f_file_copy_)
   f_return_status private_f_file_create(const f_string path, const mode_t mode, const bool exclusive) {
     f_file file = f_file_initialize;
 
-    file.flags = O_CLOEXEC | O_CREAT | O_WRONLY;
+    file.flag = f_file_flag_close_execute | f_file_flag_create | f_file_flag_write_only;
 
     if (exclusive) {
-      file.flags |= O_EXCL;
+      file.flag |= f_file_flag_exclusive;
     }
 
     f_status status = private_f_file_open(path, mode, &file);
@@ -181,10 +263,10 @@ extern "C" {
   f_return_status private_f_file_create_at(const int at_id, const f_string path, const mode_t mode, const bool exclusive) {
     f_file file = f_file_initialize;
 
-    file.flags = O_CLOEXEC | O_CREAT | O_WRONLY;
+    file.flag = f_file_flag_close_execute | f_file_flag_create | f_file_flag_write_only;
 
     if (exclusive) {
-      file.flags |= O_EXCL;
+      file.flag |= f_file_flag_exclusive;
     }
 
     f_status status = private_f_file_open_at(at_id, path, mode, &file);
@@ -232,7 +314,7 @@ extern "C" {
       if (errno == EEXIST) return F_status_set_error(F_file_found);
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
-      if (errno == EINVAL || errno == EBADF) return F_status_set_error(F_parameter);
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
       if (errno == ELOOP) return F_status_set_error(F_loop);
       if (errno == EMLINK) return F_status_set_error(F_directory_link_max);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
@@ -241,6 +323,7 @@ extern "C" {
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
 
       return F_status_set_error(F_failure);
     }
@@ -283,7 +366,7 @@ extern "C" {
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
 
       return F_status_set_error(F_failure);
     }
@@ -329,7 +412,7 @@ extern "C" {
       if (errno == EFAULT) return F_status_set_error(F_buffer);
       if (errno == EINVAL) return F_status_set_error(F_parameter);
       if (errno == ELOOP) return F_status_set_error(F_loop);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
@@ -405,7 +488,7 @@ extern "C" {
       if (errno == ELOOP) return F_status_set_error(F_loop);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
@@ -473,7 +556,7 @@ extern "C" {
 
     target->used = link_stat.st_size;
 
-    if (readlink(path, target->string, target->used) < 0) {
+    if (readlinkat(at_id, path, target->string, target->used) < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
       if (errno == EINVAL) return F_status_set_error(F_parameter);
@@ -483,7 +566,7 @@ extern "C" {
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
       if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
 
       return F_status_set_error(F_failure);
     }
@@ -495,10 +578,10 @@ extern "C" {
 #if !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
   f_return_status private_f_file_open(const f_string path, const mode_t mode, f_file *file) {
     if (mode == 0) {
-      file->id = open(path, file->flags);
+      file->id = open(path, file->flag);
     }
     else {
-      file->id = open(path, file->flags, mode);
+      file->id = open(path, file->flag, mode);
     }
 
     if (file->id < 0) {
@@ -513,12 +596,14 @@ extern "C" {
       if (errno == ELOOP) return F_status_set_error(F_loop);
       if (errno == ENFILE) return F_status_set_error(F_file_open_max);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
       if (errno == ETXTBSY) return F_status_set_error(F_busy);
+      if (errno == EISDIR) return F_status_set_error(F_directory);
+      if (errno == EOPNOTSUPP) return F_status_set_error(F_unsupported);
 
       return F_status_set_error(F_failure);
     }
@@ -530,10 +615,10 @@ extern "C" {
 #if !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_)
   f_return_status private_f_file_open_at(const int at_id, const f_string path, const mode_t mode, f_file *file) {
     if (mode == 0) {
-      file->id = openat(at_id, path, file->flags);
+      file->id = openat(at_id, path, file->flag);
     }
     else {
-      file->id = openat(at_id, path, file->flags, mode);
+      file->id = openat(at_id, path, file->flag, mode);
     }
 
     if (file->id < 0) {
@@ -547,14 +632,16 @@ extern "C" {
       if (errno == EINVAL) return F_status_set_error(F_parameter);
       if (errno == ELOOP) return F_status_set_error(F_loop);
       if (errno == ENFILE) return F_status_set_error(F_file_open_max);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
       if (errno == ETXTBSY) return F_status_set_error(F_busy);
+      if (errno == EISDIR) return F_status_set_error(F_directory);
+      if (errno == EOPNOTSUPP) return F_status_set_error(F_unsupported);
 
       return F_status_set_error(F_failure);
     }
@@ -584,9 +671,9 @@ extern "C" {
 #endif // !defined(_di_f_file_stat_) || !defined(_di_f_file_copy_)
 
 #if !defined(_di_f_file_stat_at_) || !defined(_di_f_file_copy_at_)
-  f_return_status private_f_file_stat_at(const int at_id, const f_string path, const int flags, struct stat *file_stat) {
+  f_return_status private_f_file_stat_at(const int at_id, const f_string path, const int flag, struct stat *file_stat) {
 
-    if (fstatat(at_id, path, file_stat, flags) < 0) {
+    if (fstatat(at_id, path, file_stat, flag) < 0) {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
       if (errno == ENOMEM) return F_status_set_error(F_memory_out);
@@ -595,7 +682,7 @@ extern "C" {
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == ELOOP) return F_status_set_error(F_loop);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
 
       return F_status_set_error(F_file_stat);
index 940d20f202247ed6eed71a2912144bfa4722faab..67a6e39442a149ec69b00613ddc88106957238cc 100644 (file)
@@ -57,10 +57,6 @@ extern "C" {
  *   The path file name.
  * @param mode
  *   The new mode to use.
- * @param flags
- *   Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
- *   Warning: chmod on a symolic link is currently not supported in POSIX.
- *   Therefore AT_SYMLINK_NO_FOLLOW does nothing at this time and is assumed to always be TRUE.
  *
  * @return
  *   F_none on success.
@@ -77,11 +73,10 @@ extern "C" {
  *   F_failure (with error bit) for any other (mkdir()) error.
  *
  * @see f_file_change_mode_at()
- * @see f_file_copy_at()
  */
-#if !defined(_di_f_file_change_mode_at_) || !defined(_di_f_file_copy_at_)
-  extern f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode, const int flags) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_change_mode_at_) || !defined(_di_f_file_copy_at_)
+#if !defined(_di_f_file_change_mode_at_)
+  extern f_return_status private_f_file_change_mode_at(const int at_id, const f_string path, const mode_t mode) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_change_mode_at_)
 
 /**
  * Private implementation of f_file_change_owner().
@@ -103,14 +98,17 @@ extern "C" {
  *   F_parameter (with error bit) if a parameter is invalid.
  *   F_access_denied (with error bit) on access denied.
  *   F_name (with error bit) if the filename is too long.
+ *   F_buffer (with error bit) if the buffer is invalid.
  *   F_loop (with error bit) on loop error.
  *   F_file_found_not (with error bit) if file at path was not found.
  *   F_memory_out (with error bit) if out of memory.
  *   F_directory (with error bit) on invalid directory.
- *   F_prohibited (with error bit) if filesystem does not allow for file changes.
+ *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
+ *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
  *   F_read_only (with error bit) if file is read-only.
  *   F_input_output (with error bit) on I/O error.
- *   F_failure (with error bit) for any other (mkdir()) error.
+ *   F_failure (with error bit) for any other (chown() or lchown()) error.
+ *
  *
  * @see f_file_change_owner()
  * @see f_file_copy()
@@ -132,7 +130,7 @@ extern "C" {
  *   The new user id to use.
  * @param gid
  *   The new group id to use.
- * @param flags
+ * @param flag
  *   Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
  *
  * @return
@@ -140,21 +138,23 @@ extern "C" {
  *   F_parameter (with error bit) if a parameter is invalid.
  *   F_access_denied (with error bit) on access denied.
  *   F_name (with error bit) if the filename is too long.
+ *   F_buffer (with error bit) if the buffer is invalid.
  *   F_loop (with error bit) on loop error.
  *   F_file_found_not (with error bit) if file at path was not found.
  *   F_memory_out (with error bit) if out of memory.
  *   F_directory (with error bit) on invalid directory.
- *   F_prohibited (with error bit) if filesystem does not allow for file changes.
+ *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
+ *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
  *   F_read_only (with error bit) if file is read-only.
  *   F_input_output (with error bit) on I/O error.
- *   F_failure (with error bit) for any other (mkdir()) error.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
+ *   F_failure (with error bit) for any other (chown() or lchown()) error.
  *
  * @see f_file_change_owner_at()
- * @see f_file_copy_at()
  */
-#if !defined(_di_f_file_change_owner_at_) || !defined(_di_f_file_copy_at_)
-  extern f_return_status private_f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flags) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_change_owner_at_) || !defined(_di_f_file_copy_at_)
+#if !defined(_di_f_file_change_owner_at_)
+  extern f_return_status private_f_file_change_owner_at(const int at_id, const f_string path, const uid_t uid, const gid_t gid, const int flag) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_change_owner_at_)
 
 /**
  * Private implementation of f_file_close().
@@ -242,7 +242,7 @@ extern "C" {
  * @param file
  *   The data related to the file being opened.
  *   This will be updated with the file descriptor.
- *   This will be updated with the create flags (ignoring and overriding existing file.flags).
+ *   This will be updated with the create flag (ignoring and overriding existing file.flag).
  * @param exclusive
  *   If TRUE, will fail when file already exists.
  *   If FALSE, will not fail if file already exists.
@@ -284,7 +284,7 @@ extern "C" {
  * @param file
  *   The data related to the file being opened.
  *   This will be updated with the file descriptor.
- *   This will be updated with the create flags (ignoring and overriding existing file.flags).
+ *   This will be updated with the create flag (ignoring and overriding existing file.flag).
  * @param path
  *   The path file name.
  * @param mode
@@ -313,12 +313,11 @@ extern "C" {
  *   F_file_open_max (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_copy_at()
  * @see f_file_create_at()
  */
-#if !defined(_di_f_file_create_at_) || !defined(_di_f_file_copy_at_)
+#if !defined(_di_f_file_create_at_)
   extern f_return_status private_f_file_create_at(const int at_id, const f_string path, const mode_t mode, const bool exclusive) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_create_at_) || !defined(_di_f_file_copy_at_)
+#endif // !defined(_di_f_file_create_at_)
 
 /**
  * Private implementation for creating directories.
@@ -383,7 +382,6 @@ extern "C" {
  *   F_directory_link_max (with error bit) max links limit reached or exceeded.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
  *
- * @see f_file_copy_at()
  * @see mkdirat()
  */
 #if !defined(_di_f_file_copy_at_)
@@ -441,7 +439,7 @@ extern "C" {
  *   F_name (with error bit) on path name error.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
  *   F_unsupported (with error bit) for unsupported file types.
- *   F_file_descriptor (with error bit) for bad file descriptor.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
  * @see mkfifoat()
  */
@@ -521,7 +519,7 @@ extern "C" {
  *   F_name (with error bit) on path name error.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
  *   F_unsupported (with error bit) for unsupported file types.
- *   F_file_descriptor (with error bit) for bad file descriptor.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
  * @see f_file_create_device_at()
  * @see f_file_create_node_at()
@@ -621,15 +619,14 @@ extern "C" {
  *   F_prohibited (with error bit) if filesystem does not allow for creating or linking.
  *   F_read_only (with error bit) if filesystem is read-only.
  *   F_busy (with error bit) if filesystem is too busy to perforrm write.
- *   F_file_descriptor (with error bit) if file descriptor is invalid.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *   F_failure (with error bit) for any other (symlink()) error.
  *
- * @see f_file_copy_at()
  * @see f_file_link_at()
  */
-#if !defined(_di_f_file_link_at_) || !defined(_di_f_file_copy_at_)
+#if !defined(_di_f_file_link_at_)
   extern f_return_status private_f_file_link_at(const int at_id, const f_string target, const f_string point) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_link_at_) || !defined(_di_f_file_copy_at_)
+#endif // !defined(_di_f_file_link_at_)
 
 /**
  * Private implementation of f_file_link_read().
@@ -691,7 +688,7 @@ extern "C" {
  *   F_file_found_not (with error bit) if the file at path was not found.
  *   F_memory_out (with error bit) if out of memory.
  *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
- *   F_file_descriptor (with error bit) if file descriptor is invalid.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *   F_failure (with error bit) for any other (readlinkat()) error.
  *
  * @see f_file_link_read_at()
@@ -748,15 +745,14 @@ extern "C" {
  *   F_none on success.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_file_open (with error bit) if the file is already open.
- *   F_file_descriptor (with error bit) if unable to load the file descriptor (the file pointer may still be valid).
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
- * @see f_file_copy_at()
  * @see f_file_open_at()
  */
-#if !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_)
+#if !defined(_di_f_file_open_at_)
   extern f_return_status private_f_file_open_at(const int at_id, const f_string path, const mode_t mode, f_file *file) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_)
+#endif // !defined(_di_f_file_open_at_)
 
 /**
  * Private implementation of f_file_close().
@@ -798,7 +794,7 @@ extern "C" {
  *   The parent directory, as an open directory file descriptor, in which path is relative to.
  * @param file_name
  *   The name of the file.
- * @param flags
+ * @param flag
  *   Any valid flag, such as AT_EMPTY_PATH, AT_NO_AUTOMOUNT, or AT_SYMLINK_NO_FOLLOW.
  * @param file_stat
  *   The statistics read.
@@ -815,12 +811,11 @@ extern "C" {
  *   F_loop (with error bit) if a loop occurred.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
- * @see f_file_copy_at()
  * @see f_file_stat_at()
  */
-#if !defined(_di_f_file_stat_at_) || !defined(_di_f_file_copy_at_)
-  extern f_return_status private_f_file_stat_at(const int at_id, const f_string file_name, const int flags, struct stat *file_stat) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_f_file_stat_at_) || !defined(_di_f_file_copy_at_)
+#if !defined(_di_f_file_stat_at_)
+  extern f_return_status private_f_file_stat_at(const int at_id, const f_string file_name, const int flag, struct stat *file_stat) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_file_stat_at_)
 
 /**
  * Private implementation of f_file_close().
index 80a2caf41ba9b516fdb460b873092e2fc47d04e9..7ba3de7afb67feaaae489d861e94779d584fbc4b 100644 (file)
@@ -362,6 +362,7 @@ extern "C" {
     #endif // _di_F_status_compare_
 
     #ifndef _di_F_status_access_
+      F_access,
       F_access_denied,
       F_access_denied_execute,
       F_access_denied_group,
@@ -378,6 +379,9 @@ extern "C" {
       F_access_granted_user,
       F_access_granted_world,
       F_access_granted_write,
+      F_access_group,
+      F_access_mode,
+      F_access_owner,
     #endif // _di_F_status_access_
 
     // Required.
index 095284382033149077ea466476054028a4dc7073..3b4a5026bad03132ef6062dde7dab4ffb16db711 100644 (file)
@@ -5,27 +5,36 @@
 extern "C" {
 #endif
 
-#ifndef _di_fl_directory_copy_
-  f_return_status fl_directory_copy(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) {
+#ifndef _di_fl_directory_clone_
+  f_return_status fl_directory_clone(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) {
     f_status status = F_none;
 
     status = f_directory_exists(source);
     if (F_status_is_error(status)) return status;
     if (status == F_false) return F_status_set_error(F_directory);
 
-    f_directory_listing listing = f_directory_listing_initialize;
+    const f_string_static static_source = { source, source_length, source_length };
+    const f_string_static static_destination = { destination, destination_length, destination_length };
+
+    status = private_fl_directory_clone(static_source, static_destination, role, size_block, exclusive, failures);
+
+    return F_none;
+  }
+#endif // _di_fl_directory_clone_
+
+#ifndef _di_fl_directory_copy_
+  f_return_status fl_directory_copy(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) {
+    f_status status = F_none;
 
-    status = private_fl_directory_list(source, 0, 0, F_false, &listing);
+    status = f_directory_exists(source);
     if (F_status_is_error(status)) return status;
+    if (status == F_false) return F_status_set_error(F_directory);
 
     const f_string_static static_source = { source, source_length, source_length };
     const f_string_static static_destination = { destination, destination_length, destination_length };
 
     status = private_fl_directory_copy(static_source, static_destination, mode, size_block, exclusive, failures);
 
-    f_macro_directory_listing_destroy(status, listing);
-    if (F_status_is_error(status)) return status;
-
     return F_none;
   }
 #endif // _di_fl_directory_copy_
@@ -40,6 +49,19 @@ extern "C" {
   }
 #endif // _di_fl_directory_list_
 
+#ifndef _di_fl_directory_list_at_
+  f_return_status fl_directory_list_at(const int at_id, const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing) {
+    #ifndef _di_level_2_parameter_checking_
+      if (listing == 0) return F_status_set_error(F_parameter);
+    #endif // _di_level_2_parameter_checking_
+
+    // @todo implement a directoy list that passes at_id to scandirat().
+    // but... DIR * appears to be needed, can I just instead pass the path string instead? (char *).
+
+    return private_fl_directory_list(path, filter, sort, dereference, listing);
+  }
+#endif // _di_fl_directory_list_at_
+
 #ifndef _di_fl_directory_path_pop_
   f_return_status fl_directory_path_pop(f_string_static *path) {
     #ifndef _di_level_0_parameter_checking_
index ee8fd50acc8ec2038ff8d6c056e732a61842369f..c637c16fc20b598a485d2053d1c6286a0761d9ee 100644 (file)
@@ -45,11 +45,13 @@ extern "C" {
 #endif
 
 /**
- * Copy a directory and its contents.
+ * 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.
+ *
  * Symbolic links are not followed, they are copied as the symbolic link itself.
  *
  * This does not copy unknown file types.
@@ -64,17 +66,16 @@ extern "C" {
  *   The length of the source path.
  * @param destination_length
  *   The length of the destination path.
- * @param mode
- *   The directory modes.
+ * @param role
+ *   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.)
  * @param size_block
  *   The default number of chunks to read at a time with each chunk being 1-byte.
- *   Set to 0 to use default block read size.
+ *   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 failures
- *   A list of paths and their respective status codes for copy failures.
- *   If 0, then this and statuses is ignored.
+ *   If TRUE, will fail when parent directory already exists.
+ *   If FALSE, will not fail if parent directory already exists (existing directory will be updated).
  *
  * @return
  *   F_none on success.
@@ -83,6 +84,8 @@ extern "C" {
  *   F_loop (with error bit) on loop error.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_memory_out (with error bit) if out of memory.
+ *   F_memory_allocation (with error bit) on memory allocation error.
+ *   F_memory_reallocation (with error bit) on memory re-allocation error.
  *   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.
@@ -97,41 +100,47 @@ extern "C" {
  *   F_busy (with error bit) if filesystem is too busy to perforrm write.
  *   F_file_read (with error bit) on file read error.
  *   F_file_write (with error bit) on file write error.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
- * @see f_file_copy()
+ * @see f_directory_create()
+ * @see f_file_clone()
  * @see read()
  */
-#ifndef _di_fl_directory_copy_
-  extern f_return_status fl_directory_copy(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures);
-#endif // _di_fl_directory_copy_
+#ifndef _di_fl_directory_clone_
+  extern f_return_status fl_directory_clone(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures);
+#endif // _di_fl_directory_clone_
 
 /**
- * Copy a file, as well as its file mode and possibly the owner and group.
+ * Copy a directory and its contents.
  *
  * 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.
- *
  * Symbolic links are not followed, they are copied as the symbolic link itself.
  *
  * This does not copy unknown file types.
  *
  * @param source
- *   The path to the directory to copy from.
+ *   The source file path.
+ *   Must be NULL terminated.
  * @param destination
- *   The path to copy to.
+ *   The destination file path.
+ *   Must be NULL terminated.
+ * @param source_length
+ *   The length of the source path.
+ * @param destination_length
+ *   The length of the destination path.
+ * @param mode
+ *   The directory modes.
  * @param size_block
  *   The default number of chunks to read at a time with each chunk being 1-byte.
- *   Must be greater than 0.
+ *   Set to 0 to use default block read size.
  * @param exclusive
- *   If TRUE, will fail when parent directory already exists.
- *   If FALSE, will not fail if parent directory already exists (existing directory will be updated).
- * @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.)
+ *   If TRUE, will fail when file already exists.
+ *   If FALSE, will not fail if file already exists (existing file will be replaced).
+ * @param failures
+ *   A list of paths and their respective status codes for copy failures.
+ *   If 0, then this and statuses is ignored.
  *
  * @return
  *   F_none on success.
@@ -140,6 +149,8 @@ extern "C" {
  *   F_loop (with error bit) on loop error.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_memory_out (with error bit) if out of memory.
+ *   F_memory_allocation (with error bit) on memory allocation error.
+ *   F_memory_reallocation (with error bit) on memory re-allocation error.
  *   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.
@@ -154,14 +165,14 @@ extern "C" {
  *   F_busy (with error bit) if filesystem is too busy to perforrm write.
  *   F_file_read (with error bit) on file read error.
  *   F_file_write (with error bit) on file write error.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
- * @see f_directory_create()
- * @see f_file_clone()
+ * @see f_file_copy()
  * @see read()
  */
-#ifndef _di_fl_directory_clone_
-  extern f_return_status fl_directory_clone(const f_string source, const f_string destination, const f_number_unsigned size_block, const bool exclusive, const bool roles);
-#endif // _di_fl_directory_clone_
+#ifndef _di_fl_directory_copy_
+  extern f_return_status fl_directory_copy(const f_string source, const f_string destination, const f_string_length source_length, const f_string_length destination_length, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures);
+#endif // _di_fl_directory_copy_
 
 /**
  * For some given path, print the names of each file and/or directory inside the directory, stored as a directory listing.
@@ -206,6 +217,48 @@ extern "C" {
 #endif // _di_fl_directory_list_
 
 /**
+ * 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 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 dereference
+ *   Set to TRUE to dereferenc symlinks (often is what is desired).
+ *   Set to FALSE to operate on the symlink itself.
+ * @param listing
+ *   Will be populated with the names of all top-level paths found within the given directory.
+ *
+ * @return
+ *   F_none on success.
+ *   F_data_not 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_parameter (with error bit) if a parameter is invalid.
+ *   F_memory_reallocation (with error bit) on memory reallocation error.
+ *   F_directory_open (with error bit) on directory open error.
+ *   F_directory_descriptor (with error bit) on directory file descriptor error.
+ *   F_directory_stream (with error bit) on directory stream error.
+ *   F_directory_unsupported (with error bit) on directory file descriptor not supported.
+ *   F_file_descriptor_max (with error bit) if max file descriptors was reached.
+ *   F_file_open_max (with error bit) too many open files.
+ *
+ * @see alphasort()
+ * @see opendir()
+ * @see scandir()
+ * @see versionsort()
+ */
+#ifndef _di_fl_directory_list_at_
+  extern f_return_status fl_directory_list_at(const int at_id, const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing);
+#endif // _di_fl_directory_list_at_
+
+/**
  * Append a path string onto the destination path.
  *
  * This ensures that there is a trailing '/' after pop.
index 503f32695a7cead80d60a23f9b430109f94a56a2..cf893d6f6cbe07da974f3856558e569a7a2bcfb1 100644 (file)
 extern "C" {
 #endif
 
+#if !defined(_di_fl_directory_clone_)
+  f_return_status private_fl_directory_clone(const f_string_static source, const f_string_static destination, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) {
+    f_status status = f_directory_exists(source.string);
+
+    if (F_status_is_error(status)) return status;
+    if (status == F_false) return F_status_set_error(F_directory);
+
+    struct stat source_stat;
+
+    memset(&source_stat, 0, sizeof(struct stat));
+
+    status = f_file_stat(source.string, F_false, &source_stat);
+    if (F_status_is_error(status)) return status;
+
+    status = f_directory_exists(destination.string);
+    if (F_status_is_error(status)) return status;
+
+    if (status == F_true) {
+      if (exclusive) {
+        return F_status_set_error(F_directory_found);
+      }
+
+      status = f_file_change_mode(destination.string, source_stat.st_mode);
+      if (F_status_is_error(status)) return status;
+    }
+    else {
+      status = f_directory_create(destination.string, source_stat.st_mode);
+      if (F_status_is_error(status)) return status;
+    }
+
+    if (role) {
+      status = f_file_change_owner(destination.string, source_stat.st_uid, source_stat.st_gid, F_true);
+      if (F_status_is_error(status)) return status;
+    }
+
+    f_directory_listing listing = f_directory_listing_initialize;
+
+    status = private_fl_directory_list(source.string, 0, 0, F_false, &listing);
+    if (F_status_is_error(status)) {
+      f_macro_directory_listing_delete_simple(listing);
+      return status;
+    }
+
+    status = F_none;
+
+    f_array_length i = 0;
+
+    int directory_fd = 0;
+    f_string_length failures_used = failures ? failures->used : 0;
+
+    for (; F_status_is_fine(status) && i < listing.block.used; i++) {
+      status = private_fl_directory_clone_file(listing.block.array[i], source, destination, role, size_block, exclusive, failures);
+    } // for
+
+    f_macro_string_dynamics_delete_simple(listing.block);
+
+    for (i = 0; F_status_is_fine(status) && i < listing.character.used; i++) {
+      status = private_fl_directory_clone_file(listing.character.array[i], source, destination, role, size_block, exclusive, failures);
+    } // for
+
+    f_macro_string_dynamics_delete_simple(listing.character);
+
+    for (i = 0; F_status_is_fine(status) && i < listing.regular.used; i++) {
+      status = private_fl_directory_clone_file(listing.regular.array[i], source, destination, role, size_block, exclusive, failures);
+    } // for
+
+    f_macro_string_dynamics_delete_simple(listing.regular);
+
+    for (i = 0; F_status_is_fine(status) && i < listing.link.used; i++) {
+      status = private_fl_directory_clone_file(listing.link.array[i], source, destination, role, size_block, exclusive, failures);
+    } // for
+
+    f_macro_string_dynamics_delete_simple(listing.link);
+
+    for (i = 0; F_status_is_fine(status) && i < listing.socket.used; i++) {
+      status = private_fl_directory_clone_file(listing.socket.array[i], source, destination, role, size_block, exclusive, failures);
+    } // for
+
+    f_macro_string_dynamics_delete_simple(listing.socket);
+
+    for (i = 0; F_status_is_fine(status) && i < listing.unknown.used; i++) {
+      status = private_fl_directory_clone_file(listing.unknown.array[i], source, destination, role, size_block, exclusive, failures);
+    } // for
+
+    f_macro_string_dynamics_delete_simple(listing.unknown);
+
+    for (i = 0; F_status_is_fine(status) && i < listing.directory.used; i++) {
+      f_string_static source_sub = f_string_static_initialize;
+      f_string_static destination_sub = f_string_static_initialize;
+
+      source_sub.used = source.used + listing.directory.array[i].used + 1;
+      source_sub.size = source_sub.used;
+
+      destination_sub.used = destination.used + listing.directory.array[i].used + 1;
+      destination_sub.size = destination_sub.used;
+
+      char path_source_sub[source_sub.used + 1];
+      char path_destination_sub[destination_sub.used + 1];
+
+      memcpy(path_source_sub, source.string, source.used);
+      memcpy(path_source_sub + source.used + 1, listing.directory.array[i].string, listing.directory.array[i].used);
+
+      memcpy(path_destination_sub, destination.string, destination.used);
+      memcpy(path_destination_sub + destination.used + 1, listing.directory.array[i].string, listing.directory.array[i].used);
+
+      path_source_sub[source.used] = f_path_separator[0];
+      path_source_sub[source_sub.used] = 0;
+
+      path_destination_sub[destination.used] = f_path_separator[0];
+      path_destination_sub[destination_sub.used] = 0;
+
+      source_sub.string = path_source_sub;
+      destination_sub.string = path_destination_sub;
+
+      status = private_fl_directory_clone(source_sub, destination_sub, role, size_block, exclusive, failures);
+    } // for
+
+    f_macro_string_dynamics_delete_simple(listing.directory);
+
+    if (F_status_is_error(status)) return status;
+
+    if (failures && failures_used < failures->used) return F_failure;
+
+    return F_none;
+  }
+#endif // !defined(_di_fl_directory_clone_)
+
+#if !defined(_di_fl_directory_clone_file_)
+  f_return_status private_fl_directory_clone_file(const f_string_static file, const f_string_static source, const f_string_static destination, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) {
+    char path_source[source.used + file.used + 2];
+    char path_destination[destination.used + file.used + 2];
+
+    memcpy(path_source, source.string, source.used);
+    memcpy(path_source + source.used + 1, file.string, file.used);
+    path_source[source.used] = f_path_separator[0];
+    path_source[source.used + file.used + 1] = 0;
+
+    memcpy(path_destination, destination.string, destination.used);
+    memcpy(path_destination + destination.used + 1, file.string, file.used);
+    path_destination[destination.used] = f_path_separator[0];
+    path_destination[destination.used + file.used + 1] = 0;
+
+    f_status status = f_file_clone(path_source, path_destination, role, size_block, exclusive);
+
+    if (F_status_is_error(status) || status == F_unsupported) {
+      if (status == F_status_set_error(F_memory_allocation) || status == F_status_set_error(F_memory_reallocation)) {
+        return F_status_set_error(status);
+      }
+
+      if (!failures) return F_failure;
+
+      const f_status status_failure = status;
+
+      if (failures->used + 1 > failures->size) {
+        if (failures->size + f_memory_default_allocation_step > f_array_length_size) {
+          if (failures->size + 1 > f_array_length_size) {
+            return F_status_set_error(F_buffer_too_large);
+          }
+
+          f_macro_directory_statuss_resize(status, (*failures), failures->used + 1);
+          if (F_status_is_error(status)) return status;
+        }
+        else {
+          f_macro_directory_statuss_resize(status, (*failures), failures->used + f_memory_default_allocation_step);
+          if (F_status_is_error(status)) return status;
+        }
+      }
+
+      f_directory_status failure = f_directory_status_initialize;
+      f_string_length size = 0;
+
+      // identify if failure was because of source or destination.
+      struct stat source_stat;
+
+      memset(&source_stat, 0, sizeof(struct stat));
+
+      status = f_file_stat(source.string, F_false, &source_stat);
+      if (F_status_is_error(status)) {
+        if (status == F_status_set_error(F_string_too_large)) {
+          size = f_string_length_size - 1;
+        }
+        else {
+          size = source.used + file.used + 1;
+        }
+
+        f_macro_directory_status_resize(status, failure, size + 1);
+        if (F_status_is_error(status)) return status;
+
+        memcpy(failure.path.string, path_source, size);
+        failure.path.string[size] = 0;
+      }
+      else {
+        if (status == F_status_set_error(F_string_too_large)) {
+          size = f_string_length_size - 1;
+        }
+        else {
+          size = destination.used + file.used + 1;
+        }
+
+        f_macro_directory_status_resize(status, failure, size + 1);
+        if (F_status_is_error(status)) return status;
+
+        memcpy(failure.path.string, path_destination, size);
+        failure.path.string[size] = 0;
+      }
+
+      failures->array[failures->used].path.string = failure.path.string;
+      failures->array[failures->used].path.used = size;
+      failures->array[failures->used].path.size = size + 1;
+      failures->array[failures->used].status = status_failure;
+      failures->used++;
+
+      return F_failure;
+    }
+
+    return F_none;
+  }
+#endif // !defined(_di_fl_directory_clone_file_)
+
 #if !defined(_di_fl_directory_copy_)
   f_return_status private_fl_directory_copy(const f_string_static source, const f_string_static destination, const f_directory_mode mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) {
-    f_status status = F_none;
+    f_status status = f_directory_exists(source.string);
 
-    status = f_directory_exists(source.string);
     if (F_status_is_error(status)) return status;
     if (status == F_false) return F_status_set_error(F_directory);
 
@@ -121,7 +339,7 @@ extern "C" {
   }
 #endif // !defined(_di_fl_directory_copy_)
 
-#if !defined(_di_fl_directory_copy_)
+#if !defined(_di_fl_directory_copy_file_)
   f_return_status private_fl_directory_copy_file(const f_string_static file, const f_string_static source, const f_string_static destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) {
     char path_source[source.used + file.used + 2];
     char path_destination[destination.used + file.used + 2];
@@ -211,7 +429,7 @@ extern "C" {
 
     return F_none;
   }
-#endif // !defined(_di_fl_directory_copy_)
+#endif // !defined(_di_fl_directory_copy_file_)
 
 #if !defined(_di_fl_directory_list_)
   f_return_status private_fl_directory_list(const f_string path, int (*filter)(const struct dirent *), int (*sort)(const struct dirent **, const struct dirent **), const bool dereference, f_directory_listing *listing) {
index 779043b56a81cf88b429cc48fd7ef76822eb164d..b8f4068b5d2f2150e9f9dac46a8d0e62e56dae3f 100644 (file)
@@ -15,6 +15,121 @@ extern "C" {
 #endif
 
 /**
+ * Private implementation of fl_directory_clone().
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param source
+ *   The source file path.
+ *   Must be NULL terminated.
+ * @param destination
+ *   The destination file path.
+ *   Must be NULL terminated.
+ * @param role
+ *   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.)
+ * @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 failures
+ *   A list of paths and their respective status codes for clone failures.
+ *   If 0, then this and statuses is ignored.
+ *
+ * @return
+ *   F_none on success.
+ *   F_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_memory_out (with error bit) if out of memory.
+ *   F_memory_allocation (with error bit) on memory allocation error.
+ *   F_memory_reallocation (with error bit) on memory re-allocation error.
+ *   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_block (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_name (with error bit) on path name error.
+ *   F_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_open_max (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_read (with error bit) on file read error.
+ *   F_file_write (with error bit) on file write error.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
+ *
+ * @see fl_directory_clone()
+ */
+#if !defined(_di_fl_directory_clone_)
+  extern f_return_status private_fl_directory_clone(const f_string_static source, const f_string_static destination, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_fl_directory_clone_)
+
+/**
+ * A special function intended to be used directly by private_fl_directory_clone().
+ *
+ * Will only clone a single file and record any detected errors.
+ *
+ * @param file
+ *   The name of the file within source to clone into destination.
+ *   Must be NULL terminated.
+ * @param source
+ *   The source file path.
+ *   Must be NULL terminated.
+ * @param destination
+ *   The destination file path.
+ *   Must be NULL terminated.
+ * @param role
+ *   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.)
+ * @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 failures
+ *   A list of paths and their respective status codes for clone failures.
+ *   If 0, then this and statuses is ignored.
+ *
+ * @return
+ *   F_none on success.
+ *   F_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_memory_out (with error bit) if out of memory.
+ *   F_memory_allocation (with error bit) on memory allocation error.
+ *   F_memory_reallocation (with error bit) on memory re-allocation error.
+ *   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_block (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_name (with error bit) on path name error.
+ *   F_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_open_max (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_read (with error bit) on file read error.
+ *   F_file_write (with error bit) on file write error.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
+ *
+ * @see fl_directory_clone()
+ */
+#if !defined(_di_fl_directory_clone_file_)
+  extern f_return_status private_fl_directory_clone_file(const f_string_static file, const f_string_static source, const f_string_static destination, const bool role, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_fl_directory_clone_file_)
+
+/**
  * Private implementation of fl_directory_copy().
  *
  * Intended to be shared to each of the different implementation variations.
@@ -39,9 +154,28 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_failure on handled error (failures and statuses is updated with failure and status code).
+ *   F_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_memory_out (with error bit) if out of memory.
  *   F_memory_allocation (with error bit) on memory allocation error.
  *   F_memory_reallocation (with error bit) on memory re-allocation error.
+ *   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_block (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_name (with error bit) on path name error.
+ *   F_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_open_max (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_read (with error bit) on file read error.
+ *   F_file_write (with error bit) on file write error.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
  * @see fl_directory_copy()
  */
@@ -77,15 +211,34 @@ extern "C" {
  *
  * @return
  *   F_none on success.
- *   F_failure on handled error (failures and statuses is updated with failure and status code).
+ *   F_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_memory_out (with error bit) if out of memory.
  *   F_memory_allocation (with error bit) on memory allocation error.
  *   F_memory_reallocation (with error bit) on memory re-allocation error.
+ *   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_block (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_name (with error bit) on path name error.
+ *   F_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_open_max (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_read (with error bit) on file read error.
+ *   F_file_write (with error bit) on file write error.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *
  * @see fl_directory_copy()
  */
-#if !defined(_di_fl_directory_copy_)
+#if !defined(_di_fl_directory_copy_file_)
   extern f_return_status private_fl_directory_copy_file(const f_string_static file, const f_string_static source, const f_string_static destination, const mode_t mode, const f_number_unsigned size_block, const bool exclusive, f_directory_statuss *failures) f_gcc_attribute_visibility_internal;
-#endif // !defined(_di_fl_directory_copy_)
+#endif // !defined(_di_fl_directory_copy_file_)
 
 /**
  * A special function intended to be used directly by fl_directory_list().
index 8771ce758698de3c2775a5797c365bc82bfda01e..dbbddf13c06cd075906167af40cf3b375037ed1e 100644 (file)
@@ -803,6 +803,9 @@ extern "C" {
       #endif // _di_F_status_compare_
 
       #ifndef _di_F_status_access_
+        case F_access:
+          *string = FL_status_string_access;
+          break;
         case F_access_denied:
           *string = FL_status_string_access_denied;
           break;
@@ -851,6 +854,15 @@ extern "C" {
         case F_access_granted_super:
           *string = FL_status_string_access_granted_super;
           break;
+        case F_access_group:
+          *string = FL_status_string_access_group;
+          break;
+        case F_access_mode:
+          *string = FL_status_string_access_mode;
+          break;
+        case F_access_owner:
+          *string = FL_status_string_access_owner;
+          break;
       #endif // _di_F_status_access_
 
       case F_status_code_last:
index 138f80802046e39c66ad10a431f545efc07fe9cf..ea95a8c3aa797c89fb319a5a2e32226be8de07a4 100644 (file)
@@ -579,14 +579,15 @@ extern "C" {
   #endif // _di_F_status_compare_
 
   #ifndef _di_F_status_access_
-    #define FL_status_string_access_denied         "F_access_denied"
-    #define FL_status_string_access_denied_user    "F_access_denied_user"
-    #define FL_status_string_access_denied_group   "F_access_denied_group"
-    #define FL_status_string_access_denied_world   "F_access_denied_world"
-    #define FL_status_string_access_denied_read    "F_access_denied_read"
-    #define FL_status_string_access_denied_write   "F_access_denied_write"
-    #define FL_status_string_access_denied_execute "F_access_denied_execute"
-    #define FL_status_string_access_denied_super   "F_access_denied_super"
+    #define FL_status_string_access                 "F_access"
+    #define FL_status_string_access_denied          "F_access_denied"
+    #define FL_status_string_access_denied_user     "F_access_denied_user"
+    #define FL_status_string_access_denied_group    "F_access_denied_group"
+    #define FL_status_string_access_denied_world    "F_access_denied_world"
+    #define FL_status_string_access_denied_read     "F_access_denied_read"
+    #define FL_status_string_access_denied_write    "F_access_denied_write"
+    #define FL_status_string_access_denied_execute  "F_access_denied_execute"
+    #define FL_status_string_access_denied_super    "F_access_denied_super"
     #define FL_status_string_access_granted         "F_access_granted"
     #define FL_status_string_access_granted_user    "F_access_granted_user"
     #define FL_status_string_access_granted_group   "F_access_granted_group"
@@ -595,7 +596,11 @@ extern "C" {
     #define FL_status_string_access_granted_write   "F_access_granted_write"
     #define FL_status_string_access_granted_execute "F_access_granted_execute"
     #define FL_status_string_access_granted_super   "F_access_granted_super"
+    #define FL_status_string_access_group           "F_access_group"
+    #define FL_status_string_access_mode            "F_access_mode"
+    #define FL_status_string_access_owner           "F_access_owner"
 
+    #define FL_status_string_access_length                 8
     #define FL_status_string_access_denied_length          15
     #define FL_status_string_access_denied_user_length     20
     #define FL_status_string_access_denied_group_length    21
@@ -612,6 +617,9 @@ extern "C" {
     #define FL_status_string_access_granted_write_length   22
     #define FL_status_string_access_granted_execute_length 24
     #define FL_status_string_access_granted_super_length   22
+    #define FL_status_string_access_group_length           14
+    #define FL_status_string_access_mode_length            13
+    #define FL_status_string_access_owner_length           14
   #endif // _di_F_status_access_
 
   #define FL_status_string_status_code_last "F_status_code_last"
index a1735989d8a8ea6dace3de37ee04f634ae97c57b..c60a9c8627abf81047658f18130545ea58292b97 100644 (file)
@@ -1308,6 +1308,11 @@ extern "C" {
     #endif // _di_F_status_compare_
 
     #ifndef _di_F_status_access_
+      if (fl_string_compare(string, FL_status_string_access, length, FL_status_string_access_length) == F_equal_to) {
+        *code = F_access;
+        return F_none;
+      }
+
       if (fl_string_compare(string, FL_status_string_access_denied, length, FL_status_string_access_denied_length) == F_equal_to) {
         *code = F_access_denied;
         return F_none;
@@ -1387,6 +1392,21 @@ extern "C" {
         *code = F_access_granted_super;
         return F_none;
       }
+
+      if (fl_string_compare(string, FL_status_string_access_group, length, FL_status_string_access_group_length) == F_equal_to) {
+        *code = F_access_mode;
+        return F_none;
+      }
+
+      if (fl_string_compare(string, FL_status_string_access_mode, length, FL_status_string_access_mode_length) == F_equal_to) {
+        *code = F_access_group;
+        return F_none;
+      }
+
+      if (fl_string_compare(string, FL_status_string_access_owner, length, FL_status_string_access_owner_length) == F_equal_to) {
+        *code = F_access_owner;
+        return F_none;
+      }
     #endif // _di_F_status_access_
 
     if (fl_string_compare(string, FL_status_string_status_code_last, length, FL_status_string_status_code_last_length) == F_equal_to) {
index 7c5ca16e1a3e8cbc45ca861bbdf2e68a8a1e2708..d55e9ab454c79f350cb7998cc065d57c6ecc7f81 100644 (file)
@@ -140,7 +140,7 @@ extern "C" {
       if (data->parameters[fss_basic_list_write_parameter_file].result == f_console_result_additional) {
         f_file output = f_file_initialize;
 
-        output.flags = f_file_flag_append_wo;
+        output.flag = f_file_flag_append_wo;
 
         status = f_file_open(arguments.argv[data->parameters[fss_basic_list_write_parameter_file].additional.array[0]], 0, &output);
 
index 7a20c0f2d3abfc03e97848e030654c207aed8976..ac90e9b021238a3feb4d65dfbafdcb02544d5053 100644 (file)
@@ -140,7 +140,7 @@ extern "C" {
       if (data->parameters[fss_basic_write_parameter_file].result == f_console_result_additional) {
         f_file output = f_file_initialize;
 
-        output.flags = f_file_flag_append_wo;
+        output.flag = f_file_flag_append_wo;
 
         status = f_file_open(arguments.argv[data->parameters[fss_basic_write_parameter_file].additional.array[0]], 0, &output);
 
index eb424995d993f481e7a3a29319abb836e27f7ccf..890f04150c702ae9c21f4413acdffa01665fe9e0 100644 (file)
@@ -205,7 +205,7 @@ extern "C" {
       if (data->parameters[fss_extended_write_parameter_file].result == f_console_result_additional) {
         f_file output = f_file_initialize;
 
-        output.flags = f_file_flag_append_wo;
+        output.flag = f_file_flag_append_wo;
 
         status = f_file_open(arguments.argv[data->parameters[fss_extended_write_parameter_file].additional.array[0]], 0, &output);