"Fossies" - the Fresh Open Source Software Archive

Member "src/Common/libzip/zip_source_win32handle.c" (10 Oct 2018, 15393 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "zip_source_win32handle.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.21_Source_vs_1.22_Source.

    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 <aclapi.h>
   36 #include <stdlib.h>
   37 #include <string.h>
   38 #include <wchar.h>
   39 
   40 #include "zipint.h"
   41 #include "zipwin32.h"
   42 
   43 static zip_int64_t _win32_read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
   44 static int _win32_create_temp_file(_zip_source_win32_read_file_t *ctx);
   45 static int _zip_filetime_to_time_t(FILETIME ft, time_t *t);
   46 static int _zip_seek_win32_u(void *h, zip_uint64_t offset, int whence, zip_error_t *error);
   47 static int _zip_seek_win32(void *h, zip_int64_t offset, int whence, zip_error_t *error);
   48 static int _zip_win32_error_to_errno(unsigned long win32err);
   49 static int _zip_stat_win32(void *h, zip_stat_t *st, _zip_source_win32_read_file_t *ctx);
   50 
   51 ZIP_EXTERN zip_source_t *
   52 zip_source_win32handle(zip_t *za, HANDLE h, zip_uint64_t start, zip_int64_t len) {
   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     if (h == INVALID_HANDLE_VALUE || length < -1) {
   63     zip_error_set(error, ZIP_ER_INVAL, 0);
   64     return NULL;
   65     }
   66 
   67     return _zip_source_win32_handle_or_name(NULL, h, start, length, 1, NULL, NULL, error);
   68 }
   69 
   70 
   71 zip_source_t *
   72 _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) {
   73     _zip_source_win32_read_file_t *ctx;
   74     zip_source_t *zs;
   75 
   76     if (h == INVALID_HANDLE_VALUE && fname == NULL) {
   77     zip_error_set(error, ZIP_ER_INVAL, 0);
   78     return NULL;
   79     }
   80 
   81     if ((ctx = (_zip_source_win32_read_file_t *)malloc(sizeof(_zip_source_win32_read_file_t))) == NULL) {
   82     zip_error_set(error, ZIP_ER_MEMORY, 0);
   83     return NULL;
   84     }
   85 
   86     ctx->fname = NULL;
   87     if (fname) {
   88     if ((ctx->fname = ops->op_strdup(fname)) == NULL) {
   89         zip_error_set(error, ZIP_ER_MEMORY, 0);
   90         free(ctx);
   91         return NULL;
   92     }
   93     }
   94 
   95     ctx->ops = ops;
   96     ctx->h = h;
   97     ctx->start = start;
   98     ctx->end = (len < 0 ? 0 : start + (zip_uint64_t)len);
   99     ctx->closep = ctx->fname ? 1 : closep;
  100     if (st) {
  101     memcpy(&ctx->st, st, sizeof(ctx->st));
  102     ctx->st.name = NULL;
  103     ctx->st.valid &= ~ZIP_STAT_NAME;
  104     }
  105     else {
  106     zip_stat_init(&ctx->st);
  107     }
  108 
  109     ctx->tmpname = NULL;
  110     ctx->hout = INVALID_HANDLE_VALUE;
  111 
  112     zip_error_init(&ctx->error);
  113 
  114     ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
  115     if (ctx->fname) {
  116     HANDLE th;
  117 
  118     th = ops->op_open(ctx);
  119     if (th == INVALID_HANDLE_VALUE || GetFileType(th) == FILE_TYPE_DISK) {
  120         ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
  121     }
  122     if (th != INVALID_HANDLE_VALUE) {
  123         CloseHandle(th);
  124     }
  125     }
  126     else if (GetFileType(ctx->h) == FILE_TYPE_DISK) {
  127     ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
  128     }
  129 
  130     if ((zs = zip_source_function_create(_win32_read_file, ctx, error)) == NULL) {
  131     free(ctx->fname);
  132     free(ctx);
  133     return NULL;
  134     }
  135 
  136     return zs;
  137 }
  138 
  139 
  140 static zip_int64_t
  141 _win32_read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
  142     _zip_source_win32_read_file_t *ctx;
  143     char *buf;
  144     zip_uint64_t n;
  145     DWORD i;
  146 
  147     ctx = (_zip_source_win32_read_file_t *)state;
  148     buf = (char *)data;
  149 
  150     switch (cmd) {
  151     case ZIP_SOURCE_BEGIN_WRITE:
  152     if (ctx->fname == NULL) {
  153         zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
  154         return -1;
  155     }
  156     return _win32_create_temp_file(ctx);
  157 
  158     case ZIP_SOURCE_COMMIT_WRITE: {
  159     if (!CloseHandle(ctx->hout)) {
  160         ctx->hout = INVALID_HANDLE_VALUE;
  161         zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
  162     }
  163     ctx->hout = INVALID_HANDLE_VALUE;
  164     if (ctx->ops->op_rename_temp(ctx) < 0) {
  165         zip_error_set(&ctx->error, ZIP_ER_RENAME, _zip_win32_error_to_errno(GetLastError()));
  166         return -1;
  167     }
  168     free(ctx->tmpname);
  169     ctx->tmpname = NULL;
  170     return 0;
  171     }
  172 
  173     case ZIP_SOURCE_CLOSE:
  174     if (ctx->fname) {
  175         CloseHandle(ctx->h);
  176         ctx->h = INVALID_HANDLE_VALUE;
  177     }
  178     return 0;
  179 
  180     case ZIP_SOURCE_ERROR:
  181     return zip_error_to_data(&ctx->error, data, len);
  182 
  183     case ZIP_SOURCE_FREE:
  184     free(ctx->fname);
  185     free(ctx->tmpname);
  186     if (ctx->closep && ctx->h != INVALID_HANDLE_VALUE)
  187         CloseHandle(ctx->h);
  188     free(ctx);
  189     return 0;
  190 
  191     case ZIP_SOURCE_OPEN:
  192     if (ctx->fname) {
  193         if ((ctx->h = ctx->ops->op_open(ctx)) == INVALID_HANDLE_VALUE) {
  194         zip_error_set(&ctx->error, ZIP_ER_OPEN, _zip_win32_error_to_errno(GetLastError()));
  195         return -1;
  196         }
  197     }
  198 
  199     if (ctx->closep && ctx->start > 0) {
  200         if (_zip_seek_win32_u(ctx->h, ctx->start, SEEK_SET, &ctx->error) < 0) {
  201         return -1;
  202         }
  203     }
  204     ctx->current = ctx->start;
  205     return 0;
  206 
  207     case ZIP_SOURCE_READ:
  208     if (ctx->end > 0) {
  209         n = ctx->end - ctx->current;
  210         if (n > len) {
  211         n = len;
  212         }
  213     }
  214     else {
  215         n = len;
  216     }
  217 
  218     if (n > SIZE_MAX)
  219         n = SIZE_MAX;
  220 
  221     if (!ctx->closep) {
  222         if (_zip_seek_win32_u(ctx->h, ctx->current, SEEK_SET, &ctx->error) < 0) {
  223         return -1;
  224         }
  225     }
  226 
  227     if (!ReadFile(ctx->h, buf, (DWORD)n, &i, NULL)) {
  228         zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
  229         return -1;
  230     }
  231     ctx->current += i;
  232 
  233     return (zip_int64_t)i;
  234 
  235     case ZIP_SOURCE_REMOVE:
  236     if (ctx->ops->op_remove(ctx->fname) < 0) {
  237         zip_error_set(&ctx->error, ZIP_ER_REMOVE, _zip_win32_error_to_errno(GetLastError()));
  238         return -1;
  239     }
  240     return 0;
  241 
  242     case ZIP_SOURCE_ROLLBACK_WRITE:
  243     if (ctx->hout) {
  244         CloseHandle(ctx->hout);
  245         ctx->hout = INVALID_HANDLE_VALUE;
  246     }
  247     ctx->ops->op_remove(ctx->tmpname);
  248     free(ctx->tmpname);
  249     ctx->tmpname = NULL;
  250     return 0;
  251 
  252     case ZIP_SOURCE_SEEK: {
  253     zip_int64_t new_current;
  254     int need_seek;
  255     zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
  256 
  257     if (args == NULL)
  258         return -1;
  259 
  260     need_seek = ctx->closep;
  261 
  262     switch (args->whence) {
  263     case SEEK_SET:
  264         new_current = args->offset;
  265         break;
  266 
  267     case SEEK_END:
  268         if (ctx->end == 0) {
  269         LARGE_INTEGER zero;
  270         LARGE_INTEGER new_offset;
  271 
  272         if (_zip_seek_win32(ctx->h, args->offset, SEEK_END, &ctx->error) < 0) {
  273             return -1;
  274         }
  275         zero.QuadPart = 0;
  276         if (!SetFilePointerEx(ctx->h, zero, &new_offset, FILE_CURRENT)) {
  277             zip_error_set(&ctx->error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));
  278             return -1;
  279         }
  280         new_current = new_offset.QuadPart;
  281         need_seek = 0;
  282         }
  283         else {
  284         new_current = (zip_int64_t)ctx->end + args->offset;
  285         }
  286         break;
  287     case SEEK_CUR:
  288         new_current = (zip_int64_t)ctx->current + args->offset;
  289         break;
  290 
  291     default:
  292         zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
  293         return -1;
  294     }
  295 
  296     if (new_current < 0 || (zip_uint64_t)new_current < ctx->start || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end)) {
  297         zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
  298         return -1;
  299     }
  300 
  301     ctx->current = (zip_uint64_t)new_current;
  302 
  303     if (need_seek) {
  304         if (_zip_seek_win32_u(ctx->h, ctx->current, SEEK_SET, &ctx->error) < 0) {
  305         return -1;
  306         }
  307     }
  308     return 0;
  309     }
  310 
  311     case ZIP_SOURCE_SEEK_WRITE: {
  312     zip_source_args_seek_t *args;
  313 
  314     args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
  315     if (args == NULL) {
  316         return -1;
  317     }
  318 
  319     if (_zip_seek_win32(ctx->hout, args->offset, args->whence, &ctx->error) < 0) {
  320         return -1;
  321     }
  322     return 0;
  323     }
  324 
  325     case ZIP_SOURCE_STAT: {
  326     if (len < sizeof(ctx->st))
  327         return -1;
  328 
  329     if (ctx->st.valid != 0)
  330         memcpy(data, &ctx->st, sizeof(ctx->st));
  331     else {
  332         DWORD win32err;
  333         zip_stat_t *st;
  334         HANDLE h;
  335         int success;
  336 
  337         st = (zip_stat_t *)data;
  338 
  339         if (ctx->h != INVALID_HANDLE_VALUE) {
  340         h = ctx->h;
  341         }
  342         else {
  343         h = ctx->ops->op_open(ctx);
  344         if (h == INVALID_HANDLE_VALUE) {
  345             win32err = GetLastError();
  346             if (win32err == ERROR_FILE_NOT_FOUND || win32err == ERROR_PATH_NOT_FOUND) {
  347             zip_error_set(&ctx->error, ZIP_ER_READ, ENOENT);
  348             return -1;
  349             }
  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     LARGE_INTEGER zero;
  378     LARGE_INTEGER offset;
  379 
  380     zero.QuadPart = 0;
  381     if (!SetFilePointerEx(ctx->hout, zero, &offset, FILE_CURRENT)) {
  382         zip_error_set(&ctx->error, ZIP_ER_TELL, _zip_win32_error_to_errno(GetLastError()));
  383         return -1;
  384     }
  385 
  386     return offset.QuadPart;
  387     }
  388 
  389     case ZIP_SOURCE_WRITE: {
  390     DWORD ret;
  391     if (!WriteFile(ctx->hout, data, (DWORD)len, &ret, NULL) || ret != len) {
  392         zip_error_set(&ctx->error, ZIP_ER_WRITE, _zip_win32_error_to_errno(GetLastError()));
  393         return -1;
  394     }
  395 
  396     return (zip_int64_t)ret;
  397     }
  398 
  399     default:
  400     zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
  401     return -1;
  402     }
  403 }
  404 
  405 
  406 static int
  407 _win32_create_temp_file(_zip_source_win32_read_file_t *ctx) {
  408     zip_uint32_t value;
  409     /*
  410     Windows has GetTempFileName(), but it closes the file after
  411     creation, leaving it open to a horrible race condition. So
  412     we reinvent the wheel.
  413     */
  414     int i;
  415     HANDLE th = INVALID_HANDLE_VALUE;
  416     void *temp = NULL;
  417     PSECURITY_DESCRIPTOR psd = NULL;
  418     PSECURITY_ATTRIBUTES psa = NULL;
  419     SECURITY_ATTRIBUTES sa;
  420     SECURITY_INFORMATION si;
  421     DWORD success;
  422     PACL dacl = NULL;
  423 
  424     /*
  425     Read the DACL from the original file, so we can copy it to the temp file.
  426     If there is no original file, or if we can't read the DACL, we'll use the
  427     default security descriptor.
  428     */
  429     if (ctx->h != INVALID_HANDLE_VALUE && GetFileType(ctx->h) == FILE_TYPE_DISK) {
  430     si = DACL_SECURITY_INFORMATION | UNPROTECTED_DACL_SECURITY_INFORMATION;
  431     success = GetSecurityInfo(ctx->h, SE_FILE_OBJECT, si, NULL, NULL, &dacl, NULL, &psd);
  432     if (success == ERROR_SUCCESS) {
  433         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  434         sa.bInheritHandle = FALSE;
  435         sa.lpSecurityDescriptor = psd;
  436         psa = &sa;
  437     }
  438     }
  439 
  440 
  441 #ifndef MS_UWP
  442     value = GetTickCount();
  443 #else
  444     value = (zip_uint32_t)GetTickCount64();
  445 #endif
  446 
  447     for (i = 0; i < 1024 && th == INVALID_HANDLE_VALUE; i++) {
  448     th = ctx->ops->op_create_temp(ctx, &temp, value + i, psa);
  449     if (th == INVALID_HANDLE_VALUE && GetLastError() != ERROR_FILE_EXISTS)
  450         break;
  451     }
  452 
  453     if (th == INVALID_HANDLE_VALUE) {
  454     free(temp);
  455     LocalFree(psd);
  456     zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, _zip_win32_error_to_errno(GetLastError()));
  457     return -1;
  458     }
  459 
  460     LocalFree(psd);
  461     ctx->hout = th;
  462     ctx->tmpname = temp;
  463 
  464     return 0;
  465 }
  466 
  467 
  468 static int
  469 _zip_seek_win32_u(HANDLE h, zip_uint64_t offset, int whence, zip_error_t *error) {
  470     if (offset > ZIP_INT64_MAX) {
  471     zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
  472     return -1;
  473     }
  474     return _zip_seek_win32(h, (zip_int64_t)offset, whence, error);
  475 }
  476 
  477 
  478 static int
  479 _zip_seek_win32(HANDLE h, zip_int64_t offset, int whence, zip_error_t *error) {
  480     LARGE_INTEGER li;
  481     DWORD method;
  482 
  483     switch (whence) {
  484     case SEEK_SET:
  485     method = FILE_BEGIN;
  486     break;
  487     case SEEK_END:
  488     method = FILE_END;
  489     break;
  490     case SEEK_CUR:
  491     method = FILE_CURRENT;
  492     break;
  493     default:
  494     zip_error_set(error, ZIP_ER_SEEK, EINVAL);
  495     return -1;
  496     }
  497 
  498     li.QuadPart = (LONGLONG)offset;
  499     if (!SetFilePointerEx(h, li, NULL, method)) {
  500     zip_error_set(error, ZIP_ER_SEEK, _zip_win32_error_to_errno(GetLastError()));
  501     return -1;
  502     }
  503 
  504     return 0;
  505 }
  506 
  507 
  508 static int
  509 _zip_win32_error_to_errno(DWORD win32err) {
  510     /*
  511     Note: This list isn't exhaustive, but should cover common cases.
  512     */
  513     switch (win32err) {
  514     case ERROR_INVALID_PARAMETER:
  515     return EINVAL;
  516     case ERROR_FILE_NOT_FOUND:
  517     return ENOENT;
  518     case ERROR_INVALID_HANDLE:
  519     return EBADF;
  520     case ERROR_ACCESS_DENIED:
  521     return EACCES;
  522     case ERROR_FILE_EXISTS:
  523     return EEXIST;
  524     case ERROR_TOO_MANY_OPEN_FILES:
  525     return EMFILE;
  526     case ERROR_DISK_FULL:
  527     return ENOSPC;
  528     default:
  529     return 0;
  530     }
  531 }
  532 
  533 
  534 static int
  535 _zip_stat_win32(HANDLE h, zip_stat_t *st, _zip_source_win32_read_file_t *ctx) {
  536     FILETIME mtimeft;
  537     time_t mtime;
  538     LARGE_INTEGER size;
  539     int regularp;
  540 
  541     if (!GetFileTime(h, NULL, NULL, &mtimeft)) {
  542     zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
  543     return -1;
  544     }
  545     if (_zip_filetime_to_time_t(mtimeft, &mtime) < 0) {
  546     zip_error_set(&ctx->error, ZIP_ER_READ, ERANGE);
  547     return -1;
  548     }
  549 
  550     regularp = 0;
  551     if (GetFileType(h) == FILE_TYPE_DISK) {
  552     regularp = 1;
  553     }
  554 
  555     if (!GetFileSizeEx(h, &size)) {
  556     zip_error_set(&ctx->error, ZIP_ER_READ, _zip_win32_error_to_errno(GetLastError()));
  557     return -1;
  558     }
  559 
  560     zip_stat_init(st);
  561     st->mtime = mtime;
  562     st->valid |= ZIP_STAT_MTIME;
  563     if (ctx->end != 0) {
  564     st->size = ctx->end - ctx->start;
  565     st->valid |= ZIP_STAT_SIZE;
  566     }
  567     else if (regularp) {
  568     st->size = (zip_uint64_t)size.QuadPart;
  569     st->valid |= ZIP_STAT_SIZE;
  570     }
  571 
  572     return 0;
  573 }
  574 
  575 
  576 static int
  577 _zip_filetime_to_time_t(FILETIME ft, time_t *t) {
  578     /*
  579     Inspired by http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux
  580     */
  581     const zip_int64_t WINDOWS_TICK = 10000000LL;
  582     const zip_int64_t SEC_TO_UNIX_EPOCH = 11644473600LL;
  583     ULARGE_INTEGER li;
  584     zip_int64_t secs;
  585     time_t temp;
  586 
  587     li.LowPart = ft.dwLowDateTime;
  588     li.HighPart = ft.dwHighDateTime;
  589     secs = (li.QuadPart / WINDOWS_TICK - SEC_TO_UNIX_EPOCH);
  590 
  591     temp = (time_t)secs;
  592     if (secs != (zip_int64_t)temp)
  593     return -1;
  594 
  595     *t = temp;
  596     return 0;
  597 }