]> git.seodisparate.com - SimpleArchiver/commitdiff
Impl. more robust compression
authorStephen Seo <seo.disparate@gmail.com>
Mon, 7 Oct 2024 03:08:38 +0000 (12:08 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Mon, 7 Oct 2024 03:11:03 +0000 (12:11 +0900)
src/archiver.c

index f920ebf2f95e65b889146959cace1254b8813249..4d58b958c82e337272774b75da908dd16975ff6a 100644 (file)
@@ -1389,7 +1389,7 @@ void simple_archiver_internal_cleanup_int_fd(int *fd) {
 #if SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_COSMOPOLITAN || \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_MAC ||          \
     SIMPLE_ARCHIVER_PLATFORM == SIMPLE_ARCHIVER_PLATFORM_LINUX
-void simple_archiver_internal_cleanup_decomp(pid_t *decomp_pid) {
+void simple_archiver_internal_cleanup_decomp_pid(pid_t *decomp_pid) {
   if (decomp_pid && *decomp_pid >= 0) {
     int decompressor_status;
     int decompressor_return_val;
@@ -2215,7 +2215,9 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
 
       int pipe_into_cmd[2];
       int pipe_outof_cmd[2];
-      pid_t compressor_pid;
+      __attribute__((cleanup(
+          simple_archiver_internal_cleanup_decomp_pid))) pid_t compressor_pid =
+          -1;
 
       if (pipe(pipe_into_cmd) != 0) {
         // Unable to create pipes.
@@ -2225,6 +2227,20 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
         close(pipe_into_cmd[0]);
         close(pipe_into_cmd[1]);
         return SDAS_INTERNAL_ERROR;
+      } else if (fcntl(pipe_into_cmd[1], F_SETFL, O_NONBLOCK) != 0) {
+        // Unable to set non-blocking on into-write-pipe.
+        close(pipe_into_cmd[0]);
+        close(pipe_into_cmd[1]);
+        close(pipe_outof_cmd[0]);
+        close(pipe_outof_cmd[1]);
+        return SDAS_INTERNAL_ERROR;
+      } else if (fcntl(pipe_outof_cmd[0], F_SETFL, O_NONBLOCK) != 0) {
+        // Unable to set non-blocking on outof-read-pipe.
+        close(pipe_into_cmd[0]);
+        close(pipe_into_cmd[1]);
+        close(pipe_outof_cmd[0]);
+        close(pipe_outof_cmd[1]);
+        return SDAS_INTERNAL_ERROR;
       } else if (simple_archiver_de_compress(pipe_into_cmd, pipe_outof_cmd,
                                              state->parsed->compressor,
                                              &compressor_pid) != 0) {
@@ -2241,13 +2257,14 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
       close(pipe_outof_cmd[1]);
 
       // Set up cleanup so that remaining open pipes in this side is cleaned up.
-      __attribute__((cleanup(
-          simple_archiver_internal_cleanup_int_fd))) int pipe_into_write =
-          pipe_into_cmd[1];
       __attribute__((cleanup(
           simple_archiver_internal_cleanup_int_fd))) int pipe_outof_read =
           pipe_outof_cmd[0];
+      __attribute__((cleanup(
+          simple_archiver_internal_cleanup_int_fd))) int pipe_into_write =
+          pipe_into_cmd[1];
 
+      int_fast8_t to_temp_finished = 0;
       for (uint64_t file_idx = 0; file_idx < *((uint64_t *)chunk_c_node->data);
            ++file_idx) {
         file_node = file_node->next;
@@ -2257,55 +2274,92 @@ int simple_archiver_write_v1(FILE *out_f, SDArchiverState *state,
         const SDArchiverInternalFileInfo *file_info_struct = file_node->data;
         __attribute__((cleanup(simple_archiver_helper_cleanup_FILE))) FILE *fd =
             fopen(file_info_struct->filename, "rb");
-        while (!feof(fd)) {
-          if (ferror(fd)) {
-            fprintf(stderr, "ERROR: Writing to chunk, file read error!\n");
-            return SDAS_INTERNAL_ERROR;
+
+        int_fast8_t to_comp_finished = 0;
+        while (!to_comp_finished) {
+          if (!to_comp_finished) {
+            // Write to compressor.
+            if (ferror(fd)) {
+              fprintf(stderr, "ERROR: Writing to chunk, file read error!\n");
+              return SDAS_INTERNAL_ERROR;
+            }
+            size_t fread_ret = fread(buf, 1, 1024, fd);
+            if (fread_ret > 0) {
+              ssize_t write_ret = write(pipe_into_write, buf, fread_ret);
+              if (write_ret < 0) {
+                if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                  // Non-blocking write.
+                } else {
+                  fprintf(stderr,
+                          "ERROR: Writing to compressor, pipe write error!\n");
+                  return SDAS_FAILED_TO_WRITE;
+                }
+              } else if ((size_t)write_ret != fread_ret) {
+                fprintf(
+                    stderr,
+                    "ERROR: Writing to compressor, unable to write bytes!\n");
+                return SDAS_FAILED_TO_WRITE;
+              }
+            }
+
+            if (feof(fd)) {
+              to_comp_finished = 1;
+            }
           }
-          size_t fread_ret = fread(buf, 1, 1024, fd);
-          if (fread_ret > 0) {
-            ssize_t write_ret = write(pipe_into_write, buf, fread_ret);
-            if (write_ret < 0) {
+
+          // Write compressed data to temp file.
+          ssize_t read_ret = read(pipe_outof_read, buf, 1024);
+          if (read_ret < 0) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK) {
+              // Non-blocking read.
+            } else {
               fprintf(stderr,
-                      "ERROR: Writing to compressor, pipe write error!\n");
-              return SDAS_FAILED_TO_WRITE;
-            } else if ((size_t)write_ret != fread_ret) {
+                      "ERROR: Reading from compressor, pipe read error!\n");
+              return SDAS_INTERNAL_ERROR;
+            }
+          } else if (read_ret == 0) {
+            // EOF.
+            to_temp_finished = 1;
+          } else {
+            size_t fwrite_ret = fwrite(buf, 1, (size_t)read_ret, temp_fd);
+            if (fwrite_ret != (size_t)read_ret) {
               fprintf(stderr,
-                      "ERROR: Writing to compressor, unable to write bytes!\n");
-              return SDAS_FAILED_TO_WRITE;
+                      "ERROR: Reading from compressor, failed to write to "
+                      "temporary file!\n");
+              return SDAS_INTERNAL_ERROR;
             }
           }
         }
       }
 
-      // Close write to pipe to compressor as the chunk is written.
       simple_archiver_internal_cleanup_int_fd(&pipe_into_write);
 
-      // Read compressed data into temporary file.
-      do {
-        ssize_t read_ret = read(pipe_outof_read, buf, 1024);
-        if (read_ret < 0) {
-          fprintf(stderr, "ERROR: Reading from compressor, pipe read error!\n");
-          return SDAS_INTERNAL_ERROR;
-        } else if (read_ret == 0) {
-          // EOF.
-          break;
-        } else {
-          size_t fwrite_ret = fwrite(buf, 1, (size_t)read_ret, temp_fd);
-          if (fwrite_ret != (size_t)read_ret) {
-            fprintf(stderr,
-                    "ERROR: Reading from compressor, failed to write to "
-                    "temporary file!\n");
-            return SDAS_INTERNAL_ERROR;
+      // Finish writing.
+      if (!to_temp_finished) {
+        while (1) {
+          ssize_t read_ret = read(pipe_outof_read, buf, 1024);
+          if (read_ret < 0) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK) {
+              // Non-blocking read.
+            } else {
+              fprintf(stderr,
+                      "ERROR: Reading from compressor, pipe read error!\n");
+              return SDAS_INTERNAL_ERROR;
+            }
+          } else if (read_ret == 0) {
+            // EOF.
+            break;
+          } else {
+            size_t fwrite_ret = fwrite(buf, 1, (size_t)read_ret, temp_fd);
+            if (fwrite_ret != (size_t)read_ret) {
+              fprintf(stderr,
+                      "ERROR: Reading from compressor, failed to write to "
+                      "temporary file!\n");
+              return SDAS_INTERNAL_ERROR;
+            }
           }
         }
-      } while (1);
-
-      // Close read from pipe from compressor as chunk is fully compressed.
-      simple_archiver_internal_cleanup_int_fd(&pipe_outof_read);
-
-      // Wait on compressor to stop.
-      waitpid(compressor_pid, NULL, 0);
+      }
 
       long comp_chunk_size = ftell(temp_fd);
       if (comp_chunk_size < 0) {
@@ -3661,7 +3715,7 @@ int simple_archiver_parse_archive_version_1(FILE *in_f, int_fast8_t do_extract,
       int pipe_into_cmd[2];
       int pipe_outof_cmd[2];
       __attribute__((cleanup(
-          simple_archiver_internal_cleanup_decomp))) pid_t decompressor_pid;
+          simple_archiver_internal_cleanup_decomp_pid))) pid_t decompressor_pid;
       if (pipe(pipe_into_cmd) != 0) {
         // Unable to create pipes.
         break;