diff --git a/app/Makefile b/app/Makefile index fdd7bf4d..ea09863d 100644 --- a/app/Makefile +++ b/app/Makefile @@ -175,7 +175,7 @@ CFLAGS+= -DUSE_JQ STATIC_LIB_FLAGS= ifneq ($(STATIC_LIBS),) - STATIC_LIB_FLAGS=-static ${STATIC_LIBS} + STATIC_LIB_FLAGS=${LDFLAGS_STATIC} endif STANDALONE_PFX=${BUILD_DIR}/bin/zsv_ diff --git a/app/utils/file.c b/app/utils/file.c index c8da6aae..a3600cb5 100644 --- a/app/utils/file.c +++ b/app/utils/file.c @@ -119,6 +119,28 @@ int zsv_file_exists(const char* filename) { } #endif +/** + * Open a file for exclusive write (same as fopen() but opens exclusively) + * mode must be 'w' or 'wb' + */ +FILE* zsv_fopen_wx(const char *filename, const char *mode) { + if(!mode || (strcmp(mode, "w") && strcmp(mode, "wb"))) { + fprintf(stderr, "fopen_wbx mode must be 'w' or 'wb'; got %s\n", mode ? mode : "(none)"); + return NULL; + } + + int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644); // exclusive binary write + if(fd == -1) { + return NULL; + } + + FILE *file = fdopen(fd, "wb"); // Convert to FILE* + if(file == NULL) + close(fd); + + return file; +} + /** * Copy a file, given source and destination paths * On error, output error message and return non-zero @@ -133,16 +155,22 @@ int zsv_copy_file(const char *src, const char *dest) { // copy the file int err = 0; FILE *fsrc = fopen(src, "rb"); - if(!fsrc) - err = errno ? errno : -1, perror(src); - else { - FILE *fdest = fopen(dest, "wb"); - if(!fdest) - err = errno ? errno : -1, perror(dest); - else { + if(!fsrc) { + err = errno ? errno : -1; + perror(src); + } else { + FILE *fdest = zsv_fopen_wx(dest, "wb"); + if(!fdest) { + err = errno ? errno : -1; + perror(dest); + } else { err = zsv_copy_file_ptr(fsrc, fdest); - if(err) - perror(dest); + if(err) { + if(err < 0) + fprintf(stderr, "Unknown error copying %s to %s\n", src, dest); + else + perror(dest); + } fclose(fdest); } fclose(fsrc); @@ -155,16 +183,14 @@ int zsv_copy_file(const char *src, const char *dest) { * Return error number per errno.h */ int zsv_copy_file_ptr(FILE *src, FILE *dest) { - int err = 0; + errno = 0; char buffer[4096]; size_t bytes_read; while((bytes_read = fread(buffer, 1, sizeof(buffer), src)) > 0) { - if(fwrite(buffer, 1, bytes_read, dest) != bytes_read) { - err = errno ? errno : -1; - break; - } + if(fwrite(buffer, 1, bytes_read, dest) != bytes_read) + return errno ? errno : -1; } - return err; + return errno; } size_t zsv_dir_len_basename(const char *filepath, const char **basename) { diff --git a/configure b/configure index dab57013..3217e650 100755 --- a/configure +++ b/configure @@ -466,6 +466,7 @@ _ACEOF tryflag CFLAGS_TRY -Werror=unknown-warning-option tryflag CFLAGS_TRY -Werror=unused-command-line-argument tryflag CFLAGS_TRY -Werror=ignored-optimization-argument +tryldflag LDFLAGS_STATIC -static tryldflag LDFLAGS_TRY -Werror=unknown-warning-option tryldflag LDFLAGS_TRY -Werror=unused-command-line-argument tryldflag LDFLAGS_TRY -Werror=ignored-optimization-argument @@ -729,6 +730,7 @@ CFLAGS_PIC = $CFLAGS_PIC LDFLAGS_PIC = $LDFLAGS_PIC CFLAGS_PIE = $CFLAGS_PIE LDFLAGS_PIE = $LDFLAGS_PIE +LDFLAGS_STATIC = $LDFLAGS_STATIC USE_DEBUG_STDERR = $USE_DEBUG_STDERR CFLAGS_VECTORIZE = $CFLAGS_VECTORIZE CFLAGS_VECTORIZE_OPTIMIZED = $CFLAGS_VECTORIZE_OPTIMIZED diff --git a/include/zsv/utils/file.h b/include/zsv/utils/file.h index 127a259e..dc44c598 100644 --- a/include/zsv/utils/file.h +++ b/include/zsv/utils/file.h @@ -61,6 +61,12 @@ size_t zsv_filter_write(void *FILEp, unsigned char *buff, size_t bytes_read); */ size_t zsv_dir_len_basename(const char *filepath, const char **basename); +/** + * Open a file for exclusive write (same as fopen() but opens exclusively) + * mode must be 'w' or 'wb' + */ +FILE* zsv_fopen_wx(const char *filename, const char *mode); + /** * Copy a file. Create any needed directories * On error, prints error message and returns non-zero