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.
#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_
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;
/**
* 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.
#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.
* 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.
#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);
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;
}
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);
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;
}
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);
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;
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;
*
* 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.
*
* @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_)
/**