root/ext/zip/lib/zip_source_filep.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zip_source_filep
  2. zip_source_filep_create
  3. _zip_source_file_or_p
  4. create_temp_output
  5. read_file
  6. _zip_fseek_u
  7. _zip_fseek

   1 /*
   2   zip_source_filep.c -- create data source from FILE *
   3   Copyright (C) 1999-2015 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 <sys/stat.h>
  35 #include <stdio.h>
  36 #include <stdlib.h>
  37 #include <string.h>
  38 
  39 #include "zipint.h"
  40 
  41 #ifdef HAVE_UNISTD_H
  42 #include <unistd.h>
  43 #endif
  44 
  45 #ifdef _WIN32
  46 /* WIN32 needs <fcntl.h> for _O_BINARY */
  47 #include <fcntl.h>
  48 #endif
  49 
  50 /* Windows sys/types.h does not provide these */
  51 #ifndef S_ISREG
  52 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  53 #endif
  54 #if defined(S_IXUSR) && defined(S_IRWXG) && defined(S_IRWXO)
  55 #define _SAFE_MASK (S_IXUSR | S_IRWXG | S_IRWXO)
  56 #elif defined(_S_IWRITE)
  57 #define _SAFE_MASK (_S_IWRITE)
  58 #else
  59 #error do not know safe values for umask, please report this
  60 #endif
  61 
  62 #ifdef _MSC_VER
  63 /* MSVC doesn't have mode_t */
  64 typedef int mode_t;
  65 #endif
  66 
  67 struct read_file {
  68     zip_error_t error;      /* last error information */
  69     zip_int64_t supports;
  70 
  71     /* reading */
  72     char *fname;            /* name of file to read from */
  73     FILE *f;                /* file to read from */
  74     struct zip_stat st;     /* stat information passed in */
  75     zip_uint64_t start;     /* start offset of data to read */
  76     zip_uint64_t end;       /* end offset of data to read, 0 for up to EOF */
  77     zip_uint64_t current;   /* current offset */
  78     
  79     /* writing */
  80     char *tmpname;
  81     FILE *fout;
  82 };
  83 
  84 static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd);
  85 static int create_temp_output(struct read_file *ctx);
  86 static int _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error);
  87 static int _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error);
  88 
  89 
  90 ZIP_EXTERN zip_source_t *
  91 zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len)
  92 {
  93     if (za == NULL)
  94         return NULL;
  95     
  96     return zip_source_filep_create(file, start, len, &za->error);
  97 }
  98 
  99 
 100 ZIP_EXTERN zip_source_t *
 101 zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error)
 102 {
 103     if (file == NULL || length < -1) {
 104         zip_error_set(error, ZIP_ER_INVAL, 0);
 105         return NULL;
 106     }
 107 
 108     return _zip_source_file_or_p(NULL, file, start, length, NULL, error);
 109 }
 110 
 111 
 112 zip_source_t *
 113 _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)
 114 {
 115     struct read_file *ctx;
 116     zip_source_t *zs;
 117     
 118     if (file == NULL && fname == NULL) {
 119         zip_error_set(error, ZIP_ER_INVAL, 0);
 120         return NULL;
 121     }
 122     
 123     if ((ctx=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) {
 124         zip_error_set(error, ZIP_ER_MEMORY, 0);
 125         return NULL;
 126     }
 127 
 128     ctx->fname = NULL;
 129     if (fname) {
 130         if ((ctx->fname=strdup(fname)) == NULL) {
 131             zip_error_set(error, ZIP_ER_MEMORY, 0);
 132             free(ctx);
 133             return NULL;
 134         }
 135     }
 136     ctx->f = file;
 137     ctx->start = start;
 138     ctx->end = (len < 0 ? 0 : start+(zip_uint64_t)len);
 139     if (st) {
 140         memcpy(&ctx->st, st, sizeof(ctx->st));
 141         ctx->st.name = NULL;
 142         ctx->st.valid &= ~ZIP_STAT_NAME;
 143     }
 144     else {
 145         zip_stat_init(&ctx->st);
 146     }
 147     
 148     ctx->tmpname = NULL;
 149     ctx->fout = NULL;
 150    
 151     zip_error_init(&ctx->error);
 152 
 153     ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1);
 154     if (ctx->fname) {
 155         struct stat sb;
 156 
 157         if (stat(ctx->fname, &sb) < 0 || S_ISREG(sb.st_mode)) {
 158             ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE;
 159         }
 160     }
 161     else if (fseeko(ctx->f, 0, SEEK_CUR) == 0) {
 162         ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE;
 163     }
 164 
 165     if ((zs=zip_source_function_create(read_file, ctx, error)) == NULL) {
 166         free(ctx->fname);
 167         free(ctx);
 168         return NULL;
 169     }
 170 
 171     return zs;
 172 }
 173 
 174 
 175 static int
 176 create_temp_output(struct read_file *ctx)
 177 {
 178     char *temp;
 179     int tfd;
 180     mode_t mask;
 181     FILE *tfp;
 182     
 183     if ((temp=(char *)malloc(strlen(ctx->fname)+8)) == NULL) {
 184         zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0);
 185         return -1;
 186     }
 187     sprintf(temp, "%s.XXXXXX", ctx->fname);
 188 
 189     mask = umask(_SAFE_MASK);
 190     if ((tfd=mkstemp(temp)) == -1) {
 191         zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
 192         umask(mask);
 193         free(temp);
 194         return -1;
 195     }
 196     umask(mask);
 197 
 198     if ((tfp=fdopen(tfd, "r+b")) == NULL) {
 199         zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno);
 200         close(tfd);
 201         (void)remove(temp);
 202         free(temp);
 203         return -1;
 204     }
 205     
 206 #ifdef _WIN32
 207     /*
 208      According to Pierre Joye, Windows in some environments per
 209      default creates text files, so force binary mode.
 210      */
 211     _setmode(_fileno(tfp), _O_BINARY );
 212 #endif
 213     
 214     ctx->fout = tfp;
 215     ctx->tmpname = temp;
 216     
 217     return 0;
 218 }
 219 
 220 
 221 static zip_int64_t
 222 read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
 223 {
 224     struct read_file *ctx;
 225     char *buf;
 226     zip_uint64_t n;
 227     size_t i;
 228 
 229     ctx = (struct read_file *)state;
 230     buf = (char *)data;
 231 
 232     switch (cmd) {
 233         case ZIP_SOURCE_BEGIN_WRITE:
 234             if (ctx->fname == NULL) {
 235                 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
 236                 return -1;
 237             }
 238             return create_temp_output(ctx);
 239             
 240         case ZIP_SOURCE_COMMIT_WRITE: {
 241             mode_t mask;
 242 
 243             if (fclose(ctx->fout) < 0) {
 244                 ctx->fout = NULL;
 245                 zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
 246             }
 247             ctx->fout = NULL;
 248             if (rename(ctx->tmpname, ctx->fname) < 0) {
 249                 zip_error_set(&ctx->error, ZIP_ER_RENAME, errno);
 250                 return -1;
 251             }
 252             mask = umask(022);
 253             umask(mask);
 254             /* not much we can do if chmod fails except make the whole commit fail */
 255             (void)chmod(ctx->fname, 0666&~mask);
 256             free(ctx->tmpname);
 257             ctx->tmpname = NULL;
 258             return 0;
 259         }
 260             
 261         case ZIP_SOURCE_CLOSE:
 262             if (ctx->fname) {
 263                 fclose(ctx->f);
 264                 ctx->f = NULL;
 265             }
 266             return 0;
 267             
 268         case ZIP_SOURCE_ERROR:
 269             return zip_error_to_data(&ctx->error, data, len);
 270             
 271         case ZIP_SOURCE_FREE:
 272             free(ctx->fname);
 273             free(ctx->tmpname);
 274             if (ctx->f)
 275                 fclose(ctx->f);
 276             free(ctx);
 277             return 0;
 278             
 279         case ZIP_SOURCE_OPEN:
 280             if (ctx->fname) {
 281                 if ((ctx->f=fopen(ctx->fname, "rb")) == NULL) {
 282                     zip_error_set(&ctx->error, ZIP_ER_OPEN, errno);
 283                     return -1;
 284                 }
 285             }
 286             
 287             if (ctx->start > 0) {
 288                 if (_zip_fseek_u(ctx->f, ctx->start, SEEK_SET, &ctx->error) < 0) {
 289                     return -1;
 290                 }
 291             }
 292             ctx->current = ctx->start;
 293             return 0;
 294             
 295         case ZIP_SOURCE_READ:
 296             if (ctx->end > 0) {
 297                 n = ctx->end-ctx->current;
 298                 if (n > len) {
 299                     n = len;
 300                 }
 301             }
 302             else {
 303                 n = len;
 304             }
 305             
 306             if (n > SIZE_MAX)
 307                 n = SIZE_MAX;
 308 
 309             if ((i=fread(buf, 1, (size_t)n, ctx->f)) == 0) {
 310                 if (ferror(ctx->f)) {
 311                     zip_error_set(&ctx->error, ZIP_ER_READ, errno);
 312                     return -1;
 313                 }
 314             }
 315             ctx->current += i;
 316 
 317             return (zip_int64_t)i;
 318             
 319         case ZIP_SOURCE_REMOVE:
 320             if (remove(ctx->fname) < 0) {
 321                 zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno);
 322                 return -1;
 323             }
 324             return 0;
 325             
 326         case ZIP_SOURCE_ROLLBACK_WRITE:
 327             if (ctx->fout) {
 328                 fclose(ctx->fout);
 329                 ctx->fout = NULL;
 330             }
 331             (void)remove(ctx->tmpname);
 332             free(ctx->tmpname);
 333             ctx->tmpname = NULL;
 334             return 0;
 335         
 336         case ZIP_SOURCE_SEEK: {
 337             zip_int64_t new_current;
 338             int need_seek;
 339             zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
 340 
 341             if (args == NULL)
 342                 return -1;
 343             
 344             need_seek = 1;
 345             
 346             switch (args->whence) {
 347                 case SEEK_SET:
 348                     new_current = args->offset;
 349                     break;
 350                     
 351                 case SEEK_END:
 352                     if (ctx->end == 0) {
 353                         if (_zip_fseek(ctx->f, args->offset, SEEK_END, &ctx->error) < 0) {
 354                             return -1;
 355                         }
 356                         if ((new_current = ftello(ctx->f)) < 0) {
 357                             zip_error_set(&ctx->error, ZIP_ER_SEEK, errno);
 358                             return -1;
 359                         }
 360                         need_seek = 0;
 361                     }
 362                     else {
 363                         new_current = (zip_int64_t)ctx->end + args->offset;
 364                     }
 365                     break;
 366                 case SEEK_CUR:
 367                     new_current = (zip_int64_t)ctx->current + args->offset;
 368                     break;
 369 
 370                 default:
 371                     zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
 372                     return -1;
 373             }
 374 
 375             if (new_current < 0 || (zip_uint64_t)new_current < ctx->start || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end)) {
 376                 zip_error_set(&ctx->error, ZIP_ER_INVAL, 0);
 377                 return -1;
 378             }
 379             
 380             ctx->current = (zip_uint64_t)new_current;
 381 
 382             if (need_seek) {
 383                 if (_zip_fseek_u(ctx->f, ctx->current, SEEK_SET, &ctx->error) < 0) {
 384                     return -1;
 385                 }
 386             }
 387             return 0;
 388         }
 389             
 390         case ZIP_SOURCE_SEEK_WRITE: {
 391             zip_source_args_seek_t *args;
 392             
 393             args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
 394             if (args == NULL) {
 395                 return -1;
 396             }
 397             
 398             if (_zip_fseek(ctx->fout, args->offset, args->whence, &ctx->error) < 0) {
 399                 return -1;
 400             }
 401             return 0;
 402         }
 403 
 404         case ZIP_SOURCE_STAT: {
 405             if (len < sizeof(ctx->st))
 406                 return -1;
 407 
 408             if (ctx->st.valid != 0)
 409                 memcpy(data, &ctx->st, sizeof(ctx->st));
 410             else {
 411                 zip_stat_t *st;
 412                 struct stat fst;
 413                 int err;
 414             
 415                 if (ctx->f)
 416                     err = fstat(fileno(ctx->f), &fst);
 417                 else
 418                     err = stat(ctx->fname, &fst);
 419 
 420                 if (err != 0) {
 421                     zip_error_set(&ctx->error, ZIP_ER_READ, errno);
 422                     return -1;
 423                 }
 424 
 425                 st = (zip_stat_t *)data;
 426                 
 427                 zip_stat_init(st);
 428                 st->mtime = fst.st_mtime;
 429                 st->valid |= ZIP_STAT_MTIME;
 430                 if (ctx->end != 0) {
 431                     st->size = ctx->end - ctx->start;
 432                     st->valid |= ZIP_STAT_SIZE;
 433                 }
 434                 else if ((fst.st_mode&S_IFMT) == S_IFREG) {
 435                     st->size = (zip_uint64_t)fst.st_size;
 436                     st->valid |= ZIP_STAT_SIZE;
 437                 }
 438             }
 439             return sizeof(ctx->st);
 440         }
 441 
 442         case ZIP_SOURCE_SUPPORTS:
 443             return ctx->supports;
 444             
 445         case ZIP_SOURCE_TELL:
 446             return (zip_int64_t)ctx->current;
 447             
 448         case ZIP_SOURCE_TELL_WRITE:
 449         {
 450             off_t ret = ftello(ctx->fout);
 451             
 452             if (ret < 0) {
 453                 zip_error_set(&ctx->error, ZIP_ER_TELL, errno);
 454                 return -1;
 455             }
 456             return ret;
 457         }
 458             
 459         case ZIP_SOURCE_WRITE:
 460         {
 461             size_t ret;
 462             
 463             clearerr(ctx->fout);
 464             ret = fwrite(data, 1, len, ctx->fout);
 465             if (ret != len || ferror(ctx->fout)) {
 466                 zip_error_set(&ctx->error, ZIP_ER_WRITE, errno);
 467                 return -1;
 468             }
 469             
 470             return (zip_int64_t)ret;
 471         }
 472 
 473         default:
 474             zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
 475             return -1;
 476     }
 477 }
 478 
 479 
 480 static int
 481 _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error)
 482 {
 483     if (offset > ZIP_INT64_MAX) {
 484         zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
 485         return -1;
 486     }
 487     return _zip_fseek(f, (zip_int64_t)offset, whence, error);
 488 }
 489 
 490 
 491 static int
 492 _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error)
 493 {
 494     if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) {
 495         zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW);
 496         return -1;
 497     }
 498     if (fseeko(f, (off_t)offset, whence) < 0) {
 499         zip_error_set(error, ZIP_ER_SEEK, errno);
 500         return -1;
 501     }
 502     return 0;
 503 }

/* [<][>][^][v][top][bottom][index][help] */