From: Kevin Day Date: Sat, 17 Apr 2021 20:23:35 +0000 (-0500) Subject: Bugfix: invalid file descptor error on stream close. X-Git-Tag: 0.5.3~34 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=10fb7ea5943d8172ff0f4ed8a325f33babc64845;p=fll Bugfix: invalid file descptor error on stream close. 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. --- diff --git a/level_0/f_file/c/file.c b/level_0/f_file/c/file.c index c963e6c..fa7097a 100644 --- a/level_0/f_file/c/file.c +++ b/level_0/f_file/c/file.c @@ -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; diff --git a/level_0/f_file/c/file.h b/level_0/f_file/c/file.h index 6cc0435..f346270 100644 --- a/level_0/f_file/c/file.h +++ b/level_0/f_file/c/file.h @@ -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. diff --git a/level_0/f_file/c/private-file.c b/level_0/f_file/c/private-file.c index 7e0bbb9..b443cac 100644 --- a/level_0/f_file/c/private-file.c +++ b/level_0/f_file/c/private-file.c @@ -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; diff --git a/level_0/f_file/c/private-file.h b/level_0/f_file/c/private-file.h index 2bfe943..7b8980c 100644 --- a/level_0/f_file/c/private-file.h +++ b/level_0/f_file/c/private-file.h @@ -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_) /**