--- libjpeg-turbo-2.1.4/cjpeg.c 2022-08-09 00:03:55.000000000 +0300 +++ libjpeg-turbo-2.1.4.fsync/cjpeg.c 2022-08-13 12:15:27.965663611 +0300 @@ -38,6 +38,8 @@ #include "jversion.h" /* for version message */ #include "jconfigint.h" +#include +#include /* Create the add-on message string table. */ @@ -76,7 +78,7 @@ static const char * const cdjpeg_message */ static boolean is_targa; /* records user -targa switch */ - +static boolean do_fsync; LOCAL(cjpeg_source_ptr) select_file_type(j_compress_ptr cinfo, FILE *infile) @@ -229,6 +231,7 @@ usage(void) #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) fprintf(stderr, " -memdst Compress to memory instead of file (useful for benchmarking)\n"); #endif + fprintf(stderr, " -fsync fsync output file prior to closing\n"); fprintf(stderr, " -report Report compression progress\n"); fprintf(stderr, " -strict Treat all warnings as fatal\n"); fprintf(stderr, " -verbose or -debug Emit debug output\n"); @@ -384,6 +387,10 @@ parse_switches(j_compress_ptr cinfo, int usage(); outfilename = argv[argn]; /* save it away for later use */ + } else if (keymatch(arg, "fsync", 2)) { + /* Set fsync flag */ + do_fsync = 1; + } else if (keymatch(arg, "progressive", 1)) { /* Select simple progressive mode. */ #ifdef C_PROGRESSIVE_SUPPORTED @@ -573,6 +580,7 @@ main(int argc, char **argv) unsigned char *outbuffer = NULL; unsigned long outsize = 0; JDIMENSION num_scanlines; + int ioerror = 0; progname = argv[0]; if (progname == NULL || progname[0] == 0) @@ -742,8 +750,25 @@ main(int argc, char **argv) /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); + + if (fflush(output_file) == EOF) { + fprintf(stderr, "%s: failed to write to %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } + if (do_fsync && (fsync(fileno(output_file)) == -1)) { + if (errno != EINVAL) { + fprintf(stderr, "%s: failed to fsync %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } + } if (output_file != stdout && output_file != NULL) - fclose(output_file); + if (fclose(output_file) == EOF) { + fprintf(stderr, "%s: failed to close %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } if (report) end_progress_monitor((j_common_ptr)&cinfo); @@ -758,5 +783,5 @@ main(int argc, char **argv) free(icc_profile); /* All done. */ - return (jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); + return ((jerr.num_warnings || ioerror) ? EXIT_WARNING : EXIT_SUCCESS); } --- libjpeg-turbo-2.1.4/djpeg.c 2022-08-09 00:03:55.000000000 +0300 +++ libjpeg-turbo-2.1.4.fsync/djpeg.c 2022-08-13 12:16:31.935479176 +0300 @@ -37,7 +37,8 @@ #include "jconfigint.h" #include /* to declare isprint() */ - +#include +#include /* Create the add-on message string table. */ @@ -48,6 +49,7 @@ static const char * const cdjpeg_message NULL }; +static boolean do_fsync; /* * This list defines the known output image formats @@ -153,6 +155,7 @@ usage(void) fprintf(stderr, " -dither fs Use F-S dithering (default)\n"); fprintf(stderr, " -dither none Don't use dithering in quantization\n"); fprintf(stderr, " -dither ordered Use ordered dither (medium speed, quality)\n"); + fprintf(stderr, " -fsync fsync output file prior to closing\n"); fprintf(stderr, " -icc FILE Extract ICC profile to FILE\n"); #ifdef QUANT_2PASS_SUPPORTED fprintf(stderr, " -map FILE Map to colors used in named image file\n"); @@ -385,6 +388,10 @@ parse_switches(j_decompress_ptr cinfo, i exit(EXIT_FAILURE); #endif + } else if (keymatch(arg, "fsync", 2)) { + /* Set fsync flag */ + do_fsync = 1; + } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) { /* PPM/PGM output format. */ requested_fmt = FMT_PPM; @@ -539,6 +546,7 @@ main(int argc, char **argv) unsigned long insize = 0; #endif JDIMENSION num_scanlines; + int ioerror = 0; progname = argv[0]; if (progname == NULL || progname[0] == 0) @@ -838,8 +846,24 @@ main(int argc, char **argv) /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); + if (fflush(output_file) == EOF) { + fprintf(stderr, "%s: failed to write to %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } + if (do_fsync && (fsync(fileno(output_file)) == -1)) { + if (errno != EINVAL) { + fprintf(stderr, "%s: failed to fsync %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } + } if (output_file != stdout) - fclose(output_file); + if (fclose(output_file) == EOF) { + fprintf(stderr, "%s: failed to close %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } if (report || max_scans != 0) end_progress_monitor((j_common_ptr)&cinfo); @@ -848,6 +872,6 @@ main(int argc, char **argv) free(inbuffer); /* All done. */ - exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); + exit((jerr.num_warnings || ioerror) ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ } --- libjpeg-turbo-2.1.4/jpegtran.c 2022-08-09 00:03:55.000000000 +0300 +++ libjpeg-turbo-2.1.4.fsync/jpegtran.c 2022-08-13 12:17:17.775347045 +0300 @@ -23,6 +23,8 @@ #include "jversion.h" /* for version message */ #include "jconfigint.h" +#include +#include /* * Argument-parsing code. @@ -42,7 +44,8 @@ boolean report; /* for - boolean strict; /* for -strict switch */ static JCOPY_OPTION copyoption; /* -copy switch */ static jpeg_transform_info transformoption; /* image transformation options */ - +static int do_fsync; +static int do_temp; LOCAL(void) usage(void) @@ -93,6 +96,8 @@ usage(void) fprintf(stderr, " -outfile name Specify name for output file\n"); fprintf(stderr, " -report Report transformation progress\n"); fprintf(stderr, " -strict Treat all warnings as fatal\n"); + fprintf(stderr, " -fsync fsync output file prior to closing\n"); + fprintf(stderr, " -temp write output to temp file and replace original input\n"); fprintf(stderr, " -verbose or -debug Emit debug output\n"); fprintf(stderr, " -version Print version information and exit\n"); fprintf(stderr, "Switches for wizards:\n"); @@ -314,6 +319,14 @@ parse_switches(j_compress_ptr cinfo, int usage(); outfilename = argv[argn]; /* save it away for later use */ + } else if (keymatch(arg, "fsync", 2)) { + /* Set fsync flag */ + do_fsync = 1; + + } else if (keymatch(arg, "temp", 2)) { + /* Set temp flag */ + do_temp = 1; + } else if (keymatch(arg, "perfect", 2)) { /* Fail if there is any partial edge MCUs that the transform can't * handle. */ @@ -465,6 +478,7 @@ main(int argc, char **argv) jvirt_barray_ptr *src_coef_arrays; jvirt_barray_ptr *dst_coef_arrays; int file_index; + int inputfile_index; /* We assume all-in-memory processing and can therefore use only a * single file pointer for sequential input and output operation. */ @@ -472,6 +486,8 @@ main(int argc, char **argv) FILE *icc_file; JOCTET *icc_profile = NULL; long icc_len = 0; + int ioerror = 0; + char outtemp[4096]; progname = argv[0]; if (progname == NULL || progname[0] == 0) @@ -530,7 +546,13 @@ main(int argc, char **argv) argv[file_index]); exit(EXIT_FAILURE); } + inputfile_index = file_index; } else { + if (do_temp) { + fprintf(stderr, "%s: temp mode can not be used when reading " + "from stdin\n", progname); + exit(EXIT_FAILURE); + } /* default input file is stdin */ fp = read_stdin(); } @@ -658,14 +680,41 @@ main(int argc, char **argv) /* Open the output file. */ if (outfilename != NULL) { - if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { + if (do_temp) { + fprintf(stderr, "%s: outfile parameter incompatible with temp mode\n", progname); + exit(EXIT_FAILURE); + } else if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename); exit(EXIT_FAILURE); } } else { - /* default output file is stdout */ - fp = write_stdout(); + if (do_temp) { + int fd; + int snret; + + snret = snprintf(outtemp, sizeof(outtemp), "%s.tmp.XXXXXX", argv[inputfile_index]); + if (snret < 0 || snret >= sizeof(outtemp)) { + fprintf(stderr, "%s: snprintf buffer overflow\n", progname); + exit(EXIT_FAILURE); + } + fd = mkstemp(outtemp); + if (fd == -1) { + fprintf(stderr, "%s: can't open temporary file: %s\n", + progname, strerror(errno)); + exit(EXIT_FAILURE); + } + fp = fdopen(fd, WRITE_BINARY); + outfilename = outtemp; + if (fp == NULL) { + fprintf(stderr, "%s: can't fdopen temporary file: %s\n", + progname, strerror(errno)); + exit(EXIT_FAILURE); + } + } else { + /* default output file is stdout */ + fp = write_stdout(); + } } /* Adjust default compression parameters by re-parsing the options */ @@ -701,9 +750,32 @@ main(int argc, char **argv) (void)jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); - /* Close output file, if we opened it */ - if (fp != stdout) - fclose(fp); + if (fflush(fp) == EOF) { + fprintf(stderr, "%s: failed to write to %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } + if (do_fsync && (fsync(fileno(fp)) == -1)) { + if (errno != EINVAL) { + fprintf(stderr, "%s: failed to fsync %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } + } + if (fp != stdout) { + if (fclose(fp) == EOF) { + fprintf(stderr, "%s: failed to close %s: %s\n", + progname, outfilename, strerror(errno)); + ioerror = 1; + } + if (do_temp) { + if (rename(outtemp, argv[inputfile_index]) == -1) { + fprintf(stderr, "%s: failed to rename %s to %s: %s\n", + progname, outtemp, argv[inputfile_index], strerror(errno)); + ioerror = 1; + } + } + } #if TRANSFORMS_SUPPORTED if (drop_file != NULL) fclose(drop_file);