]> Kevux Git Server - fll/commitdiff
Bugfix: Fix problems exposed by f_file project tests.
authorKevin Day <thekevinday@gmail.com>
Mon, 11 Apr 2022 02:16:54 +0000 (21:16 -0500)
committerKevin Day <thekevinday@gmail.com>
Mon, 11 Apr 2022 02:16:54 +0000 (21:16 -0500)
The f_file_access() should have the mode parameter.
Add missing f_file_access_at().

The f_file_clone() and f_file_copy() are treating exclusive incorrectly.
Do not test for exclusive when assigning the file mode, that is not what exclusive is for.

Add missing paramter check in f_file_descriptor(), f_file_read(), f_file_read_block(), f_file_read_until(), f_file_stream_read(), and f_file_stream_read_until().

The return error result for when a file is not a directory should return F_directory_not rather than F_directory.

Remove unneeded parameter check from f_file_mode_set(), f_file_stream_write_until(), and f_file_stream_write_range().

Add missing range.start > range.stop checks where appropriate.

Many of the file stream functions have locked function calls when unlocked function calls should be used.
Such as where feof() should instead be feof_unlocked() and ferror() should instead be ferror_unlocked().

The private_f_file_stream_write_until() function needs to use unlocked function calls and then must be wrapped between manual flockfile() and funlockfile() calls.

Update documentation comments.

Clean up much of the errno checks alphabetic ordering as appropriate.

Clean up the macro definitions, adding more structure and organization.

Add file access mode define macros.

Simplify function calls where the function may be called with different number of parameters.
This is not strictly allowed by the C language but somehow the POSIX standard got these in and implemented.
This is likely done through macros or some fancy linker tricks.
Avoid these uses and instead use the most likely implemented one.
Example:
  openat(at_id, path.string, file->flag);
  vs
  openat(at_id, path.string, file->flag, mode);
The latter is the one chosen to be most likely.

Add missing result checks that without those checks could potentially alter owner/group on files after an error occurred.

The f_file project tests are a works in progress and so there may be more such fixes to come.

level_0/f_file/c/file.c
level_0/f_file/c/file.h
level_0/f_file/c/file/common.c
level_0/f_file/c/file/common.h
level_0/f_file/c/private-file.c

