Use .part suffix for temp file names.
Untested for BTRFS cloning.
diff --git a/developer-xcode/libzip.xcodeproj/project.pbxproj b/developer-xcode/libzip.xcodeproj/project.pbxproj
index acd593a..08c5e07 100644
--- a/developer-xcode/libzip.xcodeproj/project.pbxproj
+++ b/developer-xcode/libzip.xcodeproj/project.pbxproj
@@ -171,7 +171,6 @@
4B3A5F531DF96EB4005A53A1 /* zip_ftell.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3A5F4E1DF96D83005A53A1 /* zip_ftell.c */; };
4B3FAE802385C5CC00192D6A /* zip_algorithm_xz.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FAE7F2385C5A300192D6A /* zip_algorithm_xz.c */; };
4B3FAE822385C79200192D6A /* liblzma.5.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B3FAE812385C79200192D6A /* liblzma.5.dylib */; };
- 4B5169A822A7993E00AA4340 /* zip_mkstempm.c in Sources */ = {isa = PBXBuildFile; fileRef = 4B5169A722A7993D00AA4340 /* zip_mkstempm.c */; };
4B51DDBA1FDAE20A00C5CA85 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D70815B2F4CF002D5007 /* libz.dylib */; };
4B51DDBB1FDAE20A00C5CA85 /* libzip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B01D68B15B2F3F1002D5007 /* libzip.framework */; };
4B51DDC11FDAE25B00C5CA85 /* ziptool.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BACD57C15BC2AEF00920691 /* ziptool.c */; };
@@ -2015,7 +2014,6 @@
4BCF302A199A2F820064207B /* zip_source_seek.c in Sources */,
4B01D6C515B2F46B002D5007 /* zip_fopen_index_encrypted.c in Sources */,
4B01D6C615B2F46B002D5007 /* zip_fopen_index.c in Sources */,
- 4B5169A822A7993E00AA4340 /* zip_mkstempm.c in Sources */,
4B69E6EE2032F18B0001EEE7 /* zip_winzip_aes.c in Sources */,
4B01D6C715B2F46B002D5007 /* zip_fopen.c in Sources */,
3D9284821C309510001EABA7 /* zip_hash.c in Sources */,
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 5ec2451..1213fa0 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -130,7 +130,6 @@
endif()
else(WIN32)
target_sources(zip PRIVATE
- zip_mkstempm.c
zip_source_file_stdio_named.c
zip_random_unix.c
)
diff --git a/lib/zip_mkstempm.c b/lib/zip_mkstempm.c
index ede5142..4efcf79 100644
--- a/lib/zip_mkstempm.c
+++ b/lib/zip_mkstempm.c
@@ -43,24 +43,28 @@
* or default permissions if there is no previous file
*/
int
-_zip_mkstempm(char *path, int mode) {
+_zip_mkstempm(char *path, int mode, bool create_file) {
int fd;
char *start, *end, *xs;
int xcnt = 0;
- end = path + strlen(path);
- start = end - 1;
+ end = path + strlen(path) - 1;
+ while (end >= path) {
+ if (*end == 'X') {
+ break;
+ }
+ end--;
+ }
+ if (end < path) {
+ errno = EINVAL;
+ return -1;
+ }
+ start = end;
while (start >= path && *start == 'X') {
xcnt++;
start--;
}
-
- if (xcnt == 0) {
- errno = EINVAL;
- return -1;
- }
-
start++;
for (;;) {
@@ -68,7 +72,7 @@
xs = start;
- while (xs < end) {
+ while (xs <= end) {
char digit = value % 36;
if (digit < 10) {
*(xs++) = digit + '0';
@@ -79,19 +83,33 @@
value /= 36;
}
- if ((fd = open(path, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, mode == -1 ? 0666 : (mode_t)mode)) >= 0) {
- if (mode != -1) {
- /* open() honors umask(), which we don't want in this case */
+ if (create_file) {
+ if ((fd = open(path, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, mode == -1 ? 0666 : (mode_t)mode)) >= 0) {
+ if (mode != -1) {
+ /* open() honors umask(), which we don't want in this case */
#ifdef HAVE_FCHMOD
- (void)fchmod(fd, (mode_t)mode);
+ (void)fchmod(fd, (mode_t)mode);
#else
- (void)chmod(path, (mode_t)mode);
+ (void)chmod(path, (mode_t)mode);
+ }
#endif
+ return fd;
}
- return fd;
+ if (errno != EEXIST) {
+ return -1;
+ }
}
- if (errno != EEXIST) {
- return -1;
+ else {
+ struct stat st;
+
+ if (stat(path, &st) < 0) {
+ if (errno == ENOENT) {
+ return 0;
+ }
+ else {
+ return -1;
+ }
+ }
}
}
}
diff --git a/lib/zip_source_file_stdio_named.c b/lib/zip_source_file_stdio_named.c
index 8027e73..974bf52 100644
--- a/lib/zip_source_file_stdio_named.c
+++ b/lib/zip_source_file_stdio_named.c
@@ -36,6 +36,7 @@
#include "zip_source_file.h"
#include "zip_source_file_stdio.h"
+#include <fcntl.h>
#include <stdlib.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
@@ -53,6 +54,8 @@
#define CAN_CLONE
#endif
+static int create_temp_file(zip_source_file_context_t *ctx, bool create_file);
+
static zip_int64_t _zip_stdio_op_commit_write(zip_source_file_context_t *ctx);
static zip_int64_t _zip_stdio_op_create_temp_output(zip_source_file_context_t *ctx);
#ifdef CAN_CLONE
@@ -123,82 +126,51 @@
static zip_int64_t
_zip_stdio_op_create_temp_output(zip_source_file_context_t *ctx) {
- char *temp;
- int tfd;
- int mode;
- FILE *tfp;
- struct stat st;
-
- if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
- zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
+ int fd = create_temp_file(ctx, true);
+
+ if (fd < 0) {
return -1;
}
-
- if (stat(ctx->fname, &st) == 0) {
- mode = st.st_mode;
- }
- else {
- mode = -1;
- }
-
- sprintf(temp, "%s.XXXXXX", ctx->fname);
-
- if ((tfd = _zip_mkstempm(temp, mode)) == -1) {
+
+ if ((ctx->fout = fdopen(fd, "r+b")) == NULL) {
zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
- free(temp);
+ close(fd);
+ (void)remove(ctx->tmpname);
+ free(ctx->tmpname);
+ ctx->tmpname = NULL;
return -1;
}
- if ((tfp = fdopen(tfd, "r+b")) == NULL) {
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
- close(tfd);
- (void)remove(temp);
- free(temp);
- return -1;
- }
-
- ctx->fout = tfp;
- ctx->tmpname = temp;
-
return 0;
}
#ifdef CAN_CLONE
static zip_int64_t
_zip_stdio_op_create_temp_output_cloning(zip_source_file_context_t *ctx, zip_uint64_t offset) {
- char *temp;
FILE *tfp;
-
+
if (offset > ZIP_OFF_MAX) {
zip_error_set(&ctx->error, ZIP_ER_SEEK, E2BIG);
return -1;
}
-
- if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
- zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
- return -1;
- }
- sprintf(temp, "%s.XXXXXX", ctx->fname);
-
+
#ifdef HAVE_CLONEFILE
-#ifndef __clang_analyzer__
- /* we can't use mkstemp, since clonefile insists on creating the file */
- if (mktemp(temp) == NULL) {
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
- free(temp);
+ /* clonefile insists on creating the file, so just create a name */
+ if (create_temp_file(ctx, false) < 0) {
return -1;
}
-#endif
-
- if (clonefile(ctx->fname, temp, 0) < 0) {
+
+ if (clonefile(ctx->fname, ctx->tmpname, 0) < 0) {
zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
- free(temp);
+ free(ctx->tmpname);
+ ctx->tmpname = NULL;
return -1;
}
- if ((tfp = _zip_fopen_close_on_exec(temp, true)) == NULL) {
+ if ((tfp = _zip_fopen_close_on_exec(ctx->tmpname, true)) == NULL) {
zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
- (void)remove(temp);
- free(temp);
+ (void)remove(ctx->tmpname);
+ free(ctx->tmpname);
+ ctx->tmpname = NULL;
return -1;
}
#else
@@ -206,19 +178,16 @@
int fd;
struct file_clone_range range;
struct stat st;
-
+
if (fstat(fileno(ctx->f), &st) < 0) {
zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
- free(temp);
return -1;
}
-
- if ((fd = mkstemp(temp)) < 0) {
- zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
- free(temp);
+
+ if ((fd = create_temp_file(ctx, true)) < 0) {
return -1;
}
-
+
range.src_fd = fileno(ctx->f);
range.src_offset = 0;
range.src_length = ((offset + st.st_blksize - 1) / st.st_blksize) * st.st_blksize;
@@ -229,16 +198,18 @@
if (ioctl(fd, FICLONERANGE, &range) < 0) {
zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
(void)close(fd);
- (void)remove(temp);
- free(temp);
+ (void)remove(ctx->tmpname);
+ free(ctx->tmpname);
+ ctx->tmpname = NULL;
return -1;
}
if ((tfp = fdopen(fd, "r+b")) == NULL) {
zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
(void)close(fd);
- (void)remove(temp);
- free(temp);
+ (void)remove(ctx->tmpname);
+ free(ctx->tmpname);
+ ctx->tmpname = NULL;
return -1;
}
}
@@ -246,20 +217,21 @@
if (ftruncate(fileno(tfp), (off_t)offset) < 0) {
(void)fclose(tfp);
- (void)remove(temp);
- free(temp);
+ (void)remove(ctx->tmpname);
+ free(ctx->tmpname);
+ ctx->tmpname = NULL;
return -1;
}
if (fseeko(tfp, (off_t)offset, SEEK_SET) < 0) {
- (void)fclose(tfp);
- (void)remove(temp);
- free(temp);
zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
+ (void)fclose(tfp);
+ (void)remove(ctx->tmpname);
+ free(ctx->tmpname);
+ ctx->tmpname = NULL;
return -1;
}
ctx->fout = tfp;
- ctx->tmpname = temp;
return 0;
}
@@ -312,3 +284,78 @@
return (zip_int64_t)ret;
}
+
+
+static int create_temp_file(zip_source_file_context_t *ctx, bool create_file) {
+ char *temp;
+ int mode;
+ struct stat st;
+ int fd;
+ char *start, *end;
+
+ if (stat(ctx->fname, &st) == 0) {
+ mode = st.st_mode;
+ }
+ else {
+ mode = -1;
+ }
+
+ if ((temp = (char *)malloc(strlen(ctx->fname) + 13)) == NULL) {
+ zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
+ return -1;
+ }
+ sprintf(temp, "%s.XXXXXX.part", ctx->fname);
+ end = temp + strlen(temp) - 5;
+ start = end - 6;
+
+ for (;;) {
+ zip_uint32_t value = zip_random_uint32();
+ char *xs = start;
+
+ while (xs < end) {
+ char digit = value % 36;
+ if (digit < 10) {
+ *(xs++) = digit + '0';
+ }
+ else {
+ *(xs++) = digit - 10 + 'a';
+ }
+ value /= 36;
+ }
+
+ if (create_file) {
+ if ((fd = open(temp, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, mode == -1 ? 0666 : (mode_t)mode)) >= 0) {
+ if (mode != -1) {
+ /* open() honors umask(), which we don't want in this case */
+#ifdef HAVE_FCHMOD
+ (void)fchmod(fd, (mode_t)mode);
+#else
+ (void)chmod(temp, (mode_t)mode);
+#endif
+ }
+ break;
+ }
+ if (errno != EEXIST) {
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
+ free(temp);
+ return -1;
+ }
+ }
+ else {
+ if (stat(temp, &st) < 0) {
+ if (errno == ENOENT) {
+ break;
+ }
+ else {
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
+ free(temp);
+ return -1;
+ }
+ }
+ }
+ }
+
+ ctx->tmpname = temp;
+
+ return create_file ? fd : 0;
+}
diff --git a/lib/zipint.h b/lib/zipint.h
index eab1e3a..6a26dc3 100644
--- a/lib/zipint.h
+++ b/lib/zipint.h
@@ -576,7 +576,7 @@
bool _zip_hash_reserve_capacity(zip_hash_t *hash, zip_uint64_t capacity, zip_error_t *error);
bool _zip_hash_revert(zip_hash_t *hash, zip_error_t *error);
-int _zip_mkstempm(char *path, int mode);
+int _zip_mkstempm(char *path, int mode, bool create_file);
zip_t *_zip_open(zip_source_t *, unsigned int, zip_error_t *);