]> Kevux Git Server - fll/commitdiff
Bugfix: invalid file descptor error on stream close.
authorKevin Day <thekevinday@gmail.com>
Sat, 17 Apr 2021 20:23:35 +0000 (15:23 -0500)
committerKevin Day <thekevinday@gmail.com>
Sat, 17 Apr 2021 20:23:35 +0000 (15:23 -0500)
This caused both flushing to fail and closing to fail.

Make flushing more flexible and more optional, expanding the close functions to be non-autoflushing and autoflushing.

The fclose() closes the file stream and therefore the descriptor will be invalid.
In this case, the descriptor need only be reset to -1.

If the stream property is not populated and "complete" is designated, then close the file by the file descriptor id.

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

index c963e6c558b5b2309674e49da84af1b33bf54deb..fa7097a079d8b6db6276f5917738d7ab7b1aa7d4 100644 (file)
@@ -85,10 +85,16 @@ extern "C" {
 
 #ifndef _di_f_file_close_
   f_status_t f_file_close(int *id) {
-    return private_f_file_close(id);
+    return private_f_file_close(F_false, id);
   }
 #endif // _di_f_file_close_
 
+#ifndef _di_f_file_close_flush_
+  f_status_t f_file_close_flush(int *id) {
+    return private_f_file_close(F_true, id);
+  }
+#endif // _di_f_file_close_flush_
+
 #ifndef _di_f_file_copy_
   f_status_t f_file_copy(const f_string_t source, const f_string_t destination, const f_mode_t mode, const f_number_unsigned_t size_block, const bool exclusive) {
     #ifndef _di_level_0_parameter_checking_
@@ -1829,33 +1835,42 @@ extern "C" {
       if (!file) return F_status_set_error(F_parameter);
     #endif // _di_level_0_parameter_checking_
 
-    if (file->stream && !fclose(file->stream)) {
-      if (errno == EACCES) return F_status_set_error(F_access_denied);
-      if (errno == EAGAIN) return F_status_set_error(F_prohibited);
-      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
-      if (errno == EFBIG) return F_status_set_error(F_file_overflow);
-      if (errno == EDEADLK) return F_status_set_error(F_deadlock);
-      if (errno == EDESTADDRREQ) return F_status_set_error(F_socket_not);
-      if (errno == EDQUOT) return F_status_set_error(F_space_not);
-      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 == EIO) return F_status_set_error(F_input_output);
-      if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
-      if (errno == ENOLCK) return F_status_set_error(F_lock);
-      if (errno == ENOSPC) return F_status_set_error(F_space_not);
-      if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory);
-      if (errno == EPERM) return F_status_set_error(F_prohibited);
-      if (errno == EPIPE) return F_status_set_error(F_pipe_not);
-      if (errno == EWOULDBLOCK) return F_status_set_error(F_block);
+    if (file->stream) {
+      if (fclose(file->stream) == EOF) {
+        if (errno == EACCES) return F_status_set_error(F_access_denied);
+        if (errno == EAGAIN) return F_status_set_error(F_prohibited);
+        if (errno == EBADF) return F_status_set_error(F_file_descriptor);
+        if (errno == EFBIG) return F_status_set_error(F_file_overflow);
+        if (errno == EDEADLK) return F_status_set_error(F_deadlock);
+        if (errno == EDESTADDRREQ) return F_status_set_error(F_socket_not);
+        if (errno == EDQUOT) return F_status_set_error(F_space_not);
+        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 == EIO) return F_status_set_error(F_input_output);
+        if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+        if (errno == ENOLCK) return F_status_set_error(F_lock);
+        if (errno == ENOSPC) return F_status_set_error(F_space_not);
+        if (errno == ENOTDIR) return F_status_set_error(F_file_type_not_directory);
+        if (errno == EPERM) return F_status_set_error(F_prohibited);
+        if (errno == EPIPE) return F_status_set_error(F_pipe_not);
+        if (errno == EWOULDBLOCK) return F_status_set_error(F_block);
 
-      return F_status_set_error(F_failure);
-    }
+        return F_status_set_error(F_failure);
+      }
 
-    file->stream = 0;
+      file->stream = 0;
+
+      // file stream will result in the file descriptor being invalid because it is already closed.
+      if (complete) {
+        file->id = -1;
+      }
+
+      return F_none;
+    }
 
     if (complete) {
-      return private_f_file_close(&file->id);
+      return private_f_file_close(F_true, &file->id);
     }
 
     return F_none;
