]> Kevux Git Server - fll/commitdiff
Feature: Add f_file_manipulate() as a wrapper for fcntl().
authorKevin Day <kevin@kevux.org>
Wed, 21 Jun 2023 01:54:31 +0000 (20:54 -0500)
committerKevin Day <kevin@kevux.org>
Wed, 21 Jun 2023 01:54:31 +0000 (20:54 -0500)
This also adds the unit tests.
The unit tests includes additional fixes where several of the wrapped functions are not being setup properly.
The fact that has not triggered an error in the past is concerning.

level_0/f_file/c/file.c
level_0/f_file/c/file.h
level_0/f_file/data/build/settings-mocks
level_0/f_file/data/build/settings-tests
level_0/f_file/tests/unit/c/mock-file.c
level_0/f_file/tests/unit/c/mock-file.h
level_0/f_file/tests/unit/c/test-file-manipulate.c [new file with mode: 0644]
level_0/f_file/tests/unit/c/test-file-manipulate.h [new file with mode: 0644]
level_0/f_file/tests/unit/c/test-file.c
level_0/f_file/tests/unit/c/test-file.h

index 5f9a499..f845275 100644 (file)
@@ -628,6 +628,32 @@ extern "C" {
   }
 #endif // _di_f_file_link_read_at_
 
