Mercurial > embed
comparison libzip/lib/zip_source_win32handle.c @ 20:3b18afe43c9d
libzip: reimport version 1.1.3
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 29 Jun 2016 09:24:55 +0200 |
parents | 2306f4b04790 |
children | 056ee6b5913e |
comparison
equal
deleted
inserted
replaced
19:07f2cdc6e430 | 20:3b18afe43c9d |
---|---|
1 /* | |
2 zip_source_win32file.c -- create data source from HANDLE (Win32) | |
3 Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner | |
4 | |
5 This file is part of libzip, a library to manipulate ZIP archives. | |
6 The authors can be contacted at <libzip@nih.at> | |
7 | |
8 Redistribution and use in source and binary forms, with or without | |
9 modification, are permitted provided that the following conditions | |
10 are met: | |
11 1. Redistributions of source code must retain the above copyright | |
12 notice, this list of conditions and the following disclaimer. | |
13 2. Redistributions in binary form must reproduce the above copyright | |
14 notice, this list of conditions and the following disclaimer in | |
15 the documentation and/or other materials provided with the | |
16 distribution. | |
17 3. The names of the authors may not be used to endorse or promote | |
18 products derived from this software without specific prior | |
19 written permission. | |
20 | |
21 THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS | |
22 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
24 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY | |
25 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
26 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | |
27 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER | |
29 IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
30 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | |
31 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
32 */ | |
33 | |
34 | |
35 #include <wchar.h> | |
36 #include <stdlib.h> | |
37 #include <string.h> | |
38 | |
39 #include "zipint.h" | |
40 #include "zipwin32.h" | |
41 | |
42 static zip_int64_t _win32_read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd); | |
43 static int _win32_create_temp_file(_zip_source_win32_read_file_t *ctx); | |
44 static int _zip_filetime_to_time_t(FILETIME ft, time_t *t); | |
45 static int _zip_seek_win32_u(void *h, zip_uint64_t offset, int whence, zip_error_t *error); | |
46 static int _zip_seek_win32(void *h, zip_int64_t offset, int whence, zip_error_t *error); | |
47 static int _zip_win32_error_to_errno(unsigned long win32err); | |
48 static int _zip_stat_win32(void *h, zip_stat_t *st, _zip_source_win32_read_file_t *ctx); | |
49 | |
50 ZIP_EXTERN zip_source_t * | |
51 zip_source_win32handle(zip_t *za, HANDLE h, zip_uint64_t start, zip_int64_t len) | |
52 { | |
53 if (za == NULL) | |
54 return NULL; | |
55 | |
56 return zip_source_win32handle_create(h, start, len, &za->error); | |
57 } | |
58 | |
59 | |
60 ZIP_EXTERN zip_source_t * | |
61 zip_source_win32handle_create(HANDLE h, zip_uint64_t start, zip_int64_t length, zip_error_t *error) | |
62 { | |
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 | |
71 | |
72 zip_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); | |
121 if (th == INVALID_HANDLE_VALUE || GetFileType(th) == FILE_TYPE_DISK) { | |
122 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) { | |
133 free(ctx->fname); | |
134 free(ctx); | |
135 return NULL; | |
136 } | |
137 | |
138 return zs; | |
139 } | |
140 | |
141 | |
142 static zip_int64_t | |
143 _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; | |
164 zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError())); | |
165 } | |
166 ctx->hout = INVALID_HANDLE_VALUE; | |
167 if (ctx->ops->op_rename_temp(ctx) < 0) { | |
168 zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError())); | |
169 return -1; | |
170 } | |
171 free(ctx->tmpname); | |
172 ctx->tmpname = NULL; | |
173 return 0; | |
174 } | |
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) { | |
197 zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError())); | |
198 return -1; | |
199 } | |
200 } | |
201 | |
202 if (ctx->closep && ctx->start > 0) { | |
203 if (_zip_seek_win32_u(ctx->h, ctx->start, SEEK_SET, &ctx->error) < 0) { | |
204 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) { | |
225 if (_zip_seek_win32_u(ctx->h, ctx->current, SEEK_SET, &ctx->error) < 0) { | |
226 return -1; | |
227 } | |
228 } | |
229 | |
230 if (!ReadFile(ctx->h, buf, (DWORD)n, &i, NULL)) { | |
231 zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError())); | |
232 return -1; | |
233 } | |
234 ctx->current += i; | |
235 | |
236 return (zip_int64_t)i; | |
237 | |
238 case ZIP_SOURCE_REMOVE: | |
239 if (ctx->ops->op_remove(ctx->fname) < 0) { | |
240 zip_error_set(&ctx->error, ZIP_ER_REMOVE, _zip_win32_error_to_errno(GetLastError())); | |
241 return -1; | |
242 } | |
243 return 0; | |
244 | |
245 case ZIP_SOURCE_ROLLBACK_WRITE: | |
246 if (ctx->hout) { | |
247 CloseHandle(ctx->hout); | |
248 ctx->hout = INVALID_HANDLE_VALUE; | |
249 } | |
250 ctx->ops->op_remove(ctx->tmpname); | |
251 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 | |
275 if (_zip_seek_win32(ctx->h, args->offset, SEEK_END, &ctx->error) < 0) { | |
276 return -1; | |
277 } | |
278 zero.QuadPart = 0; | |
279 if (!SetFilePointerEx(ctx->h, zero, &new_offset, FILE_CURRENT)) { | |
280 zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError())); | |
281 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) { | |
307 if (_zip_seek_win32_u(ctx->h, ctx->current, SEEK_SET, &ctx->error) < 0) { | |
308 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 | |
322 if (_zip_seek_win32(ctx->hout, args->offset, args->whence, &ctx->error) < 0) { | |
323 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); | |
347 if (h == INVALID_HANDLE_VALUE && GetLastError() == ERROR_FILE_NOT_FOUND) { | |
348 zip_error_set(&ctx->error, ZIP_ER_READ, ENOENT); | |
349 return -1; | |
350 } | |
351 } | |
352 | |
353 success = _zip_stat_win32(h, st, ctx); | |
354 win32err = GetLastError(); | |
355 | |
356 /* We're done with the handle, so close it if we just opened it. */ | |
357 if (h != ctx->h) { | |
358 CloseHandle(h); | |
359 } | |
360 | |
361 if (success < 0) { | |
362 /* TODO: Is this the correct error to return in all cases? */ | |
363 zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(win32err)); | |
364 return -1; | |
365 } | |
366 } | |
367 return sizeof(ctx->st); | |
368 } | |
369 | |
370 case ZIP_SOURCE_SUPPORTS: | |
371 return ctx->supports; | |
372 | |
373 case ZIP_SOURCE_TELL: | |
374 return (zip_int64_t)ctx->current; | |
375 | |
376 case ZIP_SOURCE_TELL_WRITE: | |
377 { | |
378 LARGE_INTEGER zero; | |
379 LARGE_INTEGER offset; | |
380 | |
381 zero.QuadPart = 0; | |
382 if (!SetFilePointerEx(ctx->hout, zero, &offset, FILE_CURRENT)) { | |
383 zip_error_set(&ctx->error, ZIP_ER_TELL, _zip_win32_error_to_errno(GetLastError())); | |
384 return -1; | |
385 } | |
386 | |
387 return offset.QuadPart; | |
388 } | |
389 | |
390 case ZIP_SOURCE_WRITE: | |
391 { | |
392 DWORD ret; | |
393 if (!WriteFile(ctx->hout, data, (DWORD)len, &ret, NULL) || ret != len) { | |
394 zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError())); | |
395 return -1; | |
396 } | |
397 | |
398 return (zip_int64_t)ret; | |
399 } | |
400 | |
401 default: | |
402 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); | |
403 return -1; | |
404 } | |
405 } | |
406 | |
407 | |
408 static int | |
409 _win32_create_temp_file(_zip_source_win32_read_file_t *ctx) | |
410 { | |
411 zip_uint32_t value; | |
412 /* | |
413 Windows has GetTempFileName(), but it closes the file after | |
414 creation, leaving it open to a horrible race condition. So | |
415 we reinvent the wheel. | |
416 */ | |
417 int i; | |
418 HANDLE th = INVALID_HANDLE_VALUE; | |
419 void *temp = NULL; | |
420 SECURITY_INFORMATION si; | |
421 SECURITY_ATTRIBUTES sa; | |
422 PSECURITY_DESCRIPTOR psd = NULL; | |
423 PSECURITY_ATTRIBUTES psa = NULL; | |
424 DWORD len; | |
425 BOOL success; | |
426 | |
427 /* | |
428 Read the DACL from the original file, so we can copy it to the temp file. | |
429 If there is no original file, or if we can't read the DACL, we'll use the | |
430 default security descriptor. | |
431 */ | |
432 if (ctx->h != INVALID_HANDLE_VALUE && GetFileType(ctx->h) == FILE_TYPE_DISK) { | |
433 si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION; | |
434 len = 0; | |
435 success = GetUserObjectSecurity(ctx->h, &si, NULL, len, &len); | |
436 if (!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER) { | |
437 if ((psd = (PSECURITY_DESCRIPTOR)malloc(len)) == NULL) { | |
438 zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); | |
439 return -1; | |
440 } | |
441 success = GetUserObjectSecurity(ctx->h, &si, psd, len, &len); | |
442 } | |
443 if (success) { | |
444 sa.nLength = sizeof(SECURITY_ATTRIBUTES); | |
445 sa.bInheritHandle = FALSE; | |
446 sa.lpSecurityDescriptor = psd; | |
447 psa = &sa; | |
448 } | |
449 } | |
450 | |
451 value = GetTickCount(); | |
452 for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) { | |
453 th = ctx->ops->op_create_temp(ctx, &temp, value + i, psa); | |
454 if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS) | |
455 break; | |
456 } | |
457 | |
458 if (th == INVALID_HANDLE_VALUE) { | |
459 free(temp); | |
460 free(psd); | |
461 zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError())); | |
462 return -1; | |
463 } | |
464 | |
465 free(psd); | |
466 ctx->hout = th; | |
467 ctx->tmpname = temp; | |
468 | |
469 return 0; | |
470 } | |
471 | |
472 | |
473 static int | |
474 _zip_seek_win32_u(HANDLE h, zip_uint64_t offset, int whence, zip_error_t *error) | |
475 { | |
476 if (offset > ZIP_INT64_MAX) { | |
477 zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW); | |
478 return -1; | |
479 } | |
480 return _zip_seek_win32(h, (zip_int64_t)offset, whence, error); | |
481 } | |
482 | |
483 | |
484 static int | |
485 _zip_seek_win32(HANDLE h, zip_int64_t offset, int whence, zip_error_t *error) | |
486 { | |
487 LARGE_INTEGER li; | |
488 DWORD method; | |
489 | |
490 switch (whence) { | |
491 case SEEK_SET: | |
492 method = FILE_BEGIN; | |
493 break; | |
494 case SEEK_END: | |
495 method = FILE_END; | |
496 break; | |
497 case SEEK_CUR: | |
498 method = FILE_CURRENT; | |
499 break; | |
500 default: | |
501 zip_error_set(error, ZIP_ER_SEEK, EINVAL); | |
502 return -1; | |
503 } | |
504 | |
505 li.QuadPart = (LONGLONG)offset; | |
506 if (!SetFilePointerEx(h, li, NULL, method)) { | |
507 zip_error_set(error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError())); | |
508 return -1; | |
509 } | |
510 | |
511 return 0; | |
512 } | |
513 | |
514 | |
515 static int | |
516 _zip_win32_error_to_errno(DWORD win32err) | |
517 { | |
518 /* | |
519 Note: This list isn't exhaustive, but should cover common cases. | |
520 */ | |
521 switch (win32err) { | |
522 case ERROR_INVALID_PARAMETER: | |
523 return EINVAL; | |
524 case ERROR_FILE_NOT_FOUND: | |
525 return ENOENT; | |
526 case ERROR_INVALID_HANDLE: | |
527 return EBADF; | |
528 case ERROR_ACCESS_DENIED: | |
529 return EACCES; | |
530 case ERROR_FILE_EXISTS: | |
531 return EEXIST; | |
532 case ERROR_TOO_MANY_OPEN_FILES: | |
533 return EMFILE; | |
534 case ERROR_DISK_FULL: | |
535 return ENOSPC; | |
536 default: | |
537 return 0; | |
538 } | |
539 } | |
540 | |
541 | |
542 static int | |
543 _zip_stat_win32(HANDLE h, zip_stat_t *st, _zip_source_win32_read_file_t *ctx) | |
544 { | |
545 FILETIME mtimeft; | |
546 time_t mtime; | |
547 LARGE_INTEGER size; | |
548 int regularp; | |
549 | |
550 if (!GetFileTime(h, NULL, NULL, &mtimeft)) { | |
551 zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError())); | |
552 return -1; | |
553 } | |
554 if (_zip_filetime_to_time_t(mtimeft, &mtime) < 0) { | |
555 zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE); | |
556 return -1; | |
557 } | |
558 | |
559 regularp = 0; | |
560 if (GetFileType(h) == FILE_TYPE_DISK) { | |
561 regularp = 1; | |
562 } | |
563 | |
564 if (!GetFileSizeEx(h, &size)) { | |
565 zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError())); | |
566 return -1; | |
567 } | |
568 | |
569 zip_stat_init(st); | |
570 st->mtime = mtime; | |
571 st->valid |= ZIP_STAT_MTIME; | |
572 if (ctx->end != 0) { | |
573 st->size = ctx->end - ctx->start; | |
574 st->valid |= ZIP_STAT_SIZE; | |
575 } | |
576 else if (regularp) { | |
577 st->size = (zip_uint64_t)size.QuadPart; | |
578 st->valid |= ZIP_STAT_SIZE; | |
579 } | |
580 | |
581 return 0; | |
582 } | |
583 | |
584 | |
585 static int | |
586 _zip_filetime_to_time_t(FILETIME ft, time_t *t) | |
587 { | |
588 /* | |
589 Inspired by http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux | |
590 */ | |
591 const zip_int64_t WINDOWS_TICK = 10000000LL; | |
592 const zip_int64_t SEC_TO_UNIX_EPOCH = 11644473600LL; | |
593 ULARGE_INTEGER li; | |
594 zip_int64_t secs; | |
595 time_t temp; | |
596 | |
597 li.LowPart = ft.dwLowDateTime; | |
598 li.HighPart = ft.dwHighDateTime; | |
599 secs = (li.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH); | |
600 | |
601 temp = (time_t)secs; | |
602 if (secs != (zip_int64_t)temp) | |
603 return -1; | |
604 | |
605 *t = temp; | |
606 return 0; | |
607 } |