index 6cc0435f5bd7f7e7af5d42c58b06083e9ff91b1d..f346270e636f760fa6005fc6544cf6f16f44423c 100644 (file)
@@ -125,9 +125,7 @@ extern "C" {
 /**
  * Close an open file.
  *
- * Will flush before closing.
- *
- * @todo consider making this consistent and acceptinf f_file_t instead of just the id.
+ * Will not flush before closing.
  *
  * @param id
  *   The file descriptor.
@@ -149,6 +147,30 @@ extern "C" {
 #endif // _di_f_file_close_
 
 /**
+ * Close an open file.
+ *
+ * Will flush before closing.
+ *
+ * @param id
+ *   The file descriptor.
+ *
+ * @return
+ *   F_none on success.
+ *   F_file_close (with error bit) if fclose() failed for any other reason.
+ *   F_file_descriptor (with error bit) if file descriptor is invalid.
+ *   F_file_synchronize (with error bit) on flush failure.
+ *   F_filesystem_quota_block (with error bit) if filesystem's disk blocks or inodes are exhausted.
+ *   F_input_output (with error bit) on I/O error.
+ *   F_interrupt (with error bit) when program received an interrupt signal, halting operation.
+ *   F_space_not (with error bit) if filesystem is out of space (or filesystem quota is reached).
+ *
+ * @see fclose()
+ */
+#ifndef _di_f_file_close_flush_
+  extern f_status_t f_file_close_flush(int *id);
+#endif // _di_f_file_close_flush_
+
+/**
  * Copy a file.
  *
  * The paths must not contain NULL except for the terminating NULL.
@@ -1815,8 +1837,8 @@ extern "C" {
  * Close an open file stream.
  *
  * @param complete
- *   When TRUE, will close the file descriptor as well, setting file.id is reset to -1, on success.
- *   When FALSE, will do nothing in regards to the file descriptor.
+ *   If TRUE, will close the file descriptor as well, setting file.id is reset to -1, on success.
+ *   If FALSE, will do nothing in regards to the file descriptor.
  * @param file
  *   The file information.
  *   The file.stream is set to 0, on success.
index 7e0bbb998bb5781897fb5ee9a14e03c5985e63e0..b443cac7f6e5e76fcc1ea8a8e222411051b5dd8f 100644 (file)
@@ -6,14 +6,16 @@ extern "C" {
 #endif
 
 #if !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) || !defined(_di_f_file_stream_close_)
-  f_status_t private_f_file_close(int *id) {
+  f_status_t private_f_file_close(const bool flush, int *id) {
 
-    if (*id == -1) return F_none;
+    if (id == 0 || *id == -1) return F_none;
 
-    if (F_status_is_error(private_f_file_flush(*id))) return F_status_set_error(F_file_synchronize);
+    if (flush && F_status_is_error(private_f_file_flush(*id))) {
+      return F_status_set_error(F_file_synchronize);
+    }
 
     if (close(*id) < 0) {
-      if (errno == EBADF) return F_status_set_error(F_directory_descriptor);
+      if (errno == EBADF) return F_status_set_error(F_file_descriptor);
       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);
@@ -41,7 +43,7 @@ extern "C" {
     status = private_f_file_open(destination, 0, &file_destination);
 
     if (F_status_is_error(status)) {
-      private_f_file_close(&file_source.id);
+      private_f_file_close(F_true, &file_source.id);
       return status;
     }
 
@@ -56,15 +58,15 @@ extern "C" {
       size_write = write(file_destination.id, buffer, size_read);
 
       if (size_write < 0 || size_write != size_read) {
-        private_f_file_close(&file_destination.id);
-        private_f_file_close(&file_source.id);
+        private_f_file_close(F_true, &file_destination.id);
+        private_f_file_close(F_true, &file_source.id);
 
         return F_status_set_error(F_file_write);
       }
     } // while
 
-    private_f_file_close(&file_destination.id);
-    private_f_file_close(&file_source.id);
+    private_f_file_close(F_true, &file_destination.id);
+    private_f_file_close(F_true, &file_source.id);
 
     if (size_read < 0) return F_status_set_error(F_file_read);
 
@@ -86,7 +88,7 @@ extern "C" {
     status = private_f_file_open_at(at_id, destination, 0, &file_destination);
 
     if (F_status_is_error(status)) {
-      private_f_file_close(&file_source.id);
+      private_f_file_close(F_true, &file_source.id);
       return status;
     }
 
@@ -101,15 +103,15 @@ extern "C" {
       size_write = write(file_destination.id, buffer, size_read);
 
       if (size_write < 0 || size_write != size_read) {
-        private_f_file_close(&file_destination.id);
-        private_f_file_close(&file_source.id);
+        private_f_file_close(F_true, &file_destination.id);
+        private_f_file_close(F_true, &file_source.id);
 
         return F_status_set_error(F_file_write);
       }
     } // while
 
-    private_f_file_close(&file_destination.id);
-    private_f_file_close(&file_source.id);
+    private_f_file_close(F_true, &file_destination.id);
+    private_f_file_close(F_true, &file_source.id);
 
     if (size_read < 0) return F_status_set_error(F_file_read);
 
@@ -130,7 +132,7 @@ extern "C" {
     const f_status_t status = private_f_file_open(path, mode, &file);
 
     if (file.id != -1) {
-      return private_f_file_close(&file.id);
+      return private_f_file_close(F_true, &file.id);
     }
 
     return status;
@@ -150,7 +152,7 @@ extern "C" {
     const f_status_t status = private_f_file_open_at(at_id, path, mode, &file);
 
     if (file.id != -1) {
-      return private_f_file_close(&file.id);
+      return private_f_file_close(F_true, &file.id);
     }
 
     return status;
index 2bfe9438c3ce81d61eaf18ecc5c59d4f48021965..7b8980c8f9858c165e6dd2edb0369d432e17af9d 100644 (file)
@@ -20,6 +20,9 @@ extern "C" {
  *
  * Intended to be shared to each of the different implementation variations.
  *
+ * @param flush
+ *   If TRUE, then perform flush before closing.
+ *   If FALSE, then do not perform flush before closing.
  * @param id
  *   The file descriptor.
  *
@@ -39,7 +42,7 @@ extern "C" {
  * @see f_file_stream_close()
  */
 #if !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) || !defined(_di_f_file_stream_close_)
-  extern f_status_t private_f_file_close(int *id) f_gcc_attribute_visibility_internal;
+  extern f_status_t private_f_file_close(const bool flush, int *id) f_gcc_attribute_visibility_internal;
 #endif // !defined(_di_f_file_close_) || !defined(_di_f_file_copy_) || !defined(_di_f_file_stream_close_)
 
 /**