Compare commits

...

3 commits

Author SHA1 Message Date
613354034d Use SIGPIPE handling on UNIX platforms
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 4s
2024-07-19 12:15:20 +09:00
c1c4f048cb Improve error handling
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 4s
Handle SIGPIPE.
2024-07-19 12:13:54 +09:00
e7db978a3c More robust error handling
All checks were successful
Run Unit Tests / build-and-run-unit-tests (push) Successful in 5s
2024-07-19 11:29:14 +09:00
2 changed files with 131 additions and 22 deletions

View file

@ -28,6 +28,7 @@
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h>
#include <spawn.h> #include <spawn.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -39,6 +40,18 @@
#define TEMP_FILENAME_CMP "simple_archiver_compressed_%u.tmp" #define TEMP_FILENAME_CMP "simple_archiver_compressed_%u.tmp"
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
int is_sig_pipe_occurred = 0;
void handle_sig_pipe(int sig) {
if (sig == SIGPIPE) {
is_sig_pipe_occurred = 1;
}
}
#endif
typedef struct SDArchiverInternalToWrite { typedef struct SDArchiverInternalToWrite {
void *buf; void *buf;
uint64_t size; uint64_t size;
@ -145,6 +158,9 @@ int write_files_fn(void *data, void *ud) {
return 1; return 1;
} }
// Handle SIGPIPE.
signal(SIGPIPE, handle_sig_pipe);
int pipe_into_cmd[2]; int pipe_into_cmd[2];
int pipe_outof_cmd[2]; int pipe_outof_cmd[2];
pid_t compressor_pid; pid_t compressor_pid;
@ -177,6 +193,8 @@ int write_files_fn(void *data, void *ud) {
// Failed to spawn compressor. // Failed to spawn compressor.
close(pipe_into_cmd[1]); close(pipe_into_cmd[1]);
close(pipe_outof_cmd[0]); close(pipe_outof_cmd[0]);
fprintf(stderr,
"WARNING: Failed to start compressor cmd! Invalid cmd?\n");
return 1; return 1;
} }
@ -191,31 +209,19 @@ int write_files_fn(void *data, void *ud) {
// Status is available. // Status is available.
if (WIFEXITED(compressor_status)) { if (WIFEXITED(compressor_status)) {
compressor_return_val = WEXITSTATUS(compressor_status); compressor_return_val = WEXITSTATUS(compressor_status);
if (compressor_return_val == 127) { fprintf(stderr,
// Exec failed. "WARNING: Exec failed (exec exit code %d)! Invalid "
fprintf(stderr, "compressor cmd?\n",
"WARNING: Exec failed (exec exit code 127)! Invalid " compressor_return_val);
"compressor cmd?\n"); return 1;
return 1;
} else if (compressor_return_val == 0) {
// Immediately halted.
fprintf(stderr,
"WARNING: Exec failed (exec exit code 0)! Invalid "
"compressor cmd?\n");
return 1;
} else {
// Other status returned.
fprintf(stderr,
"WARNING: Exec failed (exec exit code %d)! Invalid "
"compressor cmd?\n",
compressor_return_val);
return 1;
}
} }
} else if (compressor_ret == 0) { } else if (compressor_ret == 0) {
// Probably still running, continue on. // Probably still running, continue on.
} else { } else {
// Error. // Error.
fprintf(stderr,
"WARNING: Exec failed (exec exit code unknown)! Invalid "
"compressor cmd?\n");
return 1; return 1;
} }
@ -229,6 +235,13 @@ int write_files_fn(void *data, void *ud) {
size_t read_count; size_t read_count;
ssize_t ret; ssize_t ret;
while (!write_done || !read_done) { while (!write_done || !read_done) {
if (is_sig_pipe_occurred) {
fprintf(stderr,
"WARNING: Failed to write to compressor (SIGPIPE)! Invalid "
"compressor cmd?\n");
return 1;
}
// Read from file. // Read from file.
if (!write_done) { if (!write_done) {
if (!write_again) { if (!write_again) {
@ -241,10 +254,16 @@ int write_files_fn(void *data, void *ud) {
write_again = 1; write_again = 1;
} else { } else {
// Error during write. // Error during write.
fprintf(stderr,
"WARNING: Failed to write to compressor! Invalid "
"compressor cmd?\n");
return 1; return 1;
} }
} else if ((size_t)ret != write_count) { } else if ((size_t)ret != write_count) {
// Error during write. // Error during write.
fprintf(stderr,
"WARNING: Failed to write to compressor! Invalid "
"compressor cmd?\n");
return 1; return 1;
} else { } else {
write_again = 0; write_again = 0;
@ -258,6 +277,9 @@ int write_files_fn(void *data, void *ud) {
// fprintf(stderr, "write_done\n"); // fprintf(stderr, "write_done\n");
} else if (ferror(file_fd)) { } else if (ferror(file_fd)) {
// Error during read file. // Error during read file.
fprintf(
stderr,
"WARNING: Failed to write to compressor (failed to read)!\n");
return 1; return 1;
} }
} }
@ -270,6 +292,9 @@ int write_files_fn(void *data, void *ud) {
read_count = fwrite(read_buf, 1, ret, tmp_fd); read_count = fwrite(read_buf, 1, ret, tmp_fd);
if (read_count != (size_t)ret) { if (read_count != (size_t)ret) {
// Write to tmp_fd error. // Write to tmp_fd error.
fprintf(stderr,
"WARNING: Failed to read from compressor! Invalid "
"compressor cmd?\n");
return 1; return 1;
} else { } else {
// fprintf(stderr, "Written %zd bytes to tmp_fd.\n", read_count); // fprintf(stderr, "Written %zd bytes to tmp_fd.\n", read_count);
@ -284,6 +309,9 @@ int write_files_fn(void *data, void *ud) {
// Nop. // Nop.
} else { } else {
// Read error. // Read error.
fprintf(stderr,
"WARNING: Failed to read from compressor! Invalid "
"compressor cmd?\n");
return 1; return 1;
} }
} else { } else {
@ -292,6 +320,13 @@ int write_files_fn(void *data, void *ud) {
} }
} }
if (is_sig_pipe_occurred) {
fprintf(stderr,
"WARNING: Failed to write to compressor (SIGPIPE)! Invalid "
"compressor cmd?\n");
return 1;
}
waitpid(compressor_pid, NULL, 0); waitpid(compressor_pid, NULL, 0);
uint16_t u16; uint16_t u16;
@ -695,6 +730,8 @@ int simple_archiver_write_all(FILE *out_f, SDArchiverState *state,
fprintf(stderr, "[%10u/%10u]\n", state->count, state->max); fprintf(stderr, "[%10u/%10u]\n", state->count, state->max);
if (simple_archiver_list_get(filenames, write_files_fn, state)) { if (simple_archiver_list_get(filenames, write_files_fn, state)) {
// Error occurred. // Error occurred.
fprintf(stderr, "Error ocurred writing file(s) to archive.\n");
return SDAS_FAILED_TO_WRITE;
} }
state->out_f = NULL; state->out_f = NULL;
@ -990,10 +1027,18 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
simple_archiver_helper_make_dirs((const char *)out_f_name); simple_archiver_helper_make_dirs((const char *)out_f_name);
out_f = fopen(out_f_name, "wb"); out_f = fopen(out_f_name, "wb");
__attribute__((
cleanup(cleanup_temp_filename_delete))) void **ptrs_array =
malloc(sizeof(void *) * 2);
ptrs_array[0] = out_f_name;
ptrs_array[1] = &out_f;
#if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \ #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \ SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC || \
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
if (is_compressed) { if (is_compressed) {
// Handle SIGPIPE.
signal(SIGPIPE, handle_sig_pipe);
int pipe_into_cmd[2]; int pipe_into_cmd[2];
int pipe_outof_cmd[2]; int pipe_outof_cmd[2];
pid_t decompressor_pid; pid_t decompressor_pid;
@ -1028,6 +1073,9 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
// Failed to spawn compressor. // Failed to spawn compressor.
close(pipe_into_cmd[1]); close(pipe_into_cmd[1]);
close(pipe_outof_cmd[0]); close(pipe_outof_cmd[0]);
fprintf(
stderr,
"WARNING: Failed to start decompressor cmd! Invalid cmd?\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} }
} else { } else {
@ -1037,6 +1085,9 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
// Failed to spawn compressor. // Failed to spawn compressor.
close(pipe_into_cmd[1]); close(pipe_into_cmd[1]);
close(pipe_outof_cmd[0]); close(pipe_outof_cmd[0]);
fprintf(
stderr,
"WARNING: Failed to start decompressor cmd! Invalid cmd?\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} }
} }
@ -1045,6 +1096,30 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
close(pipe_into_cmd[0]); close(pipe_into_cmd[0]);
close(pipe_outof_cmd[1]); close(pipe_outof_cmd[1]);
int decompressor_status;
int decompressor_return_val;
int decompressor_ret =
waitpid(decompressor_pid, &decompressor_status, WNOHANG);
if (decompressor_ret == decompressor_pid) {
// Status is available.
if (WIFEXITED(decompressor_status)) {
decompressor_return_val = WEXITSTATUS(decompressor_status);
fprintf(stderr,
"WARNING: Exec failed (exec exit code %d)! Invalid "
"decompressor cmd?\n",
decompressor_return_val);
return SDAS_INTERNAL_ERROR;
}
} else if (decompressor_ret == 0) {
// Probably still running, continue on.
} else {
// Error.
fprintf(stderr,
"WARNING: Exec failed (exec exit code unknown)! Invalid "
"decompressor cmd?\n");
return SDAS_INTERNAL_ERROR;
}
uint64_t compressed_file_size = u64; uint64_t compressed_file_size = u64;
int write_again = 0; int write_again = 0;
int write_pipe_done = 0; int write_pipe_done = 0;
@ -1053,6 +1128,13 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
char recv_buf[1024]; char recv_buf[1024];
size_t amount_to_read; size_t amount_to_read;
while (!write_pipe_done || !read_pipe_done) { while (!write_pipe_done || !read_pipe_done) {
if (is_sig_pipe_occurred) {
fprintf(stderr,
"WARNING: Failed to write to decompressor (SIGPIPE)! "
"Invalid decompressor cmd?\n");
return 1;
}
// Read from file. // Read from file.
if (!write_pipe_done) { if (!write_pipe_done) {
if (!write_again && compressed_file_size != 0) { if (!write_again && compressed_file_size != 0) {
@ -1082,10 +1164,16 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
write_again = 1; write_again = 1;
} else { } else {
// Error. // Error.
fprintf(stderr,
"WARNING: Failed to write to decompressor! Invalid "
"decompressor cmd?\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} }
} else { } else {
// Should be unreachable, error. // Should be unreachable, error.
fprintf(stderr,
"WARNING: Failed to write to decompressor! Invalid "
"decompressor cmd?\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} }
} }
@ -1100,9 +1188,15 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
// Success. // Success.
} else if (ferror(out_f)) { } else if (ferror(out_f)) {
// Error. // Error.
fprintf(stderr,
"WARNING: Failed to read from decompressor! Invalid "
"decompressor cmd?\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} else { } else {
// Invalid state, error. // Invalid state, error.
fprintf(stderr,
"WARNING: Failed to read from decompressor! Invalid "
"decompressor cmd?\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} }
} else if (read_ret == -1) { } else if (read_ret == -1) {
@ -1110,6 +1204,9 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
// No bytes to read yet. // No bytes to read yet.
} else { } else {
// Error. // Error.
fprintf(stderr,
"WARNING: Failed to read from decompressor! Invalid "
"decompressor cmd?\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} }
} else if (read_ret == 0) { } else if (read_ret == 0) {
@ -1119,11 +1216,21 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
free_FILE_helper(&out_f); free_FILE_helper(&out_f);
} else { } else {
// Invalid state (unreachable?), error. // Invalid state (unreachable?), error.
fprintf(stderr,
"WARNING: Failed to read from decompressor! Invalid "
"decompressor cmd?\n");
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} }
} }
} }
if (is_sig_pipe_occurred) {
fprintf(stderr,
"WARNING: Failed to write to decompressor (SIGPIPE)! "
"Invalid decompressor cmd?\n");
return 1;
}
waitpid(decompressor_pid, NULL, 0); waitpid(decompressor_pid, NULL, 0);
} else { } else {
uint64_t compressed_file_size = u64; uint64_t compressed_file_size = u64;
@ -1162,6 +1269,7 @@ int simple_archiver_parse_archive_info(FILE *in_f, int do_extract,
return SDAS_INTERNAL_ERROR; return SDAS_INTERNAL_ERROR;
} }
ptrs_array[0] = NULL;
fprintf(stderr, " Extracted.\n"); fprintf(stderr, " Extracted.\n");
#endif #endif
} else { } else {

View file

@ -90,6 +90,7 @@ int main(int argc, const char **argv) {
SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
if (ret != SDAS_SUCCESS) { if (ret != SDAS_SUCCESS) {
unlink(parsed.filename); unlink(parsed.filename);
return 3;
} }
#endif #endif
} else if ((parsed.flags & 3) == 2) { } else if ((parsed.flags & 3) == 2) {
@ -97,7 +98,7 @@ int main(int argc, const char **argv) {
if (!file) { if (!file) {
fprintf(stderr, "ERROR: Failed to open \"%s\" for reading!\n", fprintf(stderr, "ERROR: Failed to open \"%s\" for reading!\n",
parsed.filename); parsed.filename);
return 3; return 4;
} }
int ret = simple_archiver_parse_archive_info(file, 0, NULL); int ret = simple_archiver_parse_archive_info(file, 0, NULL);
@ -112,7 +113,7 @@ int main(int argc, const char **argv) {
if (!file) { if (!file) {
fprintf(stderr, "ERROR: Failed to open \"%s\" for reading!\n", fprintf(stderr, "ERROR: Failed to open \"%s\" for reading!\n",
parsed.filename); parsed.filename);
return 3; return 5;
} }
__attribute__((cleanup(simple_archiver_free_state))) __attribute__((cleanup(simple_archiver_free_state)))