blob: 7fe003dca687bfae6d807f74436f8e39f0066e46 [file] [log] [blame]
Andrew Molyneux516cab02014-12-24 20:07:05 +00001/*
2zip_source_win32file.c -- create data source from HANDLE (Win32)
Thomas Klausner00ff6bb2016-01-08 08:21:22 +01003Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner
Andrew Molyneux516cab02014-12-24 20:07:05 +00004
5This file is part of libzip, a library to manipulate ZIP archives.
6The authors can be contacted at <libzip@nih.at>
7
8Redistribution and use in source and binary forms, with or without
9modification, are permitted provided that the following conditions
10are met:
111. Redistributions of source code must retain the above copyright
12notice, this list of conditions and the following disclaimer.
132. Redistributions in binary form must reproduce the above copyright
14notice, this list of conditions and the following disclaimer in
15the documentation and/or other materials provided with the
16distribution.
173. The names of the authors may not be used to endorse or promote
18products derived from this software without specific prior
19written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
22OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
25DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
29IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*/
33
34
Andrew Molyneux516cab02014-12-24 20:07:05 +000035#include <wchar.h>
Andrew Molyneux516cab02014-12-24 20:07:05 +000036#include <stdlib.h>
37#include <string.h>
38
Andrew Molyneux516cab02014-12-24 20:07:05 +000039#include "zipint.h"
Andrew Molyneuxc6a581a2015-02-07 14:00:05 +000040#include "zipwin32.h"
Andrew Molyneux516cab02014-12-24 20:07:05 +000041
42static zip_int64_t _win32_read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
43static int _win32_create_temp_file(_zip_source_win32_read_file_t *ctx);
44static int _zip_filetime_to_time_t(FILETIME ft, time_t *t);
Thomas Klausner3f03f6d2015-01-27 15:24:59 +010045static int _zip_seek_win32_u(void *h, zip_uint64_t offset, int whence, zip_error_t *error);
46static int _zip_seek_win32(void *h, zip_int64_t offset, int whence, zip_error_t *error);
47static int _zip_win32_error_to_errno(unsigned long win32err);
Andrew Molyneux516cab02014-12-24 20:07:05 +000048static int _zip_stat_win32(void *h, zip_stat_t *st, _zip_source_win32_read_file_t *ctx);
49
50ZIP_EXTERN zip_source_t *
Dieter Baron666d5152015-03-11 12:13:17 +010051zip_source_win32handle(zip_t *za, HANDLE h, zip_uint64_t start, zip_int64_t len)
Andrew Molyneux516cab02014-12-24 20:07:05 +000052{
53 if (za == NULL)
54 return NULL;
55
Dieter Baron666d5152015-03-11 12:13:17 +010056 return zip_source_win32handle_create(h, start, len, &za->error);
Andrew Molyneux516cab02014-12-24 20:07:05 +000057}
58
59
60ZIP_EXTERN zip_source_t *
Dieter Baron666d5152015-03-11 12:13:17 +010061zip_source_win32handle_create(HANDLE h, zip_uint64_t start, zip_int64_t length, zip_error_t *error)
Andrew Molyneux516cab02014-12-24 20:07:05 +000062{
63 if (h == INVALID_HANDLE_VALUE || length < -1) {
64 zip_error_set(error, ZIP_ER_INVAL, 0);
65 return NULL;
66 }
67
68 return _zip_source_win32_handle_or_name(NULL, h, start, length, 1, NULL, NULL, error);
69}
70
Andrew Molyneux73d4a302014-12-24 22:00:37 +000071
Andrew Molyneux516cab02014-12-24 20:07:05 +000072zip_source_t *
73_zip_source_win32_handle_or_name(const void *fname, HANDLE h, zip_uint64_t start, zip_int64_t len, int closep, const zip_stat_t *st, _zip_source_win32_file_ops_t *ops, zip_error_t *error)
74{
75 _zip_source_win32_read_file_t *ctx;
76 zip_source_t *zs;
77
78 if (h == INVALID_HANDLE_VALUE && fname == NULL) {
79 zip_error_set(error, ZIP_ER_INVAL, 0);
80 return NULL;
81 }
82
83 if ((ctx = (_zip_source_win32_read_file_t *)malloc(sizeof(_zip_source_win32_read_file_t))) == NULL) {
84 zip_error_set(error, ZIP_ER_MEMORY, 0);
85 return NULL;
86 }
87
88 ctx->fname = NULL;
89 if (fname) {
90 if ((ctx->fname = ops->op_strdup(fname)) == NULL) {
91 zip_error_set(error, ZIP_ER_MEMORY, 0);
92 free(ctx);
93 return NULL;
94 }
95 }
96
97 ctx->ops = ops;
98 ctx->h = h;
99 ctx->start = start;
100 ctx->end = (len < 0 ? 0 : start + (zip_uint64_t)len);
101 ctx->closep = ctx->fname ? 1 : closep;
102 if (st) {
103 memcpy(&ctx->st, st, sizeof(ctx->st));
104 ctx->st.name = NULL;
105 ctx->st.valid &= ~ZIP_STAT_NAME;
106 }
107 else {
108 zip_stat_init(&ctx->st);
109 }
110
111 ctx->tmpname = NULL;
112 ctx->hout = INVALID_HANDLE_VALUE;
113
114 zip_error_init(&ctx->error);
115
116 ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
117 if (ctx->fname) {
118 HANDLE th;
119
120 th = ops->op_open(ctx);
Andrew Molyneux3ace5422015-02-20 07:13:05 +0000121 if (th == INVALID_HANDLE_VALUE || GetFileType(th) == FILE_TYPE_DISK) {
Andrew Molyneux516cab02014-12-24 20:07:05 +0000122 ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
123 }
124 if (th != INVALID_HANDLE_VALUE) {
125 CloseHandle(th);
126 }
127 }
128 else if (GetFileType(ctx->h) == FILE_TYPE_DISK) {
129 ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
130 }
131
132 if ((zs = zip_source_function_create(_win32_read_file, ctx, error)) == NULL) {
Thomas Klausnera7df0552015-01-27 14:58:33 +0100133 free(ctx->fname);
Andrew Molyneux516cab02014-12-24 20:07:05 +0000134 free(ctx);
135 return NULL;
136 }
137
138 return zs;
139}
140
Andrew Molyneux73d4a302014-12-24 22:00:37 +0000141
Thomas Klausner892fb3b2015-01-27 15:00:57 +0100142static zip_int64_t
Andrew Molyneux516cab02014-12-24 20:07:05 +0000143_win32_read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
144{
145 _zip_source_win32_read_file_t *ctx;
146 char *buf;
147 zip_uint64_t n;
148 DWORD i;
149
150 ctx = (_zip_source_win32_read_file_t *)state;
151 buf = (char *)data;
152
153 switch (cmd) {
154 case ZIP_SOURCE_BEGIN_WRITE:
155 if (ctx->fname == NULL) {
156 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
157 return -1;
158 }
159 return _win32_create_temp_file(ctx);
160
161 case ZIP_SOURCE_COMMIT_WRITE: {
162 if (!CloseHandle(ctx->hout)) {
163 ctx->hout = INVALID_HANDLE_VALUE;
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100164 zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000165 }
166 ctx->hout = INVALID_HANDLE_VALUE;
Andrew Molyneux73d4a302014-12-24 22:00:37 +0000167 if (ctx->ops->op_rename_temp(ctx) < 0) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100168 zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux73d4a302014-12-24 22:00:37 +0000169 return -1;
170 }
Andrew Molyneuxdfde87c2014-12-27 10:47:03 +0000171 free(ctx->tmpname);
172 ctx->tmpname = NULL;
Andrew Molyneux73d4a302014-12-24 22:00:37 +0000173 return 0;
Andrew Molyneux516cab02014-12-24 20:07:05 +0000174 }
175
176 case ZIP_SOURCE_CLOSE:
177 if (ctx->fname) {
178 CloseHandle(ctx->h);
179 ctx->h = INVALID_HANDLE_VALUE;
180 }
181 return 0;
182
183 case ZIP_SOURCE_ERROR:
184 return zip_error_to_data(&ctx->error, data, len);
185
186 case ZIP_SOURCE_FREE:
187 free(ctx->fname);
188 free(ctx->tmpname);
189 if (ctx->closep && ctx->h != INVALID_HANDLE_VALUE)
190 CloseHandle(ctx->h);
191 free(ctx);
192 return 0;
193
194 case ZIP_SOURCE_OPEN:
195 if (ctx->fname) {
196 if ((ctx->h = ctx->ops->op_open(ctx)) == INVALID_HANDLE_VALUE) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100197 zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000198 return -1;
199 }
200 }
201
202 if (ctx->closep && ctx->start > 0) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100203 if (_zip_seek_win32_u(ctx->h, ctx->start, SEEK_SET, &ctx->error) < 0) {
Andrew Molyneux516cab02014-12-24 20:07:05 +0000204 return -1;
205 }
206 }
207 ctx->current = ctx->start;
208 return 0;
209
210 case ZIP_SOURCE_READ:
211 if (ctx->end > 0) {
212 n = ctx->end - ctx->current;
213 if (n > len) {
214 n = len;
215 }
216 }
217 else {
218 n = len;
219 }
220
221 if (n > SIZE_MAX)
222 n = SIZE_MAX;
223
224 if (!ctx->closep) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100225 if (_zip_seek_win32_u(ctx->h, ctx->current, SEEK_SET, &ctx->error) < 0) {
Andrew Molyneux516cab02014-12-24 20:07:05 +0000226 return -1;
227 }
228 }
229
230 if (!ReadFile(ctx->h, buf, (DWORD)n, &i, NULL)) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100231 zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000232 return -1;
233 }
234 ctx->current += i;
235
236 return (zip_int64_t)i;
237
238 case ZIP_SOURCE_REMOVE:
Andrew Molyneuxcb815c42014-12-24 21:24:58 +0000239 if (ctx->ops->op_remove(ctx->fname) < 0) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100240 zip_error_set(&ctx->error, ZIP_ER_REMOVE, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneuxcb815c42014-12-24 21:24:58 +0000241 return -1;
242 }
243 return 0;
Andrew Molyneux516cab02014-12-24 20:07:05 +0000244
245 case ZIP_SOURCE_ROLLBACK_WRITE:
246 if (ctx->hout) {
247 CloseHandle(ctx->hout);
248 ctx->hout = INVALID_HANDLE_VALUE;
249 }
Andrew Molyneuxcb815c42014-12-24 21:24:58 +0000250 ctx->ops->op_remove(ctx->tmpname);
Andrew Molyneux516cab02014-12-24 20:07:05 +0000251 free(ctx->tmpname);
252 ctx->tmpname = NULL;
253 return 0;
254
255 case ZIP_SOURCE_SEEK: {
256 zip_int64_t new_current;
257 int need_seek;
258 zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
259
260 if (args == NULL)
261 return -1;
262
263 need_seek = ctx->closep;
264
265 switch (args->whence) {
266 case SEEK_SET:
267 new_current = args->offset;
268 break;
269
270 case SEEK_END:
271 if (ctx->end == 0) {
272 LARGE_INTEGER zero;
273 LARGE_INTEGER new_offset;
274
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100275 if (_zip_seek_win32(ctx->h, args->offset, SEEK_END, &ctx->error) < 0) {
Andrew Molyneux516cab02014-12-24 20:07:05 +0000276 return -1;
277 }
278 zero.QuadPart = 0;
279 if (!SetFilePointerEx(ctx->h, zero, &new_offset, FILE_CURRENT)) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100280 zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000281 return -1;
282 }
283 new_current = new_offset.QuadPart;
284 need_seek = 0;
285 }
286 else {
287 new_current = (zip_int64_t)ctx->end + args->offset;
288 }
289 break;
290 case SEEK_CUR:
291 new_current = (zip_int64_t)ctx->current + args->offset;
292 break;
293
294 default:
295 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
296 return -1;
297 }
298
299 if (new_current < 0 || (zip_uint64_t)new_current < ctx->start || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end)) {
300 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
301 return -1;
302 }
303
304 ctx->current = (zip_uint64_t)new_current;
305
306 if (need_seek) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100307 if (_zip_seek_win32_u(ctx->h, ctx->current, SEEK_SET, &ctx->error) < 0) {
Andrew Molyneux516cab02014-12-24 20:07:05 +0000308 return -1;
309 }
310 }
311 return 0;
312 }
313
314 case ZIP_SOURCE_SEEK_WRITE: {
315 zip_source_args_seek_t *args;
316
317 args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
318 if (args == NULL) {
319 return -1;
320 }
321
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100322 if (_zip_seek_win32(ctx->hout, args->offset, args->whence, &ctx->error) < 0) {
Andrew Molyneux516cab02014-12-24 20:07:05 +0000323 return -1;
324 }
325 return 0;
326 }
327
328 case ZIP_SOURCE_STAT: {
329 if (len < sizeof(ctx->st))
330 return -1;
331
332 if (ctx->st.valid != 0)
333 memcpy(data, &ctx->st, sizeof(ctx->st));
334 else {
335 DWORD win32err;
336 zip_stat_t *st;
337 HANDLE h;
338 int success;
339
340 st = (zip_stat_t *)data;
341
342 if (ctx->h != INVALID_HANDLE_VALUE) {
343 h = ctx->h;
344 }
345 else {
346 h = ctx->ops->op_open(ctx);
Thomas Klausner3b106ba2016-09-16 15:13:25 +0200347 if (h == INVALID_HANDLE_VALUE) {
348 win32err = GetLastError();
349 if (win32err == ERROR_FILE_NOT_FOUND || win32err == ERROR_PATH_NOT_FOUND) {
350 zip_error_set(&ctx->error, ZIP_ER_READ, ENOENT);
351 return -1;
352 }
Andrew Molyneux3ace5422015-02-20 07:13:05 +0000353 }
Andrew Molyneux516cab02014-12-24 20:07:05 +0000354 }
355
356 success = _zip_stat_win32(h, st, ctx);
357 win32err = GetLastError();
358
359 /* We're done with the handle, so close it if we just opened it. */
360 if (h != ctx->h) {
361 CloseHandle(h);
362 }
363
364 if (success < 0) {
365 /* TODO: Is this the correct error to return in all cases? */
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100366 zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(win32err));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000367 return -1;
368 }
369 }
370 return sizeof(ctx->st);
371 }
372
373 case ZIP_SOURCE_SUPPORTS:
374 return ctx->supports;
375
376 case ZIP_SOURCE_TELL:
377 return (zip_int64_t)ctx->current;
378
379 case ZIP_SOURCE_TELL_WRITE:
380 {
381 LARGE_INTEGER zero;
382 LARGE_INTEGER offset;
383
384 zero.QuadPart = 0;
385 if (!SetFilePointerEx(ctx->hout, zero, &offset, FILE_CURRENT)) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100386 zip_error_set(&ctx->error, ZIP_ER_TELL, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000387 return -1;
388 }
389
390 return offset.QuadPart;
391 }
392
393 case ZIP_SOURCE_WRITE:
394 {
395 DWORD ret;
396 if (!WriteFile(ctx->hout, data, (DWORD)len, &ret, NULL) || ret != len) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100397 zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000398 return -1;
399 }
400
401 return (zip_int64_t)ret;
402 }
403
404 default:
405 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
406 return -1;
407 }
408}
409
Andrew Molyneux73d4a302014-12-24 22:00:37 +0000410
Thomas Klausner892fb3b2015-01-27 15:00:57 +0100411static int
Andrew Molyneux516cab02014-12-24 20:07:05 +0000412_win32_create_temp_file(_zip_source_win32_read_file_t *ctx)
413{
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100414 zip_uint32_t value;
Andrew Molyneux516cab02014-12-24 20:07:05 +0000415 /*
416 Windows has GetTempFileName(), but it closes the file after
417 creation, leaving it open to a horrible race condition. So
418 we reinvent the wheel.
419 */
420 int i;
421 HANDLE th = INVALID_HANDLE_VALUE;
422 void *temp = NULL;
Andrew Molyneuxbf871b52015-02-20 08:14:22 +0000423 SECURITY_INFORMATION si;
424 SECURITY_ATTRIBUTES sa;
425 PSECURITY_DESCRIPTOR psd = NULL;
426 PSECURITY_ATTRIBUTES psa = NULL;
427 DWORD len;
428 BOOL success;
429
430 /*
431 Read the DACL from the original file, so we can copy it to the temp file.
432 If there is no original file, or if we can't read the DACL, we'll use the
433 default security descriptor.
434 */
435 if (ctx->h != INVALID_HANDLE_VALUE && GetFileType(ctx->h) == FILE_TYPE_DISK) {
436 si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
437 len = 0;
438 success = GetUserObjectSecurity(ctx->h, &si, NULL, len, &len);
439 if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
440 if ((psd = (PSECURITY_DESCRIPTOR)malloc(len)) == NULL) {
441 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
442 return -1;
443 }
444 success = GetUserObjectSecurity(ctx->h, &si, psd, len, &len);
445 }
446 if (success) {
447 sa.nLength = sizeof(SECURITY_ATTRIBUTES);
448 sa.bInheritHandle = FALSE;
449 sa.lpSecurityDescriptor = psd;
450 psa = &sa;
451 }
452 }
Andrew Molyneux516cab02014-12-24 20:07:05 +0000453
Thomas Klausnerb51f6132016-01-05 14:07:07 +0100454 value = GetTickCount();
Andrew Molyneux516cab02014-12-24 20:07:05 +0000455 for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) {
Andrew Molyneuxbf871b52015-02-20 08:14:22 +0000456 th = ctx->ops->op_create_temp(ctx, &temp, value + i, psa);
Andrew Molyneux516cab02014-12-24 20:07:05 +0000457 if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS)
458 break;
459 }
460
461 if (th == INVALID_HANDLE_VALUE) {
462 free(temp);
Andrew Molyneuxbf871b52015-02-20 08:14:22 +0000463 free(psd);
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100464 zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000465 return -1;
466 }
467
Andrew Molyneuxbf871b52015-02-20 08:14:22 +0000468 free(psd);
Andrew Molyneux516cab02014-12-24 20:07:05 +0000469 ctx->hout = th;
470 ctx->tmpname = temp;
471
472 return 0;
473}
474
Andrew Molyneux73d4a302014-12-24 22:00:37 +0000475
Thomas Klausner892fb3b2015-01-27 15:00:57 +0100476static int
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100477_zip_seek_win32_u(HANDLE h, zip_uint64_t offset, int whence, zip_error_t *error)
Andrew Molyneux516cab02014-12-24 20:07:05 +0000478{
479 if (offset > ZIP_INT64_MAX) {
480 zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
481 return -1;
482 }
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100483 return _zip_seek_win32(h, (zip_int64_t)offset, whence, error);
Andrew Molyneux516cab02014-12-24 20:07:05 +0000484}
485
486
Thomas Klausner892fb3b2015-01-27 15:00:57 +0100487static int
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100488_zip_seek_win32(HANDLE h, zip_int64_t offset, int whence, zip_error_t *error)
Andrew Molyneux516cab02014-12-24 20:07:05 +0000489{
490 LARGE_INTEGER li;
491 DWORD method;
492
493 switch (whence) {
494 case SEEK_SET:
495 method = FILE_BEGIN;
496 break;
497 case SEEK_END:
498 method = FILE_END;
499 break;
500 case SEEK_CUR:
501 method = FILE_CURRENT;
502 break;
503 default:
504 zip_error_set(error, ZIP_ER_SEEK, EINVAL);
505 return -1;
506 }
507
508 li.QuadPart = (LONGLONG)offset;
509 if (!SetFilePointerEx(h, li, NULL, method)) {
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100510 zip_error_set(error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000511 return -1;
512 }
513
514 return 0;
515}
516
517
Thomas Klausner892fb3b2015-01-27 15:00:57 +0100518static int
Thomas Klausner3f03f6d2015-01-27 15:24:59 +0100519_zip_win32_error_to_errno(DWORD win32err)
Andrew Molyneux73d4a302014-12-24 22:00:37 +0000520{
521 /*
522 Note: This list isn't exhaustive, but should cover common cases.
523 */
Andrew Molyneux73d4a302014-12-24 22:00:37 +0000524 switch (win32err) {
525 case ERROR_INVALID_PARAMETER:
526 return EINVAL;
527 case ERROR_FILE_NOT_FOUND:
528 return ENOENT;
529 case ERROR_INVALID_HANDLE:
530 return EBADF;
531 case ERROR_ACCESS_DENIED:
532 return EACCES;
533 case ERROR_FILE_EXISTS:
534 return EEXIST;
535 case ERROR_TOO_MANY_OPEN_FILES:
536 return EMFILE;
537 case ERROR_DISK_FULL:
538 return ENOSPC;
539 default:
540 return 0;
541 }
542}
543
544
Thomas Klausner892fb3b2015-01-27 15:00:57 +0100545static int
Andrew Molyneux516cab02014-12-24 20:07:05 +0000546_zip_stat_win32(HANDLE h, zip_stat_t *st, _zip_source_win32_read_file_t *ctx)
547{
548 FILETIME mtimeft;
549 time_t mtime;
550 LARGE_INTEGER size;
551 int regularp;
552
Thomas Klausner4f9ec2e2015-01-27 15:06:43 +0100553 if (!GetFileTime(h, NULL, NULL, &mtimeft)) {
Andrew Molyneuxc6a581a2015-02-07 14:00:05 +0000554 zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
Thomas Klausner4f9ec2e2015-01-27 15:06:43 +0100555 return -1;
556 }
557 if (_zip_filetime_to_time_t(mtimeft, &mtime) < 0) {
558 zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE);
Andrew Molyneux516cab02014-12-24 20:07:05 +0000559 return -1;
560 }
561
562 regularp = 0;
563 if (GetFileType(h) == FILE_TYPE_DISK) {
564 regularp = 1;
565 }
566
567 if (!GetFileSizeEx(h, &size)) {
Andrew Molyneuxc6a581a2015-02-07 14:00:05 +0000568 zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
Andrew Molyneux516cab02014-12-24 20:07:05 +0000569 return -1;
570 }
571
572 zip_stat_init(st);
573 st->mtime = mtime;
574 st->valid |= ZIP_STAT_MTIME;
575 if (ctx->end != 0) {
576 st->size = ctx->end - ctx->start;
577 st->valid |= ZIP_STAT_SIZE;
578 }
579 else if (regularp) {
580 st->size = (zip_uint64_t)size.QuadPart;
581 st->valid |= ZIP_STAT_SIZE;
582 }
583
584 return 0;
585}
586
587
Thomas Klausner892fb3b2015-01-27 15:00:57 +0100588static int
Andrew Molyneux516cab02014-12-24 20:07:05 +0000589_zip_filetime_to_time_t(FILETIME ft, time_t *t)
590{
591 /*
592 Inspired by http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux
593 */
594 const zip_int64_t WINDOWS_TICK = 10000000LL;
595 const zip_int64_t SEC_TO_UNIX_EPOCH = 11644473600LL;
596 ULARGE_INTEGER li;
597 zip_int64_t secs;
598 time_t temp;
599
600 li.LowPart = ft.dwLowDateTime;
601 li.HighPart = ft.dwHighDateTime;
602 secs = (li.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
603
604 temp = (time_t)secs;
605 if (secs != (zip_int64_t)temp)
606 return -1;
607
608 *t = temp;
609 return 0;
610}