"Fossies" - the Fresh Open Source Software Archive

Member "src/Common/libzip/zip_source_filep.c" (10 Oct 2018, 15560 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_filep.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_filep.c -- create data source from FILE *
    3   Copyright (C) 1999-2017 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 #include <stdio.h>
   35 #include <stdlib.h>
   36 #include <string.h>
   37 #include <sys/stat.h>
   38 
   39 #include "zipint.h"
   40 
   41 #ifdef HAVE_UNISTD_H
   42 #include <unistd.h>
   43 #endif
   44 
   45 #ifdef HAVE_CLONEFILE
   46 #include <sys/attr.h>
   47 #include <sys/clonefile.h>
   48 #define CAN_CLONE
   49 #endif
   50 #ifdef HAVE_FICLONERANGE
   51 #include <linux/fs.h>
   52 #include <sys/ioctl.h>
   53 #define CAN_CLONE
   54 #endif
   55 
   56 #ifdef _WIN32
   57 /* WIN32 needs <fcntl.h> for _O_BINARY */
   58 #include <fcntl.h>
   59 #endif
   60 
   61 /* Windows sys/types.h does not provide these */
   62 #ifndef S_ISREG
   63 #define S_ISREG(m) (((m)&S_IFMT) == S_IFREG)
   64 #endif
   65 #if defined(S_IXUSR) && defined(S_IRWXG) && defined(S_IRWXO)
   66 #define _SAFE_MASK (S_IXUSR | S_IRWXG | S_IRWXO)
   67 #elif defined(_S_IWRITE)
   68 #define _SAFE_MASK (_S_IWRITE)
   69 #else
   70 #error do not know safe values for umask, please report this
   71 #endif
   72 
   73 #ifdef _MSC_VER
   74 /* MSVC doesn't have mode_t */
   75 typedef int mode_t;
   76 #endif
   77 
   78 struct read_file {
   79     zip_error_t error; /* last error information */
   80     zip_int64_t supports;
   81 
   82     /* reading */
   83     char *fname;            /* name of file to read from */
   84     FILE *f;                /* file to read from */
   85     struct zip_stat st;     /* stat information passed in */
   86     zip_error_t stat_error; /* error returned for stat */
   87     zip_uint64_t start;     /* start offset of data to read */
   88     zip_uint64_t end;       /* end offset of data to read relative to start, 0 for up to EOF */
   89     zip_uint64_t current;   /* current offset relative to start (0 is beginning of part we read) */
   90 
   91     /* writing */
   92     char *tmpname;
   93     FILE *fout;
   94 };
   95 
   96 static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
   97 static int create_temp_output(struct read_file *ctx);
   98 #ifdef CAN_CLONE
   99 static zip_int64_t create_temp_output_cloning(struct read_file *ctx, zip_uint64_t offset);
  100 #endif
  101 static int _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error);
  102 static int _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error);
  103 
  104 
  105 ZIP_EXTERN zip_source_t *
  106 zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len) {
  107     if (za == NULL)
  108     return NULL;
  109 
  110     return zip_source_filep_create(file, start, len, &za->error);
  111 }
  112 
  113 
  114 ZIP_EXTERN zip_source_t *
  115 zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error) {
  116     if (file == NULL || length < -1) {
  117     zip_error_set(error, ZIP_ER_INVAL, 0);
  118     return NULL;
  119     }
  120 
  121     return _zip_source_file_or_p(NULL, file, start, length, NULL, error);
  122 }
  123 
  124 
  125 zip_source_t *
  126 _zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int64_t len, const zip_stat_t *st, zip_error_t *error) {
  127     struct read_file *ctx;
  128     zip_source_t *zs;
  129     struct stat sb;
  130     bool stat_valid;
  131 
  132     if (file == NULL && fname == NULL) {
  133     zip_error_set(error, ZIP_ER_INVAL, 0);
  134     return NULL;
  135     }
  136 
  137     if (len < 0) {
  138     len = 0;
  139     }
  140 
  141     if (start > ZIP_INT64_MAX || start + (zip_uint64_t)len < start) {
  142     zip_error_set(error, ZIP_ER_INVAL, 0);
  143     return NULL;
  144     }
  145 
  146     if ((ctx = (struct read_file *)malloc(sizeof(struct read_file))) == NULL) {
  147     zip_error_set(error, ZIP_ER_MEMORY, 0);
  148     return NULL;
  149     }
  150 
  151     ctx->fname = NULL;
  152     if (fname) {
  153     if ((ctx->fname = strdup(fname)) == NULL) {
  154         zip_error_set(error, ZIP_ER_MEMORY, 0);
  155         free(ctx);
  156         return NULL;
  157     }
  158     }
  159     ctx->f = file;
  160     ctx->start = start;
  161     ctx->end = (zip_uint64_t)len;
  162     if (st) {
  163     memcpy(&ctx->st, st, sizeof(ctx->st));
  164     ctx->st.name = NULL;
  165     ctx->st.valid &= ~ZIP_STAT_NAME;
  166     }
  167     else {
  168     zip_stat_init(&ctx->st);
  169     }
  170 
  171     if (ctx->end > 0) {
  172     ctx->st.size = ctx->end;
  173     ctx->st.valid |= ZIP_STAT_SIZE;
  174     }
  175 
  176     zip_error_init(&ctx->stat_error);
  177 
  178     ctx->tmpname = NULL;
  179     ctx->fout = NULL;
  180 
  181     zip_error_init(&ctx->error);
  182 
  183     ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
  184 
  185     if (ctx->fname) {
  186     stat_valid = stat(ctx->fname, &sb) >= 0;
  187 
  188     if (!stat_valid) {
  189         if (ctx->start == 0 && ctx->end == 0) {
  190         ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
  191         }
  192     }
  193     }
  194     else {
  195     stat_valid = fstat(fileno(ctx->f), &sb) >= 0;
  196     }
  197 
  198     if (!stat_valid) {
  199     zip_error_set(&ctx->stat_error, ZIP_ER_READ, errno);
  200     }
  201     else {
  202     if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) {
  203         ctx->st.mtime = sb.st_mtime;
  204         ctx->st.valid |= ZIP_STAT_MTIME;
  205     }
  206     if (S_ISREG(sb.st_mode)) {
  207         ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
  208 
  209         if (ctx->start + ctx->end > (zip_uint64_t)sb.st_size) {
  210         zip_error_set(error, ZIP_ER_INVAL, 0);
  211         free(ctx->fname);
  212         free(ctx);
  213         return NULL;
  214         }
  215 
  216         if (ctx->end == 0) {
  217         ctx->st.size = (zip_uint64_t)sb.st_size - ctx->start;
  218         ctx->st.valid |= ZIP_STAT_SIZE;
  219 
  220         if (ctx->fname && start == 0) {
  221             ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
  222         }
  223         }
  224     }
  225     }
  226 
  227 #ifdef CAN_CLONE
  228     if (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE)) {
  229     ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING);
  230     }
  231 #endif
  232 
  233     if ((zs = zip_source_function_create(read_file, ctx, error)) == NULL) {
  234     free(ctx->fname);
  235     free(ctx);
  236     return NULL;
  237     }
  238 
  239     return zs;
  240 }
  241 
  242 
  243 static int
  244 create_temp_output(struct read_file *ctx) {
  245     char *temp;
  246     int tfd;
  247     mode_t mask;
  248     FILE *tfp;
  249 
  250     if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
  251     zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
  252     return -1;
  253     }
  254     sprintf(temp, "%s.XXXXXX", ctx->fname);
  255 
  256     mask = umask(_SAFE_MASK);
  257     if ((tfd = mkstemp(temp)) == -1) {
  258     zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  259     umask(mask);
  260     free(temp);
  261     return -1;
  262     }
  263     umask(mask);
  264 
  265     if ((tfp = fdopen(tfd, "r+b")) == NULL) {
  266     zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  267     close(tfd);
  268     (void)remove(temp);
  269     free(temp);
  270     return -1;
  271     }
  272 
  273 #ifdef _WIN32
  274     /*
  275      According to Pierre Joye, Windows in some environments per
  276      default creates text files, so force binary mode.
  277      */
  278     _setmode(_fileno(tfp), _O_BINARY);
  279 #endif
  280 
  281     ctx->fout = tfp;
  282     ctx->tmpname = temp;
  283 
  284     return 0;
  285 }
  286 
  287 #ifdef CAN_CLONE
  288 zip_int64_t static create_temp_output_cloning(struct read_file *ctx, zip_uint64_t offset) {
  289     char *temp;
  290     FILE *tfp;
  291 
  292     if (offset > ZIP_OFF_MAX) {
  293     zip_error_set(&ctx->error, ZIP_ER_SEEK, E2BIG);
  294     return -1;
  295     }
  296 
  297     if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) {
  298     zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
  299     return -1;
  300     }
  301     sprintf(temp, "%s.XXXXXX", ctx->fname);
  302 
  303 #ifdef HAVE_CLONEFILE
  304 #ifndef __clang_analyzer__
  305     /* we can't use mkstemp, since clonefile insists on creating the file */
  306     if (mktemp(temp) == NULL) {
  307     zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  308     free(temp);
  309     return -1;
  310     }
  311 #endif
  312 
  313     if (clonefile(ctx->fname, temp, 0) < 0) {
  314     zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  315     free(temp);
  316     return -1;
  317     }
  318     if ((tfp = fopen(temp, "r+b")) == NULL) {
  319     zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  320     (void)remove(temp);
  321     free(temp);
  322     return -1;
  323     }
  324 #else
  325     {
  326     int fd;
  327     struct file_clone_range range;
  328     struct stat st;
  329 
  330     if (fstat(fileno(ctx->f), &st) < 0) {
  331         zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  332         return -1;
  333     }
  334 
  335     if ((fd = mkstemp(temp)) < 0) {
  336         zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  337         free(temp);
  338         return -1;
  339     }
  340 
  341     range.src_fd = fileno(ctx->f);
  342     range.src_offset = 0;
  343     range.src_length = ((offset + st.st_blksize - 1) / st.st_blksize) * st.st_blksize;
  344     if (range.src_length > st.st_size) {
  345         range.src_length = 0;
  346     }
  347     range.dest_offset = 0;
  348     if (ioctl(fd, FICLONERANGE, &range) < 0) {
  349         zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  350         (void)close(fd);
  351         (void)remove(temp);
  352         free(temp);
  353         return -1;
  354     }
  355 
  356     if ((tfp = fdopen(fd, "r+b")) == NULL) {
  357         zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  358         (void)close(fd);
  359         (void)remove(temp);
  360         free(temp);
  361         return -1;
  362     }
  363     }
  364 #endif
  365 
  366     if (ftruncate(fileno(tfp), (off_t)offset) < 0) {
  367     (void)fclose(tfp);
  368     (void)remove(temp);
  369     free(temp);
  370     return -1;
  371     }
  372     if (fseeko(tfp, (off_t)offset, SEEK_SET) < 0) {
  373     (void)fclose(tfp);
  374     (void)remove(temp);
  375     free(temp);
  376     zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
  377     }
  378 
  379     ctx->fout = tfp;
  380     ctx->tmpname = temp;
  381 
  382     return 0;
  383 }
  384 #endif
  385 
  386 
  387 static zip_int64_t
  388 read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) {
  389     struct read_file *ctx;
  390     char *buf;
  391     zip_uint64_t n;
  392     size_t i;
  393 
  394     ctx = (struct read_file *)state;
  395     buf = (char *)data;
  396 
  397     switch (cmd) {
  398     case ZIP_SOURCE_BEGIN_WRITE:
  399     if (ctx->fname == NULL) {
  400         zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
  401         return -1;
  402     }
  403     return create_temp_output(ctx);
  404 
  405 #ifdef CAN_CLONE
  406     case ZIP_SOURCE_BEGIN_WRITE_CLONING:
  407     if (ctx->fname == NULL) {
  408         zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
  409         return -1;
  410     }
  411     return create_temp_output_cloning(ctx, len);
  412 #endif
  413 
  414     case ZIP_SOURCE_COMMIT_WRITE: {
  415     mode_t mask;
  416 
  417     if (fclose(ctx->fout) < 0) {
  418         ctx->fout = NULL;
  419         zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
  420     }
  421     ctx->fout = NULL;
  422     if (rename(ctx->tmpname, ctx->fname) < 0) {
  423         zip_error_set(&ctx->error, ZIP_ER_RENAME, errno);
  424         return -1;
  425     }
  426     mask = umask(022);
  427     umask(mask);
  428     /* not much we can do if chmod fails except make the whole commit fail */
  429     (void)chmod(ctx->fname, 0666 & ~mask);
  430     free(ctx->tmpname);
  431     ctx->tmpname = NULL;
  432     return 0;
  433     }
  434 
  435     case ZIP_SOURCE_CLOSE:
  436     if (ctx->fname) {
  437         fclose(ctx->f);
  438         ctx->f = NULL;
  439     }
  440     return 0;
  441 
  442     case ZIP_SOURCE_ERROR:
  443     return zip_error_to_data(&ctx->error, data, len);
  444 
  445     case ZIP_SOURCE_FREE:
  446     free(ctx->fname);
  447     free(ctx->tmpname);
  448     if (ctx->f)
  449         fclose(ctx->f);
  450     free(ctx);
  451     return 0;
  452 
  453     case ZIP_SOURCE_OPEN:
  454     if (ctx->fname) {
  455         if ((ctx->f = fopen(ctx->fname, "rb")) == NULL) {
  456         zip_error_set(&ctx->error, ZIP_ER_OPEN, errno);
  457         return -1;
  458         }
  459     }
  460 
  461     if (ctx->start > 0) {
  462         if (_zip_fseek_u(ctx->f, ctx->start, SEEK_SET, &ctx->error) < 0) {
  463         /* TODO: skip by reading */
  464         return -1;
  465         }
  466     }
  467     ctx->current = 0;
  468     return 0;
  469 
  470     case ZIP_SOURCE_READ:
  471     if (ctx->end > 0) {
  472         n = ctx->end - ctx->current;
  473         if (n > len) {
  474         n = len;
  475         }
  476     }
  477     else {
  478         n = len;
  479     }
  480 
  481     if (n > SIZE_MAX)
  482         n = SIZE_MAX;
  483 
  484     if ((i = fread(buf, 1, (size_t)n, ctx->f)) == 0) {
  485         if (ferror(ctx->f)) {
  486         zip_error_set(&ctx->error, ZIP_ER_READ, errno);
  487         return -1;
  488         }
  489     }
  490     ctx->current += i;
  491 
  492     return (zip_int64_t)i;
  493 
  494     case ZIP_SOURCE_REMOVE:
  495     if (remove(ctx->fname) < 0) {
  496         zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno);
  497         return -1;
  498     }
  499     return 0;
  500 
  501     case ZIP_SOURCE_ROLLBACK_WRITE:
  502     if (ctx->fout) {
  503         fclose(ctx->fout);
  504         ctx->fout = NULL;
  505     }
  506     (void)remove(ctx->tmpname);
  507     free(ctx->tmpname);
  508     ctx->tmpname = NULL;
  509     return 0;
  510 
  511     case ZIP_SOURCE_SEEK: {
  512     zip_int64_t new_current;
  513     int need_seek;
  514     zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
  515 
  516     if (args == NULL)
  517         return -1;
  518 
  519     need_seek = 1;
  520 
  521     switch (args->whence) {
  522     case SEEK_SET:
  523         new_current = args->offset;
  524         break;
  525 
  526     case SEEK_END:
  527         if (ctx->end == 0) {
  528         if (_zip_fseek(ctx->f, args->offset, SEEK_END, &ctx->error) < 0) {
  529             return -1;
  530         }
  531         if ((new_current = ftello(ctx->f)) < 0) {
  532             zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);
  533             return -1;
  534         }
  535         new_current -= (zip_int64_t)ctx->start;
  536         need_seek = 0;
  537         }
  538         else {
  539         new_current = (zip_int64_t)ctx->end + args->offset;
  540         }
  541         break;
  542 
  543     case SEEK_CUR:
  544         new_current = (zip_int64_t)ctx->current + args->offset;
  545         break;
  546 
  547     default:
  548         zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
  549         return -1;
  550     }
  551 
  552     if (new_current < 0 || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end) || (zip_uint64_t)new_current + ctx->start < ctx->start) {
  553         zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
  554         return -1;
  555     }
  556 
  557     ctx->current = (zip_uint64_t)new_current;
  558 
  559     if (need_seek) {
  560         if (_zip_fseek_u(ctx->f, ctx->current + ctx->start, SEEK_SET, &ctx->error) < 0) {
  561         return -1;
  562         }
  563     }
  564     return 0;
  565     }
  566 
  567     case ZIP_SOURCE_SEEK_WRITE: {
  568     zip_source_args_seek_t *args;
  569 
  570     args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
  571     if (args == NULL) {
  572         return -1;
  573     }
  574 
  575     if (_zip_fseek(ctx->fout, args->offset, args->whence, &ctx->error) < 0) {
  576         return -1;
  577     }
  578     return 0;
  579     }
  580 
  581     case ZIP_SOURCE_STAT: {
  582     if (len < sizeof(ctx->st))
  583         return -1;
  584 
  585     if (zip_error_code_zip(&ctx->stat_error) != 0) {
  586         zip_error_set(&ctx->error, zip_error_code_zip(&ctx->stat_error), zip_error_code_system(&ctx->stat_error));
  587         return -1;
  588     }
  589 
  590     memcpy(data, &ctx->st, sizeof(ctx->st));
  591     return sizeof(ctx->st);
  592     }
  593 
  594     case ZIP_SOURCE_SUPPORTS:
  595     return ctx->supports;
  596 
  597     case ZIP_SOURCE_TELL:
  598     return (zip_int64_t)ctx->current;
  599 
  600     case ZIP_SOURCE_TELL_WRITE: {
  601     off_t ret = ftello(ctx->fout);
  602 
  603     if (ret < 0) {
  604         zip_error_set(&ctx->error, ZIP_ER_TELL, errno);
  605         return -1;
  606     }
  607     return ret;
  608     }
  609 
  610     case ZIP_SOURCE_WRITE: {
  611     size_t ret;
  612 
  613     clearerr(ctx->fout);
  614     ret = fwrite(data, 1, len, ctx->fout);
  615     if (ret != len || ferror(ctx->fout)) {
  616         zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
  617         return -1;
  618     }
  619 
  620     return (zip_int64_t)ret;
  621     }
  622 
  623     default:
  624     zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
  625     return -1;
  626     }
  627 }
  628 
  629 
  630 static int
  631 _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error) {
  632     if (offset > ZIP_INT64_MAX) {
  633     zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
  634     return -1;
  635     }
  636     return _zip_fseek(f, (zip_int64_t)offset, whence, error);
  637 }
  638 
  639 
  640 static int
  641 _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error) {
  642     if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) {
  643     zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
  644     return -1;
  645     }
  646     if (fseeko(f, (off_t)offset, whence) < 0) {
  647     zip_error_set(error, ZIP_ER_SEEK, errno);
  648     return -1;
  649     }
  650     return 0;
  651 }