]> 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 5f9a499a4fd6d77aa70974ff37056041aec9fdaf..f8452751789be9553af0289983b0f59b43c34893 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 9f5fafa3e6c2125642a308ba3c40f62ea5c30bcc..b770f8446362d7dda5a1a1d8e02002a4407fe782 100644 (file)
@@ -1046,6 +1046,42 @@ extern "C" {
 #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.
  *
  * This does not set mode based on umask(), which is already applied if f_file_mode_from_string() was used to create mode_change.
index 33eb42981b1974c5fb420a8677656c397920d442..3b46a39eb7376f74a7cbab874e229b8a356122bc 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 a382816b4122f210f141a0d89e06b42810f09202..7bb518a764616bbb262ec78c1e27541f014fcf6c 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 d929dcb53ff092014b915b6d982b9f007e7296d4..1aa8aba0351f8fb72cf563f68a10493b3999d9ec 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 0862c8cc744f57248cee39f9b5f977b071321ae8..7b876f9e66dabb5d587cb4e0b32ae9a793fb06af 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 479513b4ce13bd3f4eddb4a687eb967805b2e3ba..e74a43db9ea64f38592a7e3b14615723e5a1b1aa 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 0b841d0f0e24795abff74e9894e77f8c8ae8cae9..142c0d56d4f95063d6f285ba6e6c7f565264dcb1 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"