diff --git a/lib/zip_source_file_win32.c b/lib/zip_source_file_win32.c index 3c55d601f..2e63f5cf2 100644 --- a/lib/zip_source_file_win32.c +++ b/lib/zip_source_file_win32.c @@ -84,8 +84,7 @@ void _zip_win32_op_close(zip_source_file_context_t *ctx) { zip_int64_t _zip_win32_op_read(zip_source_file_context_t *ctx, void *buf, zip_uint64_t len) { DWORD i; - /* TODO: cap len to "DWORD_MAX" */ - if (!ReadFile((HANDLE)ctx->f, buf, (DWORD)len, &i, NULL)) { + if (!ReadFile((HANDLE)ctx->f, buf, _zip_win32_clamp_length(len), &i, NULL)) { zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError())); return -1; } @@ -166,6 +165,11 @@ int _zip_win32_error_to_errno(DWORD win32err) { } +DWORD _zip_win32_clamp_length(zip_uint64_t len) { + return (DWORD)ZIP_MIN(len, ZIP_UINT32_MAX); +} + + static bool _zip_stat_win32(zip_source_file_context_t *ctx, zip_source_file_stat_t *st, HANDLE h) { FILETIME mtimeft; time_t mtime; diff --git a/lib/zip_source_file_win32.h b/lib/zip_source_file_win32.h index da691f0a4..1a0d2b7b0 100644 --- a/lib/zip_source_file_win32.h +++ b/lib/zip_source_file_win32.h @@ -67,6 +67,7 @@ typedef struct zip_win32_file_operations zip_win32_file_operations_t; extern zip_source_file_operations_t _zip_source_file_win32_named_ops; void _zip_win32_op_close(zip_source_file_context_t *ctx); +DWORD _zip_win32_clamp_length(zip_uint64_t len); 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_named.c b/lib/zip_source_file_win32_named.c index df3c41ce2..9fdfc99e6 100644 --- a/lib/zip_source_file_win32_named.c +++ b/lib/zip_source_file_win32_named.c @@ -241,13 +241,27 @@ static char *_zip_win32_named_op_string_duplicate(zip_source_file_context_t *ctx static zip_int64_t _zip_win32_named_op_write(zip_source_file_context_t *ctx, const void *data, zip_uint64_t len) { + const zip_uint8_t *buf = (const zip_uint8_t *)data; + zip_uint64_t written = 0; DWORD ret; - 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; + + while (written < len) { + DWORD chunk = _zip_win32_clamp_length(len - written); + const void *chunk_data = written == 0 ? data : buf + written; + + if (!WriteFile((HANDLE)ctx->fout, chunk_data, chunk, &ret, NULL)) { + zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError())); + return -1; + } + if (ret == 0) { + zip_error_set(&ctx->error, ZIP_ER_WRITE, EINTR); + return -1; + } + + written += ret; } - return (zip_int64_t)ret; + return (zip_int64_t)written; }