+#ifndef _di_f_file_manipulate_
+  f_status_t f_file_manipulate(const f_file_t file, const int command, const long argument) {
+
+    if (file.id == -1) return F_file_descriptor_not;
+
+    if (fcntl(file.id, command, argument) == -1) {
+      if (errno == EACCES) return F_status_set_error(F_access_denied);
+      if (errno == EAGAIN) return F_status_set_error(F_again);
+      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+      if (errno == EBUSY) return F_status_set_error(F_busy);
+      if (errno == EDEADLK) return F_status_set_error(F_deadlock);
+      if (errno == EFAULT) return F_status_set_error(F_buffer);
+      if (errno == EINTR) return F_status_set_error(F_interrupt);
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+      if (errno == ENOLCK) return F_status_set_error(F_lock);
+      if (errno == ENOTDIR) return F_status_set_error(F_directory_not);
+      if (errno == EPERM) return F_status_set_error(F_prohibited);
+
+      return F_status_set_error(F_failure);
+    }
+
+    return F_none;
+  }
+#endif // _di_f_file_manipulate_
+
 #ifndef _di_f_file_mode_determine_
   f_status_t f_file_mode_determine(const mode_t mode_file, const f_file_mode_t mode_change, const uint8_t mode_replace, const bool directory_is, mode_t *mode) {
     #ifndef _di_level_0_parameter_checking_
index 9f5fafa..b770f84 100644 (file)
@@ -1045,6 +1045,42 @@ extern "C" {
   extern f_status_t f_file_link_read_at(const f_file_t directory, const f_string_static_t path, const int flag, f_string_dynamic_t * const target);
 #endif // _di_f_file_link_read_at_
 
+/**
+ * Manipulate the file by the file descriptor.
+ *
+ * @param file
+ *   The data related to the file containing the file descriptor.
+ *   The file descriptor is required to be valid.
+ * @param command
+ *   The command to perform.
+ *   See fcntl() for details.
+ * @param argument
+ *   An argument associated with the command.
+ *   See fcntl() for details.
+ *
+ * @return
+ *   F_none on success.
+ *
+ *   F_access_denied (with error bit) on access denied (due to locks being held by other processes).
+ *   F_again (with error bit) on operation on file is prohibited (often due to file being memory mapped by another process).
+ *   F_buffer (with error bit) if the buffer is invalid.
+ *   F_busy (with error bit) if system is too busy to perform operation.
+ *   F_deadlock (with error bit) if operation would cause a deadlock.
+ *   F_directory_not (with error bit) on invalid directory.
+ *   F_file_descriptor (with error bit) if file descriptor is invalid.
+ *   F_file_descriptor_max (with error bit) if max file descriptors is reached.
+ *   F_interrupt (with error bit) when program received an interrupt signal, halting operation.
+ *   F_lock (with error bit) if failed to lock, such as lock table is full or too many open segments.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_prohibited (with error bit) if operation is prohibited (maps to EPERM).
+ *   F_failure (with error bit) for any other error.
+ *
+ * @see fcntl()
+ */
+#ifndef _di_f_file_manipulate_
+  extern f_status_t f_file_manipulate(const f_file_t file, const int command, const long argument);
+#endif // _di_f_file_manipulate_
+
 /**
  * Determine how the mode should be applied based on different file properties and the given mode properties.
  *
index 33eb429..3b46a39 100644 (file)
@@ -63,18 +63,21 @@ flags -Wl,--wrap=chmod
 flags -Wl,--wrap=chown
 flags -Wl,--wrap=close
 flags -Wl,--wrap=faccessat
+flags -Wl,--wrap=fchmod
 flags -Wl,--wrap=fchmodat
+flags -Wl,--wrap=fchown
 flags -Wl,--wrap=fchownat
 flags -Wl,--wrap=fclose
+flags -Wl,--wrap=fopen
 flags -Wl,--wrap=fdopen
+flags -Wl,--wrap=freopen
 flags -Wl,--wrap=feof_unlocked
 flags -Wl,--wrap=ferror_unlocked
 flags -Wl,--wrap=fflush
 flags -Wl,--wrap=fileno
 flags -Wl,--wrap=flockfile
-flags -Wl,--wrap=fopen
+flags -Wl,--wrap=fcntl
 flags -Wl,--wrap=fread_unlocked
-flags -Wl,--wrap=freopen
 flags -Wl,--wrap=fstat
 flags -Wl,--wrap=fstatat
 flags -Wl,--wrap=fsync
@@ -85,7 +88,6 @@ flags -Wl,--wrap=link
 flags -Wl,--wrap=linkat
 flags -Wl,--wrap=lseek
 flags -Wl,--wrap=lstat
-flags -Wl,--wrap=makedev
 flags -Wl,--wrap=mkdir
 flags -Wl,--wrap=mkdirat
 flags -Wl,--wrap=mkfifo
@@ -100,12 +102,11 @@ flags -Wl,--wrap=readlinkat
 flags -Wl,--wrap=rename
 flags -Wl,--wrap=renameat
 flags -Wl,--wrap=renameat2
-flags -Wl,--wrap=remove
 flags -Wl,--wrap=stat
 flags -Wl,--wrap=symlink
 flags -Wl,--wrap=symlinkat
 flags -Wl,--wrap=unlink
 flags -Wl,--wrap=unlinkat
-flags -Wl,--wrap=utimensat
 flags -Wl,--wrap=umask
+flags -Wl,--wrap=utimensat
 flags -Wl,--wrap=write
index a382816..7bb518a 100644 (file)
@@ -25,7 +25,7 @@ build_language c
 build_libraries -lc -lcmocka
 build_libraries-individual -lf_memory -lf_string -lf_file
 
-build_sources_program test-file-access.c test-file-access_at.c test-file-clone.c test-file-close.c test-file-copy.c test-file-create.c test-file-create_at.c test-file-create_device.c test-file-create_device_at.c test-file-create_fifo.c test-file-create_fifo_at.c test-file-create_node.c test-file-create_node_at.c test-file-descriptor.c test-file-exists.c test-file-exists_at.c test-file-flush.c test-file-group_read.c test-file-is.c test-file-is_at.c test-file-is_stat.c test-file-link.c test-file-link_at.c test-file-link_hard.c test-file-link_hard_at.c test-file-link_read.c test-file-link_read_at.c test-file-mode_determine.c test-file-mode_from_string.c test-file-mode_read.c test-file-mode_read_at.c test-file-mode_set.c test-file-mode_set_at.c test-file-mode_to_mode.c test-file-name_base.c test-file-name_directory.c test-file-open.c test-file-open_at.c test-file-owner_read.c test-file-read.c test-file-read_block.c test-file-read_until.c test-file-remove.c test-file-remove_at.c test-file-rename.c test-file-rename_at.c test-file-role_change.c test-file-role_change_at.c test-file-seek.c test-file-size.c test-file-size_at.c test-file-size_by_id.c test-file-stat.c test-file-stat_at.c test-file-stat_by_id.c test-file-stream_close.c test-file-stream_open_descriptor.c test-file-stream_open.c test-file-stream_read.c test-file-stream_read_block.c test-file-stream_read_until.c test-file-stream_reopen.c test-file-stream_write.c test-file-stream_write_block.c test-file-stream_write_until.c test-file-stream_write_range.c test-file-touch.c test-file-touch_at.c test-file-type.c test-file-type_at.c test-file-umask_get.c test-file-umask_set.c test-file-write.c test-file-write_block.c test-file-write_until.c test-file-write_range.c
+build_sources_program test-file-access.c test-file-access_at.c test-file-clone.c test-file-close.c test-file-copy.c test-file-create.c test-file-create_at.c test-file-create_device.c test-file-create_device_at.c test-file-create_fifo.c test-file-create_fifo_at.c test-file-create_node.c test-file-create_node_at.c test-file-descriptor.c test-file-exists.c test-file-exists_at.c test-file-flush.c test-file-group_read.c test-file-is.c test-file-is_at.c test-file-is_stat.c test-file-link.c test-file-link_at.c test-file-link_hard.c test-file-link_hard_at.c test-file-link_read.c test-file-link_read_at.c test-file-manipulate.c test-file-mode_determine.c test-file-mode_from_string.c test-file-mode_read.c test-file-mode_read_at.c test-file-mode_set.c test-file-mode_set_at.c test-file-mode_to_mode.c test-file-name_base.c test-file-name_directory.c test-file-open.c test-file-open_at.c test-file-owner_read.c test-file-read.c test-file-read_block.c test-file-read_until.c test-file-remove.c test-file-remove_at.c test-file-rename.c test-file-rename_at.c test-file-role_change.c test-file-role_change_at.c test-file-seek.c test-file-size.c test-file-size_at.c test-file-size_by_id.c test-file-stat.c test-file-stat_at.c test-file-stat_by_id.c test-file-stream_close.c test-file-stream_open_descriptor.c test-file-stream_open.c test-file-stream_read.c test-file-stream_read_block.c test-file-stream_read_until.c test-file-stream_reopen.c test-file-stream_write.c test-file-stream_write_block.c test-file-stream_write_until.c test-file-stream_write_range.c test-file-touch.c test-file-touch_at.c test-file-type.c test-file-type_at.c test-file-umask_get.c test-file-umask_set.c test-file-write.c test-file-write_block.c test-file-write_until.c test-file-write_range.c
 build_sources_program test-file.c
 
 build_script no
index d929dcb..1aa8aba 100644 (file)
@@ -205,6 +205,19 @@ void __wrap_flockfile(FILE *filehandle) {
 
 }
 
+int __wrap_fcntl(int fd, int cmd, ...) {
+
+  const bool failure = mock_type(bool);
+
+  if (failure) {
+    errno = mock_type(int);
+
+    return -1;
+  }
+
+  return 0;
+}
+
 size_t __wrap_fread_unlocked(void *ptr, size_t size, size_t nmemb, FILE *stream) {
 
   return mock_type(int);
index 0862c8c..7b876f9 100644 (file)
@@ -46,6 +46,7 @@ extern int __wrap_ferror_unlocked(FILE *stream);
 extern int __wrap_fflush(FILE *stream);
 extern int __wrap_fileno(FILE *stream);
 extern void __wrap_flockfile(FILE *filehandle);
+extern int __wrap_fcntl(int fd, int cmd, ...);
 extern size_t __wrap_fread_unlocked(void *ptr, size_t size, size_t nmemb, FILE *stream);
 extern int __wrap_fstat(int fd, struct stat *statbuf);
 extern int __wrap_fstatat(int dirfd, const char *pathname, struct stat *statbuf, int flags);
diff --git a/level_0/f_file/tests/unit/c/test-file-manipulate.c b/level_0/f_file/tests/unit/c/test-file-manipulate.c
new file mode 100644 (file)
index 0000000..0b09ce1
--- /dev/null
@@ -0,0 +1,84 @@
+#include "test-file.h"
+#include "test-file-manipulate.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_file_manipulate__fails(void **state) {
+
+  const f_file_t file = macro_f_file_t_initialize_2(F_type_output_d, F_type_descriptor_output_d, F_file_flag_write_only_d);
+
+  {
+    int errnos[] = {
+      EACCES,
+      EAGAIN,
+      EBADF,
+      EBUSY,
+      EDEADLK,
+      EFAULT,
+      EINTR,
+      EINVAL,
+      EMFILE,
+      ENOLCK,
+      ENOTDIR,
+      EPERM,
+      mock_errno_generic,
+    };
+
+    f_status_t statuss[] = {
+      F_access_denied,
+      F_again,
+      F_file_descriptor,
+      F_busy,
+      F_deadlock,
+      F_buffer,
+      F_interrupt,
+      F_parameter,
+      F_file_descriptor_max,
+      F_lock,
+      F_directory_not,
+      F_prohibited,
+      F_failure,
+    };
+
+    for (int i = 0; i < 13; ++i) {
+
+      will_return(__wrap_fcntl, true);
+      will_return(__wrap_fcntl, errnos[i]);
+
+      const f_status_t status = f_file_manipulate(file, 0, 0);
+
+      assert_int_equal(status, F_status_set_error(statuss[i]));
+    } // for
+  }
+}
+
+void test__f_file_manipulate__returns_file_descriptor_not(void **state) {
+
+  const f_file_t file = macro_f_file_t_initialize_2(F_type_output_d, -1, F_file_flag_write_only_d);
+
+  {
+    const f_status_t status = f_file_manipulate(file, 0, 0);
+
+    assert_int_equal(status, F_file_descriptor_not);
+  }
+}
+
+void test__f_file_manipulate__works(void **state) {
+
+  const f_file_t file = macro_f_file_t_initialize_2(F_type_output_d, F_type_descriptor_output_d, F_file_flag_write_only_d);
+
+  {
+
+    will_return(__wrap_fcntl, false);
+
+    const f_status_t status = f_file_manipulate(file, 0, 0);
+
+    assert_int_equal(status, F_none);
+  }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_file/tests/unit/c/test-file-manipulate.h b/level_0/f_file/tests/unit/c/test-file-manipulate.h
new file mode 100644 (file)
index 0000000..7718c17
--- /dev/null
@@ -0,0 +1,34 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: File
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the file project.
+ */
+#ifndef _TEST__F_file_manipulate_h
+#define _TEST__F_file_manipulate_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_file_manipulate()
+ */
+extern void test__f_file_manipulate__fails(void **state);
+
+/**
+ * Test that function works but the descriptor is not valid.
+ *
+ * @see f_file_manipulate()
+ */
+extern void test__f_file_manipulate__returns_file_descriptor_not(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_file_manipulate()
+ */
+extern void test__f_file_manipulate__works(void **state);
+
+#endif // _TEST__F_file_manipulate_h
index 479513b..e74a43d 100644 (file)
@@ -159,6 +159,10 @@ int main(void) {
     cmocka_unit_test(test__f_file_link_read_at__returns_file_descriptor_not),
     cmocka_unit_test(test__f_file_link_read_at__works),
 
+    cmocka_unit_test(test__f_file_manipulate__fails),
+    cmocka_unit_test(test__f_file_manipulate__returns_file_descriptor_not),
+    cmocka_unit_test(test__f_file_manipulate__works),
+
     cmocka_unit_test(test__f_file_mode_determine__works_basic),
     cmocka_unit_test(test__f_file_mode_determine__works_basic_replace),
 
@@ -397,6 +401,7 @@ int main(void) {
       // f_file_link_hard_at() doesn't use parameter checking.
       cmocka_unit_test(test__f_file_link_read__parameter_checking),
       cmocka_unit_test(test__f_file_link_read_at__parameter_checking),
+      // f_file_manipulate() doesn't use parameter checking.
       cmocka_unit_test(test__f_file_mode_determine__parameter_checking),
       cmocka_unit_test(test__f_file_mode_from_string__parameter_checking),
       cmocka_unit_test(test__f_file_mode_read__parameter_checking),
index 0b841d0..142c0d5 100644 (file)
@@ -53,6 +53,7 @@
 #include "test-file-link_hard_at.h"
 #include "test-file-link_read.h"
 #include "test-file-link_read_at.h"
+#include "test-file-manipulate.h"
 #include "test-file-mode_determine.h"
 #include "test-file-mode_from_string.h"
 #include "test-file-mode_read.h"