index c0915d5df3f7fe7ecb7d51aff5f4bd91cff40bb2..b4fe5493ad3923cdc4aa9f69c4e720027cbb3be7 100644 (file)
@@ -6,28 +6,70 @@ extern "C" {
 #endif
 
 #ifndef _di_f_file_access_
-  f_status_t f_file_access(const f_string_static_t path) {
+  f_status_t f_file_access(const f_string_static_t path, const int mode) {
 
     if (!path.used) {
       return F_data_not;
     }
 
-    if (access(path.string, F_OK)) {
-      if (errno == ENOENT) return F_false;
-      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+    if (access(path.string, mode) == -1) {
+
+      if (mode == F_file_access_mode_exist_d) {
+        if (errno == ENOENT) return F_false;
+      }
+      else {
+        if (errno == EACCES) return F_false;
+      }
+
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == ENOENT) return F_status_set_error(F_file_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_true;
+  }
+#endif // _di_f_file_access_
+
+#ifndef _di_f_file_access_at_
+  f_status_t f_file_access_at(const int at_id, const f_string_static_t path, const int mode, const int flag) {
+
+    if (!path.used) {
+      return F_data_not;
+    }
+
+    if (faccessat(at_id, path.string, mode, flag) == -1) {
+
+      if (mode == F_file_access_mode_exist_d) {
+        if (errno == ENOENT) return F_false;
+      }
+      else {
+        if (errno == EACCES) return F_false;
+      }
+
       if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+      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 == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == ENOENT) return F_status_set_error(F_file_not);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
+      if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
 
-      return F_status_set_error(F_false);
+      return F_status_set_error(F_failure);
     }
 
     return F_true;
   }
-#endif // _di_f_file_access_
+#endif // _di_f_file_access_at_
 
 #ifndef _di_f_file_clone_
   f_status_t f_file_clone(const f_string_static_t source, const f_string_static_t destination, const bool role, const f_number_unsigned_t size_block, const bool exclusive) {
@@ -48,10 +90,8 @@ extern "C" {
       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_mode_set(destination, source_stat.st_mode);
-        if (F_status_is_error(status)) return status;
-      }
+      status = private_f_file_mode_set(destination, source_stat.st_mode);
+      if (F_status_is_error(status)) return status;
 
       if (role) {
         status = private_f_file_role_change(destination, source_stat.st_uid, source_stat.st_gid, F_false);
@@ -122,14 +162,11 @@ extern "C" {
     if (F_status_is_error(status)) return status;
 
     if (macro_f_file_type_is_regular(source_stat.st_mode)) {
-
       status = private_f_file_create(destination, (~F_file_type_mask_d) & mode.regular, exclusive);
       if (F_status_is_error(status)) return status;
 
-      if (!exclusive) {
-        status = private_f_file_mode_set(destination, (~F_file_type_mask_d) & mode.regular);
-        if (F_status_is_error(status)) return status;
-      }
+      status = private_f_file_mode_set(destination, (~F_file_type_mask_d) & mode.regular);
+      if (F_status_is_error(status)) return status;
 
       return private_f_file_copy_content(source, destination, size_block == 0 ? F_file_default_read_size_d : size_block);
     }
@@ -153,6 +190,7 @@ extern "C" {
       f_string_dynamic_t target = f_string_dynamic_t_initialize;
 
       status = private_f_file_link_read(source, source_stat, &target);
+
       if (F_status_is_error(status)) {
         f_string_dynamic_resize(0, &target);
 
@@ -331,6 +369,9 @@ extern "C" {
 
 #ifndef _di_f_file_descriptor_
   f_status_t f_file_descriptor(f_file_t *file) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!file) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
 
     file->id = fileno(file->stream);
 
@@ -460,15 +501,15 @@ extern "C" {
     memset(&stat_file, 0, sizeof(struct stat));
 
     if (fstatat(at_id, path.string, &stat_file, flag) < 0) {
-      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == ELOOP) return F_status_set_error(F_loop);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
+      if (errno == ENOENT) return F_file_found_not;
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
-      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);
     }
@@ -521,7 +562,7 @@ extern "C" {
       if (errno == EINVAL) return F_status_set_error(F_parameter);
       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 == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
@@ -549,7 +590,7 @@ extern "C" {
       if (errno == EINVAL) return F_status_set_error(F_parameter);
       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 == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
@@ -1296,9 +1337,6 @@ extern "C" {
 
 #ifndef _di_f_file_mode_set_
   f_status_t f_file_mode_set(const f_string_static_t path, const mode_t mode) {
-    #ifndef _di_level_0_parameter_checking_
-      if (!path.used) return F_status_set_error(F_parameter);
-    #endif // _di_level_0_parameter_checking_
 
     if (!path.used) {
       return F_data_not;
@@ -1508,6 +1546,7 @@ extern "C" {
 #ifndef _di_f_file_read_
   f_status_t f_file_read(const f_file_t file, f_string_dynamic_t * const buffer) {
     #ifndef _di_level_0_parameter_checking_
+      if (!file.size_read) return F_status_set_error(F_parameter);
       if (!buffer) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
@@ -1519,7 +1558,6 @@ extern "C" {
     ssize_t size_read = 0;
 
     do {
-
       status = f_string_dynamic_increase_by(file.size_read, buffer);
       if (F_status_is_error(status)) return status;
 
@@ -1548,6 +1586,7 @@ extern "C" {
 #ifndef _di_f_file_read_block_
   f_status_t f_file_read_block(const f_file_t file, f_string_dynamic_t * const buffer) {
     #ifndef _di_level_0_parameter_checking_
+      if (!file.size_read) return F_status_set_error(F_parameter);
       if (!buffer) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
@@ -1591,6 +1630,7 @@ extern "C" {
 #ifndef _di_f_file_read_until_
   f_status_t f_file_read_until(const f_file_t file, const f_array_length_t total, f_string_dynamic_t * const buffer) {
     #ifndef _di_level_0_parameter_checking_
+      if (!file.size_read) return F_status_set_error(F_parameter);
       if (!buffer) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
@@ -1659,7 +1699,7 @@ extern "C" {
       if (errno == EFAULT) return F_status_set_error(F_buffer);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
 
@@ -1687,7 +1727,7 @@ extern "C" {
       if (errno == EFAULT) return F_status_set_error(F_buffer);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_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);
@@ -1719,7 +1759,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_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == ENOTEMPTY) return F_status_set_error(F_directory_empty_not);
       if (errno == EEXIST) return F_status_set_error(F_directory_empty_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
@@ -1753,7 +1793,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_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == ENOTEMPTY) return F_status_set_error(F_directory_empty_not);
       if (errno == EEXIST) return F_status_set_error(F_directory_empty_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
@@ -2057,6 +2097,7 @@ extern "C" {
 #ifndef _di_f_file_stream_read_
   f_status_t f_file_stream_read(const f_file_t file, f_string_dynamic_t * const buffer) {
     #ifndef _di_level_0_parameter_checking_
+      if (!file.size_read) return F_status_set_error(F_parameter);
       if (!buffer) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
@@ -2066,13 +2107,13 @@ extern "C" {
 
     flockfile(file.stream);
 
-    if (feof(file.stream)) {
+    if (feof_unlocked(file.stream)) {
       funlockfile(file.stream);
 
       return F_none_eof;
     }
 
-    if (ferror(file.stream)) {
+    if (ferror_unlocked(file.stream)) {
       funlockfile(file.stream);
 
       return F_status_set_error(F_error);
@@ -2092,7 +2133,7 @@ extern "C" {
 
       size_read = fread_unlocked(buffer->string + buffer->used, sizeof(f_char_t), file.size_read, file.stream);
 
-      if (ferror(file.stream)) {
+      if (ferror_unlocked(file.stream)) {
         funlockfile(file.stream);
 
         if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block);
@@ -2108,7 +2149,7 @@ extern "C" {
 
       buffer->used += size_read;
 
-    } while (size_read == file.size_read && !feof(file.stream));
+    } while (size_read == file.size_read && !feof_unlocked(file.stream));
 
     funlockfile(file.stream);
 
@@ -2120,26 +2161,40 @@ extern "C" {
   f_status_t f_file_stream_read_block(const f_file_t file, f_string_dynamic_t * const buffer) {
     #ifndef _di_level_0_parameter_checking_
       if (!file.size_read) return F_status_set_error(F_parameter);
+      if (!buffer) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
     if (!file.stream) return F_status_set_error(F_file_closed);
 
-    if (feof(file.stream)) {
+    flockfile(file.stream);
+
+    if (feof_unlocked(file.stream)) {
+      funlockfile(file.stream);
+
       return F_none_eof;
     }
 
-    if (ferror(file.stream)) {
+    if (ferror_unlocked(file.stream)) {
+      funlockfile(file.stream);
+
       return F_status_set_error(F_error);
     }
 
     {
       const f_status_t status = f_string_dynamic_increase_by(file.size_read, buffer);
-      if (F_status_is_error(status)) return status;
+
+      if (F_status_is_error(status)) {
+        funlockfile(file.stream);
+
+        return status;
+      }
     }
 
-    const size_t size_read = fread(buffer->string + buffer->used, sizeof(f_char_t), file.size_read, file.stream);
+    const size_t size_read = fread_unlocked(buffer->string + buffer->used, sizeof(f_char_t), file.size_read, file.stream);
+
+    if (ferror_unlocked(file.stream)) {
+      funlockfile(file.stream);
 
-    if (ferror(file.stream)) {
       if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block);
       if (errno == EBADF) return F_status_set_error(F_file_descriptor);
       if (errno == EFAULT) return F_status_set_error(F_buffer);
@@ -2155,10 +2210,14 @@ extern "C" {
       buffer->used += size_read;
     }
 
-    if (feof(file.stream)) {
+    if (feof_unlocked(file.stream)) {
+      funlockfile(file.stream);
+
       return F_none_eof;
     }
 
+    funlockfile(file.stream);
+
     return F_none;
   }
 #endif // _di_f_file_stream_read_block_
@@ -2166,6 +2225,7 @@ extern "C" {
 #ifndef _di_f_file_stream_read_until_
   f_status_t f_file_stream_read_until(const f_file_t file, const f_array_length_t total, f_string_dynamic_t * const buffer) {
     #ifndef _di_level_0_parameter_checking_
+      if (!file.size_read) return F_status_set_error(F_parameter);
       if (!buffer) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
@@ -2173,13 +2233,13 @@ extern "C" {
 
     flockfile(file.stream);
 
-    if (feof(file.stream)) {
+    if (feof_unlocked(file.stream)) {
       funlockfile(file.stream);
 
       return F_none_eof;
     }
 
-    if (ferror(file.stream)) {
+    if (ferror_unlocked(file.stream)) {
       funlockfile(file.stream);
 
       return F_status_set_error(F_error);
@@ -2206,9 +2266,9 @@ extern "C" {
         buffer_size = total - buffer_count;
       }
 
-      size_read = fread(buffer->string + buffer->used, sizeof(f_char_t), file.size_read, file.stream);
+      size_read = fread_unlocked(buffer->string + buffer->used, sizeof(f_char_t), file.size_read, file.stream);
 
-      if (ferror(file.stream)) {
+      if (ferror_unlocked(file.stream)) {
         funlockfile(file.stream);
 
         if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block);
@@ -2224,7 +2284,7 @@ extern "C" {
 
       buffer->used += size_read;
 
-      if (feof(file.stream)) {
+      if (feof_unlocked(file.stream)) {
         funlockfile(file.stream);
 
         return F_none_eof;
@@ -2394,7 +2454,6 @@ extern "C" {
   f_status_t f_file_stream_write_until(const f_file_t file, const f_string_static_t buffer, const f_array_length_t total, f_array_length_t * const written) {
     #ifndef _di_level_0_parameter_checking_
       if (!file.size_write) return F_status_set_error(F_parameter);
-      if (!total) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
     if (!file.stream) {
@@ -2454,14 +2513,13 @@ extern "C" {
   f_status_t f_file_stream_write_range(const f_file_t file, const f_string_static_t buffer, const f_string_range_t range, f_array_length_t * const written) {
     #ifndef _di_level_0_parameter_checking_
       if (!file.size_write) return F_status_set_error(F_parameter);
-      if (range.start >= buffer.used) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
     if (!file.stream) {
       return F_status_set_error(F_file_closed);
     }
 
-    if (!buffer.used || range.start >= buffer.used) {
+    if (!buffer.used || range.start > range.stop || range.start >= buffer.used) {
       if (written) {
         *written = 0;
       }
@@ -2481,8 +2539,12 @@ extern "C" {
     if (written) {
       const f_string_static_t buffer_adjusted = macro_f_string_static_t_initialize(buffer.string + range.start, 0, buffer.used - range.start);
 
+      flockfile(file.stream);
+
       private_f_file_stream_write_until(file, buffer_adjusted, write_max, written);
 
+      funlockfile(file.stream);
+
       if (status == F_none) {
         if (range.start + *written == buffer.used) {
           return F_none_stop;
@@ -2497,8 +2559,12 @@ extern "C" {
       const f_string_static_t buffer_adjusted = macro_f_string_static_t_initialize(buffer.string + range.start, 0, buffer.used - range.start);
       f_array_length_t written_local = 0;
 
+      flockfile(file.stream);
+
       private_f_file_stream_write_until(file, buffer_adjusted, write_max, &written_local);
 
+      funlockfile(file.stream);
+
       if (status == F_none) {
         if (range.start + written_local == buffer.used) {
           return F_none_eos;
@@ -2544,7 +2610,7 @@ extern "C" {
       if (errno == ELOOP) return F_status_set_error(F_loop);
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       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_directory_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
       if (errno == ESRCH) return  F_status_set_error(F_search);
@@ -2584,7 +2650,7 @@ extern "C" {
       if (errno == ELOOP) return F_status_set_error(F_loop);
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       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_directory_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
       if (errno == ESRCH) return  F_status_set_error(F_search);
@@ -2615,7 +2681,7 @@ extern "C" {
       if (errno == EFAULT) return F_status_set_error(F_buffer);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
       if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       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);
@@ -2648,7 +2714,7 @@ extern "C" {
       if (errno == EFAULT) return F_status_set_error(F_buffer);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
       if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       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);
@@ -2847,14 +2913,13 @@ extern "C" {
   f_status_t f_file_write_range(const f_file_t file, const f_string_static_t buffer, const f_string_range_t range, f_array_length_t * const written) {
     #ifndef _di_level_0_parameter_checking_
       if (!file.size_write) return F_status_set_error(F_parameter);
-      if (range.start >= buffer.used) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
     if (file.id == -1) {
       return F_status_set_error(F_file_closed);
     }
 
-    if (!buffer.used || range.start >= buffer.used) {
+    if (!buffer.used || range.start > range.stop || range.start >= buffer.used) {
       if (written) {
         *written = 0;
       }
index 98a9c0544ffb875433dbd8e46f53c77fe0c4d1a9..bf16a02084cbed92d1e132898eb3c8398e6e2890 100644 (file)
@@ -47,30 +47,77 @@ extern "C" {
 /**
  * Check if a file can be accessed.
  *
+ * Do not use this to check file access before immediately attempting to open a file due to the possibility that the permissions change between this call and the open call.
+ * Instead, use the f_file_open() directly.
+ *
+ * The access() method always follows symbolic links, so if a symbolic link itself needs to be checked, instead use f_file_access_at() with the AT_SYMLINK_NOFOLLOW flag.
+ *
  * @param path
  *   The path file name.
+ * @param mode
+ *   The file mode to check access of.
  *
  * @return
- *   F_true if file exists.
- *   F_false if file does not exist.
+ *   F_true if requested access is allowed.
+ *   F_false if requested access is denied.
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) on access denied.
- *   F_directory (with error bit) on invalid directory.
- *   F_false (with error bit) on unknown/unhandled errors.
+ *   F_directory_not (with error bit) on invalid directory.
+ *   F_file_not (with error bit) the file does not exist.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
  *   F_name (with error bit) on path name error.
  *   F_number_overflow (with error bit) on overflow error.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
+ *   F_failure (with error bit) for any other failure.
+ *
  * @see access()
  */
 #ifndef _di_f_file_access_
-  extern f_status_t f_file_access(const f_string_static_t path);
+  extern f_status_t f_file_access(const f_string_static_t path, const int mode);
 #endif // _di_f_file_access_
 
 /**
+ * Check if a file can be accessed.
+ *
+ * Do not use this to check file access before immediately attempting to open a file due to the possibility that the permissions change between this call and the open call.
+ * Instead, use the f_file_open() directly.
+ *
+ * @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 mode
+ *   The file mode to check access of.
+ * @param flag
+ *   Options to control how this operates.
+ *
+ * @return
+ *   F_true if requested access is allowed.
+ *   F_false if requested access is denied.
+ *   F_data_not if path.used is 0.
+ *
+ *   F_access_denied (with error bit) on access denied.
+ *   F_directory_not (with error bit) on invalid directory.
+ *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
+ *   F_file_not (with error bit) the file does not exist.
+ *   F_loop (with error bit) on loop error.
+ *   F_memory_not (with error bit) if out of memory.
+ *   F_name (with error bit) on path name error.
+ *   F_number_overflow (with error bit) on overflow error.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *
+ *   F_failure (with error bit) for any other failure.
+ *
+ * @see faccessat()
+ */
+#ifndef _di_f_file_access_at_
+  extern f_status_t f_file_access_at(const int at_id, const f_string_static_t path, const int mode, const int flag);
+#endif // _di_f_file_access_at_
+
+/**
  * 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.
@@ -104,7 +151,7 @@ extern "C" {
  *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
  *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_file_open_max (with error bit) when system-wide max open files is reached.
  *   F_file_read (with error bit) on file read error.
@@ -208,7 +255,7 @@ extern "C" {
  *
  *   F_access_denied (with error bit) on access denied.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_file_open_max (with error bit) when system-wide max open files is reached.
  *   F_file_read (with error bit) on file read error.
@@ -249,7 +296,7 @@ extern "C" {
  *
  *   F_access_denied (with error bit) on access denied.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_file_open_max (with error bit) when system-wide max open files is reached.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
@@ -291,7 +338,7 @@ extern "C" {
  *
  *   F_access_denied (with error bit) on access denied.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_file_open_max (with error bit) when system-wide max open files is reached.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
@@ -333,7 +380,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) on access denied.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
  *   F_loop (with error bit) on loop error.
@@ -375,7 +422,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) on access denied.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
@@ -408,7 +455,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) on access denied.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or ififos are exhausted.
  *   F_loop (with error bit) on loop error.
@@ -441,7 +488,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) on access denied.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or ififos are exhausted.
@@ -476,7 +523,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) on access denied.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
  *   F_loop (with error bit) on loop error.
@@ -512,7 +559,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) on access denied.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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.
  *   F_file_found (with error bit) if a file was found while exclusive is TRUE.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
@@ -564,7 +611,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
  *   F_name (with error bit) on path name error.
@@ -596,7 +643,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) on access denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_false (with error bit) on unknown/unhandled errors.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -646,7 +693,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -681,7 +728,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
  *   F_name (with error bit) on path name error.
@@ -713,7 +760,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
  *   F_name (with error bit) on path name error.
@@ -747,7 +794,7 @@ extern "C" {
  *   F_file_found (with error bit) if a file aleady exists at the path.
  *   F_file_found_not (with error bit) if a parent path in point does not exist or is a broken symlink.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_interrupt (with error bit) when program received an interrupt signal, halting operation.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -784,7 +831,7 @@ extern "C" {
  *   F_access_denied (with error bit) on access denied.
  *   F_busy (with error bit) if file system is too busy to perform write.
  *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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.
  *   F_file_found (with error bit) if a file aleady exists at the path.
  *   F_file_found_not (with error bit) if a parent path in point does not exist or is a broken symlink.
@@ -822,7 +869,7 @@ extern "C" {
  *   F_access_denied (with error bit) on access denied.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found (with error bit) if a file aleady exists at the path.
  *   F_file_found_not (with error bit) if a parent path in point does not exist or is a broken symlink.
  *   F_filesystem_quota_block (with error bit) if file system's disk blocks or inodes are exhausted.
@@ -865,7 +912,7 @@ extern "C" {
  *   F_access_denied (with error bit) on access denied.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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.
  *   F_file_found (with error bit) if a file aleady exists at the path.
  *   F_file_found_not (with error bit) if a parent path in point does not exist or is a broken symlink.
@@ -906,7 +953,7 @@ extern "C" {
  *
  *   F_access_denied (with error bit) on access denied.
  *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found_not (with error bit) if the file at path was not found.
  *   F_input_output (with error bit) on I/O error.
  *   F_loop (with error bit) on loop error.
@@ -944,7 +991,7 @@ extern "C" {
  *
  *   F_access_denied (with error bit) on access denied.
  *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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.
  *   F_file_found_not (with error bit) if the file at path was not found.
  *   F_input_output (with error bit) on I/O error.
@@ -1094,7 +1141,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1123,7 +1170,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1154,7 +1201,7 @@ extern "C" {
  *
  *   F_access_denied (with error bit) on access denied.
  *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if file at path was not found.
  *   F_input_output (with error bit) on I/O error.
  *   F_loop (with error bit) on loop error.
@@ -1190,7 +1237,7 @@ extern "C" {
  *   F_access_denied (with error bit) on access denied.
  *   F_access_mode (with error bit) if the current user does not have access to assign the file mode.
  *   F_file_found_not (with error bit) if file at path was not found.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_input_output (with error bit) on I/O error.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1306,6 +1353,7 @@ extern "C" {
  *   F_access_denied (with error bit) on access denied.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_busy (with error bit) if file system is too busy to perform write.
+ *   F_directory (with error bit) if path is a directory and is unable to access a directory (read, write, already exists, etc.. depending on requested open action).
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_file_open_max (with error bit) when system-wide max open files is reached.
  *   F_file_type_not_directory (with error bit) if F_NOTIFY was specified and file.id is not a directory.
@@ -1372,7 +1420,7 @@ extern "C" {
  *   F_data_not if path.used is 0.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1499,7 +1547,7 @@ extern "C" {
  *
  *   F_access_denied (with error bit) on access denied.
  *   F_busy (with error bit) if file is busy.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found_not (with error bit) if file not found.
  *   F_file_type_directory (with error bit) file is a directory (directories cannot be removed via this function).
  *   F_input_output (with error bit) if an I/O error occurred.
@@ -1532,7 +1580,7 @@ extern "C" {
  *
  *   F_access_denied (with error bit) on access denied.
  *   F_busy (with error bit) if file is busy.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_file_found_not (with error bit) if file not found.
  *   F_file_type_directory (with error bit) file is a directory (directories cannot be removed via this function).
  *   F_input_output (with error bit) if an I/O error occurred.
@@ -1573,7 +1621,7 @@ extern "C" {
  *   F_access_denied (with error bit) on access denied.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (with error bit) if a supposed directory in path is not actually a directory.
  *   F_directory_empty_not (with error bit) if the destination is a non-empty directory.
  *   F_file_found_not (with error bit) if file at path was not found.
  *   F_file_type_directory (with error bit) if destination is a directory but source is not.
@@ -1622,7 +1670,7 @@ extern "C" {
  *   F_access_denied (with error bit) on access denied.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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 or to_id.
  *   F_directory_empty_not (with error bit) if the destination is a non-empty directory.
  *   F_file_found_not (with error bit) if file at path was not found.
@@ -1668,7 +1716,7 @@ extern "C" {
  *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
  *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
  *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if file at path was not found.
  *   F_input_output (with error bit) on I/O error.
  *   F_loop (with error bit) on loop error.
@@ -1709,7 +1757,7 @@ extern "C" {
  *   F_access_group (with error bit) if the current user does not have access to assign the specified group.
  *   F_access_owner (with error bit) if the current user does not have access to assign the specified owner.
  *   F_buffer (with error bit) if the buffer is invalid.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_directory_descriptor (with error bit) for bad directory descriptor for at_id.
  *   F_file_found_not (with error bit) if file at path was not found.
  *   F_input_output (with error bit) on I/O error.
@@ -1770,7 +1818,7 @@ extern "C" {
  *   F_none on success.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1801,7 +1849,7 @@ extern "C" {
  *   F_none on success.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1827,7 +1875,7 @@ extern "C" {
  *   F_none on success.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1856,7 +1904,7 @@ extern "C" {
  *   F_none on success.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1886,7 +1934,7 @@ extern "C" {
  *   F_none on success.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -1912,7 +1960,7 @@ extern "C" {
  *   F_none on success.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_file_found_not (with error bit) if the file was not found.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
@@ -2226,6 +2274,7 @@ extern "C" {
  * @return
  *   F_none on success.
  *   F_none_stop on success but no data was written (written == 0) (not an error and often happens if file type is not a regular file).
+ *   F_data_not on success but buffer.used is 0.
  *
  *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
  *   F_buffer (with error bit) if the buffer is invalid.
@@ -2260,6 +2309,7 @@ extern "C" {
  * @return
  *   F_none on success.
  *   F_none_stop on success but no data was written (written == 0) (not an error and often happens if file type is not a regular file).
+ *   F_data_not on success but buffer.used is 0.
  *
  *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
  *   F_buffer (with error bit) if the buffer is invalid.
@@ -2295,6 +2345,7 @@ extern "C" {
  *   F_none on success.
  *   F_none_stop on success but no data was written (written == 0) (not an error and often happens if file type is not a regular file).
  *   F_none_eos on success but range.stop exceeded buffer.used (only wrote up to buffer.used).
+ *   F_data_not on success but either buffer.used or total is 0.
  *
  *   F_block (with error bit) if file descriptor is set to non-block and the write would result in a blocking operation.
  *   F_buffer (with error bit) if the buffer is invalid.
@@ -2339,7 +2390,7 @@ extern "C" {
  *   F_interrupt (with error bit) if interrupt was received.
  *   F_parameter (with error bit) if a parameter is invalid.
  *
- * @see fwrite()
+ * @see fwrite_unlocked()
  */
 #ifndef _di_f_file_stream_write_range_
   extern f_status_t f_file_stream_write_range(const f_file_t file, const f_string_static_t buffer, const f_string_range_t range, f_array_length_t * const written);
@@ -2365,7 +2416,7 @@ extern "C" {
  *   F_access_denied (with error bit) on access denied.
  *   F_buffer (with error bit) if the buffer is invalid.
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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.
  *   F_file_found (with error bit) if a file aleady exists at the path.
  *   F_file_open_max (with error bit) when system-wide max open files is reached.
@@ -2408,7 +2459,7 @@ extern "C" {
  *   F_buffer (with error bit) if the buffer is invalid.
  *
  *   F_busy (with error bit) if file system is too busy to perform write.
- *   F_directory (with error bit) if a supposed directory in path is not actually a directory.
+ *   F_directory_not (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.
  *   F_file_found (with error bit) if a file aleady exists at the path (when calling utimensat()).
  *   F_file_open_max (with error bit) when system-wide max open files is reached.
@@ -2447,7 +2498,7 @@ extern "C" {
  *   F_file_found_not if the path was not found.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
  *   F_name (with error bit) on path name error.
@@ -2477,7 +2528,7 @@ extern "C" {
  *   F_file_found_not if the path was not found.
  *
  *   F_access_denied (with error bit) if access to the file was denied.
- *   F_directory (with error bit) on invalid directory.
+ *   F_directory_not (with error bit) on invalid directory.
  *   F_loop (with error bit) on loop error.
  *   F_memory_not (with error bit) if out of memory.
  *   F_name (with error bit) on path name error.
index 92c2b63037d2052673696683b4954d9ae87cb68e..7356b86dac8a2a90f85b60df4c04ddf84dddd02e 100644 (file)
@@ -4,7 +4,7 @@
 extern "C" {
 #endif
 
-#ifndef _di_f_file_type_
+#ifndef _di_f_file_types_
   const f_string_static_t f_file_type_name_block_s = macro_f_string_static_t_initialize(F_file_type_name_block_s, 0, F_file_type_name_block_s_length);
   const f_string_static_t f_file_type_name_character_s = macro_f_string_static_t_initialize(F_file_type_name_character_s, 0, F_file_type_name_character_s_length);
   const f_string_static_t f_file_type_name_directory_s = macro_f_string_static_t_initialize(F_file_type_name_directory_s, 0, F_file_type_name_directory_s_length);
@@ -12,14 +12,16 @@ extern "C" {
   const f_string_static_t f_file_type_name_link_s = macro_f_string_static_t_initialize(F_file_type_name_link_s, 0, F_file_type_name_link_s_length);
   const f_string_static_t f_file_type_name_regular_s = macro_f_string_static_t_initialize(F_file_type_name_regular_s, 0, F_file_type_name_regular_s_length);
   const f_string_static_t f_file_type_name_socket_s = macro_f_string_static_t_initialize(F_file_type_name_socket_s, 0, F_file_type_name_socket_s_length);
+#endif // _di_f_file_types_
 
+#ifndef _di_f_file_open_modes_
   const f_string_static_t f_file_open_mode_append_s = macro_f_string_static_t_initialize(F_file_open_mode_append_s, 0, F_file_open_mode_append_s_length);
   const f_string_static_t f_file_open_mode_read_s = macro_f_string_static_t_initialize(F_file_open_mode_read_s, 0, F_file_open_mode_read_s_length);
   const f_string_static_t f_file_open_mode_read_append_s = macro_f_string_static_t_initialize(F_file_open_mode_read_append_s, 0, F_file_open_mode_read_append_s_length);
   const f_string_static_t f_file_open_mode_read_truncate_s = macro_f_string_static_t_initialize(F_file_open_mode_read_truncate_s, 0, F_file_open_mode_read_truncate_s_length);
   const f_string_static_t f_file_open_mode_read_write_s = macro_f_string_static_t_initialize(F_file_open_mode_read_write_s, 0, F_file_open_mode_read_write_s_length);
   const f_string_static_t f_file_open_mode_truncate_s = macro_f_string_static_t_initialize(F_file_open_mode_truncate_s, 0, F_file_open_mode_truncate_s_length);
-#endif // _di_f_file_type_
+#endif // _di_f_file_open_modes_
 
 #ifndef _di_f_file_operation_strings_
   const f_string_static_t f_file_operation_access_s = macro_f_string_static_t_initialize(F_file_operation_access_s, 0, F_file_operation_access_s_length);
index 1a5f7a36a3f7837754124e22e0979bec38786e64..fb1402e53f1bc528e298b2bf668e2e8c05f19057 100644 (file)
@@ -52,15 +52,33 @@ extern "C" {
  * Provide file type macros.
  *
  * These type macros are of size 32-bit (int32_t).
+ *
+ * F_file_type_*:
+ *   - block:     The file type is a block device.
+ *   - character: The file type is a character device.
+ *   - directory: The file type is a directory.
+ *   - fifo:      The file type is a File-In-File-Out pipe.
+ *   - mask:      A mask used to get the bits of the file data representing the file type.
+ *   - link:      The file type is a file link.
+ *   - regular:   The file type is a regular file.
+ *   - socket:    The file type is a socket file.
+ *
+ * F_file_type_name_*:
+ *  - block:     A string representing the block file type.
+ *  - character: A string representing the character file type.
+ *  - directory: A string representing the directory file type.
+ *  - fifo:      A string representing the fifo file type.
+ *  - link:      A string representing the link file type.
+ *  - regular:   A string representing the regular file type.
+ *  - socket:    A string representing the socket file type.
  */
-#ifndef _di_f_file_type_
-  #define F_file_type_mask_d S_IFMT
-
+#ifndef _di_f_file_types_
   #define F_file_type_block_d     S_IFBLK
   #define F_file_type_character_d S_IFCHR
   #define F_file_type_directory_d S_IFDIR
   #define F_file_type_fifo_d      S_IFIFO
   #define F_file_type_link_d      S_IFLNK
+  #define F_file_type_mask_d      S_IFMT
   #define F_file_type_regular_d   S_IFREG
   #define F_file_type_socket_d    S_IFSOCK
 
@@ -90,6 +108,43 @@ extern "C" {
   #define macro_f_file_type_is_regular(mode)   (macro_f_file_type_get(mode) == F_file_type_regular_d)
   #define macro_f_file_type_is_socket(mode)    (macro_f_file_type_get(mode) == F_file_type_socket_d)
 
+  extern const f_string_static_t f_file_type_name_block_s;
+  extern const f_string_static_t f_file_type_name_character_s;
+  extern const f_string_static_t f_file_type_name_directory_s;
+  extern const f_string_static_t f_file_type_name_fifo_s;
+  extern const f_string_static_t f_file_type_name_link_s;
+  extern const f_string_static_t f_file_type_name_regular_s;
+  extern const f_string_static_t f_file_type_name_socket_s;
+#endif // _di_f_file_types_
+
+/**
+ * Provide macros for file access mode operations.
+ *
+ * F_file_access_mode_*:
+ *   - execute: Check if file can be executed.
+ *   - exist:   Check if file exists.
+ *   - read:    Check if file can be read.
+ *   - write:   Check if file can be written to.
+ */
+#ifndef _di_f_file_access_modes_
+  #define F_file_access_mode_execute_d X_OK
+  #define F_file_access_mode_exist_d   F_OK
+  #define F_file_access_mode_read_d    R_OK
+  #define F_file_access_mode_write_d   W_OK
+#endif // _di_f_file_access_modes_
+
+/**
+ * Provide file open mode macros.
+ *
+ * F_file_open_mode_*:
+ *   - append:        Open file in append mode.
+ *   - read:          Open file in read only mode.
+ *   - read_append:   Open file in read append mode.
+ *   - read_truncate: Open file in read truncate mode.
+ *   - read_write:    Open file in read write mode.
+ *   - truncate:      Open file in truncate mode.
+ */
+#ifndef _di_f_file_open_modes_
   #define F_file_open_mode_append_s        "a"
   #define F_file_open_mode_read_s          "r"
   #define F_file_open_mode_read_append_s   "a+"
@@ -104,21 +159,13 @@ extern "C" {
   #define F_file_open_mode_read_write_s_length    2
   #define F_file_open_mode_truncate_s_length      1
 
-  extern const f_string_static_t f_file_type_name_block_s;
-  extern const f_string_static_t f_file_type_name_character_s;
-  extern const f_string_static_t f_file_type_name_directory_s;
-  extern const f_string_static_t f_file_type_name_fifo_s;
-  extern const f_string_static_t f_file_type_name_link_s;
-  extern const f_string_static_t f_file_type_name_regular_s;
-  extern const f_string_static_t f_file_type_name_socket_s;
-
   extern const f_string_static_t f_file_open_mode_append_s;
   extern const f_string_static_t f_file_open_mode_read_s;
   extern const f_string_static_t f_file_open_mode_read_append_s;
   extern const f_string_static_t f_file_open_mode_read_truncate_s;
   extern const f_string_static_t f_file_open_mode_read_write_s;
   extern const f_string_static_t f_file_open_mode_truncate_s;
-#endif // _di_f_file_type_
+#endif // _di_f_file_open_modes_
 
 /**
  * Commonly used file related properties.
index 6a9394409566808ddc0d9f24adb6c31390819d1c..0bb1ef8b5346fe6204a938755207be4e8d1b159e 100644 (file)
@@ -24,10 +24,10 @@ extern "C" {
       }
 
       if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
       if (errno == EINTR) return F_status_set_error(F_interrupt);
       if (errno == EIO) return F_status_set_error(F_input_output);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
 
       return F_status_set_error(F_file_close);
     }
@@ -64,7 +64,7 @@ extern "C" {
 
     memset(buffer, 0, sizeof(f_char_t) * size_block);
 
-    while ((size_read = read(file_source.id, buffer, size_block)) > 0) {
+    while ((size_read = read(file_source.id, buffer, size_block)) > (ssize_t) 0) {
 
       size_write = write(file_destination.id, buffer, size_read);
 
@@ -193,7 +193,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_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
 
@@ -219,7 +219,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_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_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);
@@ -241,7 +241,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EPERM) return F_status_set_error(F_prohibited);
       if (errno == EROFS) return F_status_set_error(F_read_only);
 
@@ -257,15 +257,15 @@ extern "C" {
 
     if (mkfifoat(at_id, path.string, mode) < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
       if (errno == EEXIST) return F_status_set_error(F_file_found);
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_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);
     }
@@ -281,14 +281,14 @@ extern "C" {
       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);
-      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       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 == ENAMETOOLONG) return F_status_set_error(F_name);
       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_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_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);
@@ -305,17 +305,17 @@ extern "C" {
 
     if (mknodat(at_id, path.string, mode, device) < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
       if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
       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) 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_directory_descriptor);
+      if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       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_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_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);
@@ -349,10 +349,10 @@ extern "C" {
 
     if (symlink(target.string, point.string) < 0) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
-      if (errno == EFBIG || errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
       if (errno == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
       if (errno == EEXIST) return F_status_set_error(F_file_found);
       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_interrupt);
       if (errno == EINVAL) return F_status_set_error(F_parameter);
       if (errno == ELOOP) return F_status_set_error(F_loop);
@@ -360,7 +360,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_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_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);
@@ -389,7 +389,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_not);
       if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_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);
@@ -427,7 +427,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
 
       return F_status_set_error(F_failure);
     }
@@ -463,7 +463,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
 
       return F_status_set_error(F_failure);
     }
@@ -483,7 +483,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EPERM) return F_status_set_error(F_access_mode);
       if (errno == EROFS) return F_status_set_error(F_read_only);
 
@@ -506,7 +506,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EPERM) return F_status_set_error(F_access_mode);
       if (errno == EROFS) return F_status_set_error(F_read_only);
 
@@ -520,19 +520,14 @@ extern "C" {
 #if !defined(_di_f_file_open_) || !defined(_di_f_file_copy_)
   f_status_t private_f_file_open(const f_string_static_t path, const mode_t mode, f_file_t * const file) {
 
-    if (!mode) {
-      file->id = open(path.string, file->flag);
-    }
-    else {
-      file->id = open(path.string, file->flag, mode);
-    }
+    file->id = open(path.string, file->flag, mode);
 
     if (file->id == -1) {
       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);
       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 == EDQUOT) return F_status_set_error(F_filesystem_quota_block);
       if (errno == EINTR) return F_status_set_error(F_interrupt);
       if (errno == EINVAL) return F_status_set_error(F_parameter);
       if (errno == EISDIR) return F_status_set_error(F_directory);
@@ -558,12 +553,7 @@ extern "C" {
 #if !defined(_di_f_file_open_at_) || !defined(_di_f_file_copy_at_)
   f_status_t private_f_file_open_at(const int at_id, const f_string_static_t path, const mode_t mode, f_file_t * const file) {
 
-    if (!mode) {
-      file->id = openat(at_id, path.string, file->flag);
-    }
-    else {
-      file->id = openat(at_id, path.string, file->flag, mode);
-    }
+    file->id = openat(at_id, path.string, file->flag, mode);
 
     if (file->id == -1) {
       if (errno == EACCES) return F_status_set_error(F_access_denied);
@@ -625,7 +615,7 @@ extern "C" {
         }
       }
 
-      if (gid != -1) {
+      if (result == 0 && gid != -1) {
         result = lchown(path.string, -1, gid);
 
         if (result < 0 && errno == EPERM) {
@@ -642,7 +632,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EROFS) return F_status_set_error(F_read_only);
 
       return F_status_set_error(F_failure);
@@ -682,7 +672,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EROFS) return F_status_set_error(F_read_only);
 
       return F_status_set_error(F_failure);
@@ -702,7 +692,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
 
       return F_status_set_error(F_file_stat);
@@ -723,7 +713,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_status_set_error(F_file_found_not);
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
 
       return F_status_set_error(F_file_stat);
@@ -745,7 +735,7 @@ extern "C" {
       if (errno == ENAMETOOLONG) return F_status_set_error(F_name);
       if (errno == ENOENT) return F_file_found_not;
       if (errno == ENOMEM) return F_status_set_error(F_memory_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_directory);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
       if (errno == EOVERFLOW) return F_status_set_error(F_number_overflow);
 
       return F_status_set_error(F_file_stat);
@@ -809,7 +799,7 @@ extern "C" {
 
     while (*written < write_max) {
 
-      size_write = fwrite(buffer.string + *written, write_amount, write_size, file.stream);
+      size_write = fwrite_unlocked(buffer.string + *written, write_amount, write_size, file.stream);
 
       if (size_write < 0) {
         if (errno == EAGAIN || errno == EWOULDBLOCK) return F_status_set_error(F_block);