Convert all Windows file sources to new framework.
Not tested, not yet included in build.
diff --git a/developer-xcode/libzip.xcodeproj/project.pbxproj b/developer-xcode/libzip.xcodeproj/project.pbxproj
index 2fd9fe7..8ef4e86 100644
--- a/developer-xcode/libzip.xcodeproj/project.pbxproj
+++ b/developer-xcode/libzip.xcodeproj/project.pbxproj
@@ -635,6 +635,9 @@
4B93995F24640B1700AEBDA4 /* zip_source_file_win32.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = zip_source_file_win32.h; sourceTree = "<group>"; };
4B93996024640B1700AEBDA4 /* zip_source_file_win32.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32.c; sourceTree = "<group>"; };
4B93996124641D5700AEBDA4 /* zip_source_file_win32_ansi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32_ansi.c; sourceTree = "<group>"; };
+ 4B93996224643F5700AEBDA4 /* zip_source_file_win32_utf8.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32_utf8.c; sourceTree = "<group>"; };
+ 4B9399632464401300AEBDA4 /* zip_source_file_win32_utf16.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32_utf16.c; sourceTree = "<group>"; };
+ 4B93996424644E7E00AEBDA4 /* zip_source_file_win32_write.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zip_source_file_win32_write.c; sourceTree = "<group>"; };
4B97204D188EBE85002FAFAD /* zip_file_get_external_attributes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_file_get_external_attributes.c; sourceTree = "<group>"; };
4B97204E188EBE85002FAFAD /* zip_file_set_external_attributes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip_file_set_external_attributes.c; sourceTree = "<group>"; };
4BACD57715BC2AEF00920691 /* add_from_filep.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = add_from_filep.c; path = ../regress/add_from_filep.c; sourceTree = "<group>"; };
@@ -1496,6 +1499,9 @@
4B93995824631B3E00AEBDA4 /* zip_source_file_stdio.h */,
4B93996024640B1700AEBDA4 /* zip_source_file_win32.c */,
4B93996124641D5700AEBDA4 /* zip_source_file_win32_ansi.c */,
+ 4B93996424644E7E00AEBDA4 /* zip_source_file_win32_write.c */,
+ 4B9399632464401300AEBDA4 /* zip_source_file_win32_utf16.c */,
+ 4B93996224643F5700AEBDA4 /* zip_source_file_win32_utf8.c */,
4B93995F24640B1700AEBDA4 /* zip_source_file_win32.h */,
4B93995924631B3E00AEBDA4 /* zip_source_file.h */,
4BDC722F15B1B25E00236D3C /* zip_source_free.c */,
diff --git a/lib/zip_source_file_win32.c b/lib/zip_source_file_win32.c
index 8e55dd7..dbb21da 100644
--- a/lib/zip_source_file_win32.c
+++ b/lib/zip_source_file_win32.c
@@ -33,7 +33,7 @@
#include "zip_source_file_win32.h"
-zip_source_file_operations_t ops_win32_read = {
+static zip_source_file_operations_t ops_win32_read = {
_zip_win32_op_close,
NULL,
NULL,
@@ -67,13 +67,13 @@
return NULL;
}
- return zip_source_file_common_new(NULL, h, start, len, NULL, ops_win32_read, &za->error);
+ return zip_source_file_common_new(NULL, h, start, len, NULL, ops_win32_read, NULL, error);
}
void
zip_win32_op_close(zip_source_file_context_t *ctx) {
- CloseHandle(ctx->h);
+ CloseHandle((HANDLE)ctx->f);
}
@@ -129,7 +129,7 @@
zip_int64_t
_zip_win32_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) {
DWORD ret;
- if (!WriteFile(ctx->hout, data, (DWORD)len, &ret, NULL) || ret != len) {
+ if (!WriteFile((HANDLE)ctx->fout, data, (DWORD)len, &ret, NULL) || ret != len) {
zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
return -1;
}
@@ -143,7 +143,7 @@
LARGE_INTEGER zero;
LARGE_INTEGER new_offset;
- if (!SetFilePointerEx(ctx->h, zero, &new_offset, FILE_CURRENT)) {
+ if (!SetFilePointerEx((HANDLE)ctx->f, zero, &new_offset, FILE_CURRENT)) {
zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));
return -1;
}
@@ -175,6 +175,64 @@
}
}
+zip_int64_t
+_zip_win32_create_temp_output(zip_source_file_context_t *ctx, char *tmpname, size_t tmpname_size, _zip_win32_open_t open, _zip_win32_mktmepname_t mktempname) {
+ /* Windows has GetTempFileName(), but it closes the file after
+ creation, leaving it open to a horrible race condition. So
+ we reinvent the wheel.
+ */
+
+ int i;
+ HANDLE th = INVALID_HANDLE_VALUE;
+ void *temp = NULL;
+ PSECURITY_DESCRIPTOR psd = NULL;
+ PSECURITY_ATTRIBUTES psa = NULL;
+ SECURITY_ATTRIBUTES sa;
+ SECURITY_INFORMATION si;
+ DWORD success;
+ PACL dacl = NULL;
+
+ /*
+ Read the DACL from the original file, so we can copy it to the temp file.
+ If there is no original file, or if we can't read the DACL, we'll use the
+ default security descriptor.
+ */
+
+ if ((HANDLE)ctx->f != INVALID_HANDLE_VALUE && GetFileType((HANDLE)ctx->f) == FILE_TYPE_DISK) {
+ si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
+ success = GetSecurityInfo(ctx->h, SE_FILE_OBJECT, si, NULL, NULL, &dacl, NULL, &psd);
+ if (success == ERROR_SUCCESS) {
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = FALSE;
+ sa.lpSecurityDescriptor = psd;
+ psa = &sa;
+ }
+ }
+
+ #ifndef MS_UWP
+ value = GetTickCount();
+ #else
+ value = (zip_uint32_t)GetTickCount64();
+ #endif
+
+ for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) {
+ mktempname(tmpname, tmpname_size, value + i);
+ th = open(ctx, tmpname, true, psa);
+
+ if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS)
+ break;
+ }
+
+ LocalFree(psd);
+
+ if (th == INVALID_HANDLE_VALUE) {
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError()));
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return th;
+}
+
bool
_zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h) {
FILETIME mtimeft;
diff --git a/lib/zip_source_file_win32.h b/lib/zip_source_file_win32.h
index 96b76db..63aa48e 100644
--- a/lib/zip_source_file_win32.h
+++ b/lib/zip_source_file_win32.h
@@ -34,6 +34,28 @@
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+/* 0x0501 => Windows XP; needs to be at least this value because of GetFileSizeEx */
+#if !defined(MS_UWP) && !defined(_WIN32_WINNT)
+#define _WIN32_WINNT 0x0501
+#endif
+
+#include <windows.h>
+
+struct zip_source_file_win32_write_operations {
+ char *(*allocate_tempname)(const char *name, size_t extra_chars),
+ HANDLE (*create_file)(const char *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file),
+ bool (*delete_file)(const char *name),
+ DWORD (*get_file_attributes)(const char *name),
+ void (*make_tempname)(char *buf, size_t len, const char *name, int i),
+ bool (*move_file)(const char *from, const char *to),
+ bool (*set_file_attributes)(const char *name, DWORD attributes),
+ char *(*strdup)(const char *string)
+};
+
+typedef struct zip_source_file_win32_write_operations zip_source_file_win32_write_operations_t;
+
+zip_source_file_operations_t zip_source_file_win32_write_operations;
+
zip_int64_t _zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len);
bool _zip_win32_op_seek(zip_source_file_context_t *ctx, void *f, zip_int64_t offset, int whence);
zip_int64_t _zip_win32_op_tell(zip_source_file_context_t *ctx, void *f);
diff --git a/lib/zip_source_file_win32_ansi.c b/lib/zip_source_file_win32_ansi.c
index 4017428..7dcf15c 100644
--- a/lib/zip_source_file_win32_ansi.c
+++ b/lib/zip_source_file_win32_ansi.c
@@ -1,5 +1,5 @@
/*
- zip_source_file_win32_ansi.c -- read/write Windows ANSI file source implementation
+ zip_source_file_win32_ansi.c -- Windows file source write operations for ANSI interface
Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
This file is part of libzip, a library to manipulate ZIP archives.
@@ -33,138 +33,47 @@
#include "zip_source_file_win32.h"
-static zip_int64_t _zip_win32_ansi_op_commit_write(zip_source_file_context_t *ctx);
-static zip_int64_t _zip_win32_ansi_op_create_temp_output(zip_source_file_context_t *ctx);
-static zip_int64_t _zip_win32_ansi_op_commit_write(zip_source_file_context_t *ctx);
-static bool _zip_win32_ansi_op_open(zip_source_file_context_t *ctx);
-static zip_int64_t _zip_win32_ansi_op_remove(zip_source_file_context_t *ctx);
-static void _zip_win32_ansi_op_rollback_write(zip_source_file_context_t *ctx);
-static bool _zip_win32_ansi_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);
+static char *ansi_allocate_tempname(const char *name, size_t extra_chars);
+static void ansi_make_tempname(char *buf, size_t len, const char *name, int i);
-static HANDLE win32_ansi_open(zip_source_file_context_t *ctx);
+zip_source_file_win32_write_operations_t ops_ansi {
+ ansi_allocate_tempname,
+ CreateFileA,
+ DeleteFileA,
+ GetFileAttributesA,
+ ansi_make_tempname,
+ MoveFileA,
+ SetFileAttributesA,
+ strdup
+};
-zip_source_file_operations_t ops_win32_read = {
- _zip_win32_op_close,
- _zip_win32_ansi_op_commit_write,
- _zip_win32_ansi_op_create_temp_output,
- NULL,
- _zip_win32_ansi_op_open,
- _zip_win32_op_read,
- _zip_win32_ansi_op_remove,
- _zip_win32_ansi_op_rollback_write,
- _zip_win32_op_seek,
- _zip_win32_ansi_op_stat,
- strdup,
- _zip_win32_op_tell,
- _zip_win32_op_write
-}
+ZIP_EXTERN zip_source_t *
+zip_source_win32a(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
+ if (za == NULL)
+ return NULL;
-static zip_int64_t
-_zip_win32_ansi_op_commit_write(zip_source_file_context_t *ctx) {
- if (!CloseHandle((HANDLE)ctx->fout)) {
- zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
- return -1
- }
-
- DWORD attributes = GetFileAttributesA(ctx->tmpname);
- if (attributes == INVALID_FILE_ATTRIBUTES) {
- zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
- return -1;
- }
-
- if (attributes & FILE_ATTRIBUTE_TEMPORARY) {
- if (!SetFileAttributesA(ctx->tmpname, attributes & ~FILE_ATTRIBUTE_TEMPORARY)) {
- zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
- return -1;
- }
- }
-
- if (!MoveFileExA(ctx->tmpname, ctx->fname, MOVEFILE_REPLACE_EXISTING)) {
- zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
- return -1;
- }
-
- return 0;
-}
-
-static zip_int64_t
-_zip_win32_ansi_op_create_temp_output(zip_source_file_context_t *ctx) {
- size_t len;
- void *temp;
- HANDLE h;
-
- len = strlen(ctx->fname) + 10;
- if ((temp = malloc(len)) == NULL) {
- zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
- return false;
- }
- if (sprintf((char *)*temp, "%s.%08x", (const char *)ctx->fname, value) != len - 1) {
- return -1;
- }
-
- h = CreateFileA((const char *)*temp, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY, NULL);
- if (h == INVALID_HANDLE_VALUE) {
- free(temp);
- return -1;
- }
-
- ctx->tmpname = temp;
- ctx->fout = h;
-
- return 0;
+ return zip_source_win32a_create(fname, start, len, &za->error);
}
-
-static bool
-_zip_win32_ansi_op_open(zip_source_file_context_t *ctx) {
- HANDLE h = win32_ansi_open(ctx);
-
- if (h == INVALID_HANDLE_VALUE) {
- return false;
+ZIP_EXTERN zip_source_t *
+zip_source_win32a_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
+ if (fname == NULL || length < -1) {
+ zip_error_set(error, ZIP_ER_INVAL, 0);
+ return NULL;
}
-
- ctx->f = h;
- return true;
+
+ return zip_source_file_common_new(fname, NULL, start, length, NULL, &zip_source_file_win32_write_operations, &ops_ansi, error);
}
-static zip_int64_t
-_zip_win32_ansi_op_remove(zip_source_file_context_t *ctx) {
- DeleteFileA((const char *)fname);
- /* TODO: propagate errors */
- return 0;
+static char *
+ansi_allocate_tempname(const char *name, size_t extra_chars) {
+ return (char *)malloc(strlen(name) + extra_chars);
}
static void
-_zip_win32_ansi_op_rollback_write(zip_source_file_context_t *ctx) {
- if (ctx->fout) {
- CloseHandle((HANDLE)ctx->fout);
- }
- DeleteFileA(ctx->tmpname);
-}
-
-
-static bool
-_zip_win32_ansi_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {
- HANDLE h = win32_ansi_open(ctx);
-
- if (h == INVALID_HANDLE_VALUE) {
- return false;
- }
-
- return _zip_stat_win32(ctx, st, h);
-}
-
-
-static HANDLE
-win32_ansi_open(zip_source_file_context_t *ctx) {
- HANDLE h = CreateFileA(ctx->fname, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (h == INVALID_HANDLE_VALUE) {
- zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError()));
- }
-
- return h;
+ansi_make_tempname(char *buf, size_t len, const char *name, int i) {
+ snprintf(buf, len, "%s.%d", name, i);
}
diff --git a/lib/zip_source_file_win32_utf16.c b/lib/zip_source_file_win32_utf16.c
new file mode 100644
index 0000000..34aa923
--- /dev/null
+++ b/lib/zip_source_file_win32_utf16.c
@@ -0,0 +1,123 @@
+/*
+ zip_source_file_win32_utf16.c -- Windows file source write operations for UTF-16 interface
+ Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zip_source_file_win32.h"
+
+static char *utf16_allocate_tempname(const char *name, size_t extra_chars);
+static HANDLE utf16_create_file(const char *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file);
+static bool utf16_delete_file(const char *name);
+static DWORD utf16_get_file_attributes(const char *name);
+static void utf16_make_tempname(char *buf, size_t len, const char *name, int i);
+static bool utf16_move_file(const char *from, const char *to);
+static bool utf16_set_file_attributes(const char *name, DWORD attributes);
+static char *utf16_strdup(const char *string);
+
+zip_source_file_win32_write_operations_t ops_utf16 {
+ utf16_allocate_tempname,
+ utf16_create_file,
+ utf16_delete_file,
+ utf16_get_file_attributes,
+ utf16_make_tempname,
+ utf16_move_file,
+ utf16_set_file_attributes,
+ utf16_strdup
+};
+
+ZIP_EXTERN zip_source_t *
+zip_source_win32w(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
+ if (za == NULL)
+ return NULL;
+
+ return zip_source_win32w_create(fname, start, len, &za->error);
+}
+
+
+ZIP_EXTERN zip_source_t *
+zip_source_win32w_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
+ if (fname == NULL || length < -1) {
+ zip_error_set(error, ZIP_ER_INVAL, 0);
+ return NULL;
+ }
+
+ return zip_source_file_common_new(fname, NULL, start, length, NULL, &zip_source_file_win32_write_operations, &ops_utf16, error);
+}
+
+
+static char *
+utf16_allocate_tempname(const char *name, size_t extra_chars) {
+ return (char *)malloc((wcslen(name) + extra_chars) * sizeof(wchar_t));
+}
+
+
+HANDLE utf16_create_file(const char *name, DWORD access, DWORD share_mode, PSECURITY_ATTRIBUTES security_attributes, DWORD creation_disposition, DWORD file_attributes, HANDLE template_file) {
+#ifdef MS_UWP
+ CREATEFILE2_EXTENDED_PARAMETERS extParams = {0};
+ extParams.dwFileAttributes = file_attributes;
+ extParams.dwFileFlags = FILE_FLAG_RANDOM_ACCESS;
+ extParams.dwSecurityQosFlags = SECURITY_ANONYMOUS;
+ extParams.dwSize = sizeof(extParams);
+ extParams.hTemplateFile = NULL;
+ extParams.lpSecurityAttributes = security_attributes;
+
+ return CreateFile2((const wchar_t *)name, access, share_mode, creation_disposition, &extParams);
+ #else
+ return CreateFileW((const wchar_t *)name, access, share_mode, security_attributes, creation_disposition, file_attributes, NULL);
+ #endif
+}
+
+
+bool utf16_delete_file(const char *name) {
+ return DeleteFileW((const wchar_t *)name);
+}
+
+
+DWORD utf16_get_file_attributes(const char *name) {
+ return GetFileAttributesW((const wchar_t *)name)
+}
+
+
+static void
+utf16_make_tempname(char *buf, size_t len, const char *name, int i) {
+ _snwprintf((wchar_t *)*buf, len, L"%s.%08x", (const wchar_t *)name, i);
+}
+
+static bool
+utf16_set_file_attributes(const char *name, DWORD attributes) {
+ return SetFileAttributesW((const wchar_t *)name, attributes);
+}
+
+
+static char *
+utf16_strdup(const char *string) {
+ return (char *)_wcsdup((const wchar_t *)string);
+}
diff --git a/lib/zip_source_file_win32_utf8.c b/lib/zip_source_file_win32_utf8.c
new file mode 100644
index 0000000..eaeacdc
--- /dev/null
+++ b/lib/zip_source_file_win32_utf8.c
@@ -0,0 +1,73 @@
+/*
+ zip_source_file_win32_ansi.c -- read/write Windows UTF-8 file source implementation
+ Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zip_source_file_win32.h"
+
+ZIP_EXTERN zip_source_t *
+zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
+ if (za == NULL) {
+ return NULL;
+ }
+
+ return zip_source_file_create(fname, start, len, &za->error);
+}
+
+
+ZIP_EXTERN zip_source_t *
+zip_source_file_create(const char *fname, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
+ int size;
+ wchar_t *wfname;
+ zip_source_t *source;
+
+ if (fname == NULL || length < -1) {
+ zip_error_set(error, ZIP_ER_INVAL, 0);
+ return NULL;
+ }
+
+ /* Convert fname from UTF-8 to Windows-friendly UTF-16. */
+ size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, NULL, 0);
+ if (size == 0) {
+ zip_error_set(error, ZIP_ER_INVAL, 0);
+ return NULL;
+ }
+ if ((wfname = (wchar_t *)malloc(sizeof(wchar_t) * size)) == NULL) {
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
+ return NULL;
+ }
+ MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, wfname, size);
+
+ source = zip_source_win32w_create(wfname, start, length, error);
+
+ free(wfname);
+ return source;
+}
diff --git a/lib/zip_source_file_win32_write.c b/lib/zip_source_file_win32_write.c
new file mode 100644
index 0000000..640860f
--- /dev/null
+++ b/lib/zip_source_file_win32_write.c
@@ -0,0 +1,225 @@
+/*
+ zip_source_file_win32_write.c -- read/write Windows file source implementation
+ Copyright (C) 1999-2020 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "zip_source_file_win32.h"
+
+static zip_int64_t _zip_win32_write_op_commit_write(zip_source_file_context_t *ctx);
+static zip_int64_t _zip_win32_write_op_create_temp_output(zip_source_file_context_t *ctx);
+static zip_int64_t _zip_win32_write_op_commit_write(zip_source_file_context_t *ctx);
+static bool _zip_win32_write_op_open(zip_source_file_context_t *ctx);
+static zip_int64_t _zip_win32_write_op_remove(zip_source_file_context_t *ctx);
+static void _zip_win32_write_op_rollback_write(zip_source_file_context_t *ctx);
+static bool _zip_win32_write_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st);
+
+static HANDLE win32_write_open(zip_source_file_context_t *ctx);
+
+/* clang-format off */
+zip_source_file_operations_t zip_source_file_win32_write_operations = {
+ _zip_win32_op_close,
+ _zip_win32_write_op_commit_write,
+ _zip_win32_write_op_create_temp_output,
+ NULL,
+ _zip_win32_write_op_open,
+ _zip_win32_op_read,
+ _zip_win32_write_op_remove,
+ _zip_win32_write_op_rollback_write,
+ _zip_win32_op_seek,
+ _zip_win32_write_op_stat,
+ strdup,
+ _zip_win32_op_tell,
+ _zip_win32_op_write
+};
+/* clang-format on */
+
+static zip_int64_t
+_zip_win32_write_op_commit_write(zip_source_file_context_t *ctx) {
+ zip_source_file_win32_write_operations_t *write_ops = (zip_source_file_win32_write_operations_t *)ctx->ops_userdata;
+
+ if (!CloseHandle((HANDLE)ctx->fout)) {
+ zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
+ return -1
+ }
+
+ DWORD attributes = write_ops->get_file_attributes(ctx->tmpname);
+ if (attributes == INVALID_FILE_ATTRIBUTES) {
+ zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
+ return -1;
+ }
+
+ if (attributes & FILE_ATTRIBUTE_TEMPORARY) {
+ if (!write_ops->set_file_attributes(ctx->tmpname, attributes & ~FILE_ATTRIBUTE_TEMPORARY)) {
+ zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
+ return -1;
+ }
+ }
+
+ if (!write_ops->move_file(ctx->tmpname, ctx->fname, MOVEFILE_REPLACE_EXISTING)) {
+ zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
+ return -1;
+ }
+
+ return 0;
+}
+
+static zip_int64_t
+_zip_win32_write_op_create_temp_output(zip_source_file_context_t *ctx) {
+ zip_source_file_win32_write_operations_t *write_ops = (zip_source_file_win32_write_operations_t *)ctx->ops_userdata;
+
+ int i;
+ HANDLE th = INVALID_HANDLE_VALUE;
+ void *temp = NULL;
+ PSECURITY_DESCRIPTOR psd = NULL;
+ PSECURITY_ATTRIBUTES psa = NULL;
+ SECURITY_ATTRIBUTES sa;
+ SECURITY_INFORMATION si;
+ DWORD success;
+ PACL dacl = NULL;
+ char *tempname = NULL;
+ size_t tempname_size = 0;
+
+ if ((HANDLE)ctx->f != INVALID_HANDLE_VALUE && GetFileType((HANDLE)ctx->f) == FILE_TYPE_DISK) {
+ si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
+ success = GetSecurityInfo(ctx->h, SE_FILE_OBJECT, si, NULL, NULL, &dacl, NULL, &psd);
+ if (success == ERROR_SUCCESS) {
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = FALSE;
+ sa.lpSecurityDescriptor = psd;
+ psa = &sa;
+ }
+ }
+
+ #ifndef MS_UWP
+ value = GetTickCount();
+#else
+ value = (zip_uint32_t)GetTickCount64();
+#endif
+
+ if ((tempname = write_ops->allocate_tempname(ctx->fname, 10, &tempname_size)) == NULL) {
+ zip_error_set(&ctx->error, ZIP_ER_NOMEM, 0);
+ return -1;
+ }
+
+ for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) {
+ write_ops->make_tempname(tempname, tempname_size, ctx->fname, value + i);
+
+ th = win32_write_open(ctx, tempname, true, psa);
+ if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS)
+ break;
+ }
+
+ if (th == INVALID_HANDLE_VALUE) {
+ free(tempname);
+ LocalFree(psd);
+ zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError()));
+ return -1;
+ }
+
+ LocalFree(psd);
+ ctx->fout = th;
+ ctx->tmpname = tempname;
+
+ return 0;
+}
+
+
+static bool
+_zip_win32_write_op_open(zip_source_file_context_t *ctx) {
+ HANDLE h = win32_write_open(ctx, ctx->fname, false, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ ctx->f = h;
+ return true;
+}
+
+
+static zip_int64_t
+_zip_win32_write_op_remove(zip_source_file_context_t *ctx) {
+ zip_source_file_win32_write_operations_t *write_ops = (zip_source_file_win32_write_operations_t *)ctx->ops_userdata;
+
+ if (!write_ops->delete_file(ctx->fname)) {
+ zip_error_set(&ctx->error, ZIP_ER_REMOVE, _zip_win32_error_to_errno(GetLastError()));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void
+_zip_win32_write_op_rollback_write(zip_source_file_context_t *ctx) {
+ zip_source_file_win32_write_operations_t *write_ops = (zip_source_file_win32_write_operations_t *)ctx->ops_userdata;
+
+ if (ctx->fout) {
+ CloseHandle((HANDLE)ctx->fout);
+ }
+ write_ops->delete_file(ctx->tmpname);
+}
+
+
+static bool
+_zip_win32_write_op_stat(zip_source_file_context_t *ctx, zip_source_file_stat_t *st) {
+ HANDLE h = win32_write_open(ctx, ctx->fname, false, NULL);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ return _zip_stat_win32(ctx, st, h);
+}
+
+
+static HANDLE
+win32_write_open(zip_source_file_context_t *ctx, const char *name, bool temporary, PSECURITY_ATTRIBUTES security_attributes) {
+ DWORD access = GENERIC_READ;
+ DWORD share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ DWORD creation_disposition = OPEN_EXISTING;
+ DWORD file_attributes = FILE_ATTRIBUTE_NORMAL;
+
+ if (temporary) {
+ access |= GENERIC_WRITE;
+ share_mode = FILE_SHARE_READ;
+ creation_disposition = CREATE_NEW;
+ file_attributes |= FILE_ATTRIBUTE_TEMPORARY;
+ }
+
+ HANDLE h = write_ops->create_file(name, access, share_mode, security_attributes, creation_disposition, file_attributes);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError()));
+ }
+
+ return h;
+}
diff --git a/lib/zip_source_win32utf8.c b/lib/zip_source_win32utf8.c
index 3d2ce39..6b33560 100644
--- a/lib/zip_source_win32utf8.c
+++ b/lib/zip_source_win32utf8.c
@@ -40,9 +40,10 @@
ZIP_EXTERN zip_source_t *
zip_source_file(zip_t *za, const char *fname, zip_uint64_t start, zip_int64_t len) {
- if (za == NULL)
- return NULL;
-
+ if (za == NULL) {
+ return NULL;
+ }
+
return zip_source_file_create(fname, start, len, &za->error);
}
@@ -54,24 +55,24 @@
zip_source_t *source;
if (fname == NULL || length < -1) {
- zip_error_set(error, ZIP_ER_INVAL, 0);
- return NULL;
+ zip_error_set(error, ZIP_ER_INVAL, 0);
+ return NULL;
}
/* Convert fname from UTF-8 to Windows-friendly UTF-16. */
size = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, NULL, 0);
if (size == 0) {
- zip_error_set(error, ZIP_ER_INVAL, 0);
- return NULL;
+ zip_error_set(error, ZIP_ER_INVAL, 0);
+ return NULL;
}
if ((wfname = (wchar_t *)malloc(sizeof(wchar_t) * size)) == NULL) {
- zip_error_set(error, ZIP_ER_MEMORY, 0);
- return NULL;
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
+ return NULL;
}
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fname, -1, wfname, size);
source = zip_source_win32w_create(wfname, start, length, error);
-
+
free(wfname);
return source;
}