From cd7a01c34fc4304ef8161ee617568f274ace5d24 Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sun, 18 Mar 2018 23:13:40 +0100 Subject: Windows: Update libzip to version 1.5.0 that include fixes for some security issues. --- src/Common/libzip/zip_source_filep.c | 650 +++++++++++++++++++++-------------- 1 file changed, 387 insertions(+), 263 deletions(-) (limited to 'src/Common/libzip/zip_source_filep.c') diff --git a/src/Common/libzip/zip_source_filep.c b/src/Common/libzip/zip_source_filep.c index a8a271a8..9fc9a01c 100644 --- a/src/Common/libzip/zip_source_filep.c +++ b/src/Common/libzip/zip_source_filep.c @@ -1,6 +1,6 @@ /* zip_source_filep.c -- create data source from FILE * - Copyright (C) 1999-2016 Dieter Baron and Thomas Klausner + Copyright (C) 1999-2017 Dieter Baron and Thomas Klausner This file is part of libzip, a library to manipulate ZIP archives. The authors can be contacted at @@ -31,10 +31,10 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include #include +#include #include "zipint.h" @@ -42,6 +42,17 @@ #include #endif +#ifdef HAVE_CLONEFILE +#include +#include +#define CAN_CLONE +#endif +#ifdef HAVE_FICLONERANGE +#include +#include +#define CAN_CLONE +#endif + #ifdef _WIN32 /* WIN32 needs for _O_BINARY */ #include @@ -49,7 +60,7 @@ /* Windows sys/types.h does not provide these */ #ifndef S_ISREG -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISREG(m) (((m)&S_IFMT) == S_IFREG) #endif #if defined(S_IXUSR) && defined(S_IRWXG) && defined(S_IRWXO) #define _SAFE_MASK (S_IXUSR | S_IRWXG | S_IRWXO) @@ -65,7 +76,7 @@ typedef int mode_t; #endif struct read_file { - zip_error_t error; /* last error information */ + zip_error_t error; /* last error information */ zip_int64_t supports; /* reading */ @@ -84,13 +95,15 @@ struct read_file { static zip_int64_t read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd); static int create_temp_output(struct read_file *ctx); +#ifdef CAN_CLONE +static zip_int64_t create_temp_output_cloning(struct read_file *ctx, zip_uint64_t offset); +#endif static int _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error); static int _zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error); ZIP_EXTERN zip_source_t * -zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len) -{ +zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len) { if (za == NULL) return NULL; @@ -99,8 +112,7 @@ zip_source_filep(zip_t *za, FILE *file, zip_uint64_t start, zip_int64_t len) ZIP_EXTERN zip_source_t * -zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error) -{ +zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_error_t *error) { if (file == NULL || length < -1) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; @@ -111,10 +123,11 @@ zip_source_filep_create(FILE *file, zip_uint64_t start, zip_int64_t length, zip_ zip_source_t * -_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) -{ +_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) { struct read_file *ctx; zip_source_t *zs; + struct stat sb; + bool stat_valid; if (file == NULL && fname == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); @@ -130,14 +143,14 @@ _zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int return NULL; } - if ((ctx=(struct read_file *)malloc(sizeof(struct read_file))) == NULL) { + if ((ctx = (struct read_file *)malloc(sizeof(struct read_file))) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); return NULL; } ctx->fname = NULL; if (fname) { - if ((ctx->fname=strdup(fname)) == NULL) { + if ((ctx->fname = strdup(fname)) == NULL) { zip_error_set(error, ZIP_ER_MEMORY, 0); free(ctx); return NULL; @@ -148,8 +161,8 @@ _zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int ctx->end = (zip_uint64_t)len; if (st) { memcpy(&ctx->st, st, sizeof(ctx->st)); - ctx->st.name = NULL; - ctx->st.valid &= ~ZIP_STAT_NAME; + ctx->st.name = NULL; + ctx->st.valid &= ~ZIP_STAT_NAME; } else { zip_stat_init(&ctx->st); @@ -170,44 +183,54 @@ _zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int ctx->supports = ZIP_SOURCE_SUPPORTS_READABLE | zip_source_make_command_bitmap(ZIP_SOURCE_SUPPORTS, ZIP_SOURCE_TELL, -1); if (ctx->fname) { - struct stat sb; - if (stat(ctx->fname, &sb) < 0) { - zip_error_set(&ctx->stat_error, ZIP_ER_READ, errno); + stat_valid = stat(ctx->fname, &sb) >= 0; + + if (!stat_valid) { if (ctx->start == 0 && ctx->end == 0) { ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE; } } - else { - if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) { - ctx->st.mtime = sb.st_mtime; - ctx->st.valid |= ZIP_STAT_MTIME; + } + else { + stat_valid = fstat(fileno(ctx->f), &sb) >= 0; + } + + if (!stat_valid) { + zip_error_set(&ctx->stat_error, ZIP_ER_READ, errno); + } + else { + if ((ctx->st.valid & ZIP_STAT_MTIME) == 0) { + ctx->st.mtime = sb.st_mtime; + ctx->st.valid |= ZIP_STAT_MTIME; + } + if (S_ISREG(sb.st_mode)) { + ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE; + + if (ctx->start + ctx->end > (zip_uint64_t)sb.st_size) { + zip_error_set(error, ZIP_ER_INVAL, 0); + free(ctx->fname); + free(ctx); + return NULL; } - if (S_ISREG(sb.st_mode)) { - ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE; - - if (ctx->start + ctx->end > (zip_uint64_t)sb.st_size) { - zip_error_set(error, ZIP_ER_INVAL, 0); - free(ctx->fname); - free(ctx); - return NULL; - } - if (ctx->end == 0) { - ctx->st.size = (zip_uint64_t)sb.st_size - ctx->start; - ctx->st.valid |= ZIP_STAT_SIZE; + if (ctx->end == 0) { + ctx->st.size = (zip_uint64_t)sb.st_size - ctx->start; + ctx->st.valid |= ZIP_STAT_SIZE; - if (start == 0) { - ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE; - } + if (ctx->fname && start == 0) { + ctx->supports = ZIP_SOURCE_SUPPORTS_WRITABLE; } } } } - else if (fseeko(ctx->f, 0, SEEK_CUR) == 0) { - ctx->supports = ZIP_SOURCE_SUPPORTS_SEEKABLE; + +#ifdef CAN_CLONE + if (ctx->supports & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE)) { + ctx->supports |= ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_BEGIN_WRITE_CLONING); } +#endif - if ((zs=zip_source_function_create(read_file, ctx, error)) == NULL) { + if ((zs = zip_source_function_create(read_file, ctx, error)) == NULL) { free(ctx->fname); free(ctx); return NULL; @@ -218,34 +241,33 @@ _zip_source_file_or_p(const char *fname, FILE *file, zip_uint64_t start, zip_int static int -create_temp_output(struct read_file *ctx) -{ +create_temp_output(struct read_file *ctx) { char *temp; int tfd; mode_t mask; FILE *tfp; - if ((temp=(char *)malloc(strlen(ctx->fname)+8)) == NULL) { + if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) { zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); return -1; } sprintf(temp, "%s.XXXXXX", ctx->fname); mask = umask(_SAFE_MASK); - if ((tfd=mkstemp(temp)) == -1) { - zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + if ((tfd = mkstemp(temp)) == -1) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); umask(mask); - free(temp); - return -1; + free(temp); + return -1; } umask(mask); - if ((tfp=fdopen(tfd, "r+b")) == NULL) { - zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); - close(tfd); - (void)remove(temp); - free(temp); - return -1; + if ((tfp = fdopen(tfd, "r+b")) == NULL) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + close(tfd); + (void)remove(temp); + free(temp); + return -1; } #ifdef _WIN32 @@ -253,7 +275,7 @@ create_temp_output(struct read_file *ctx) According to Pierre Joye, Windows in some environments per default creates text files, so force binary mode. */ - _setmode(_fileno(tfp), _O_BINARY ); + _setmode(_fileno(tfp), _O_BINARY); #endif ctx->fout = tfp; @@ -262,10 +284,108 @@ create_temp_output(struct read_file *ctx) return 0; } +#ifdef CAN_CLONE +zip_int64_t static create_temp_output_cloning(struct read_file *ctx, zip_uint64_t offset) { + char *temp; + FILE *tfp; + + if (offset > ZIP_OFF_MAX) { + zip_error_set(&ctx->error, ZIP_ER_SEEK, E2BIG); + return -1; + } + + if ((temp = (char *)malloc(strlen(ctx->fname) + 8)) == NULL) { + zip_error_set(&ctx->error, ZIP_ER_MEMORY, 0); + return -1; + } + sprintf(temp, "%s.XXXXXX", ctx->fname); + +#ifdef HAVE_CLONEFILE +#ifndef __clang_analyzer__ + /* we can't use mkstemp, since clonefile insists on creating the file */ + if (mktemp(temp) == NULL) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + free(temp); + return -1; + } +#endif + + if (clonefile(ctx->fname, temp, 0) < 0) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + free(temp); + return -1; + } + if ((tfp = fopen(temp, "r+b")) == NULL) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + (void)remove(temp); + free(temp); + return -1; + } +#else + { + int fd; + struct file_clone_range range; + struct stat st; + + if (fstat(fileno(ctx->f), &st) < 0) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + return -1; + } + + if ((fd = mkstemp(temp)) < 0) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + free(temp); + return -1; + } + + range.src_fd = fileno(ctx->f); + range.src_offset = 0; + range.src_length = ((offset + st.st_blksize - 1) / st.st_blksize) * st.st_blksize; + if (range.src_length > st.st_size) { + range.src_length = 0; + } + range.dest_offset = 0; + if (ioctl(fd, FICLONERANGE, &range) < 0) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + (void)close(fd); + (void)remove(temp); + free(temp); + return -1; + } + + if ((tfp = fdopen(fd, "r+b")) == NULL) { + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + (void)close(fd); + (void)remove(temp); + free(temp); + return -1; + } + } +#endif + + if (ftruncate(fileno(tfp), (off_t)offset) < 0) { + (void)fclose(tfp); + (void)remove(temp); + free(temp); + return -1; + } + if (fseeko(tfp, (off_t)offset, SEEK_SET) < 0) { + (void)fclose(tfp); + (void)remove(temp); + free(temp); + zip_error_set(&ctx->error, ZIP_ER_TMPOPEN, errno); + } + + ctx->fout = tfp; + ctx->tmpname = temp; + + return 0; +} +#endif + static zip_int64_t -read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) -{ +read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct read_file *ctx; char *buf; zip_uint64_t n; @@ -275,235 +395,240 @@ read_file(void *state, void *data, zip_uint64_t len, zip_source_cmd_t cmd) buf = (char *)data; switch (cmd) { - case ZIP_SOURCE_BEGIN_WRITE: - if (ctx->fname == NULL) { - zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); - return -1; - } - return create_temp_output(ctx); - - case ZIP_SOURCE_COMMIT_WRITE: { - mode_t mask; - - if (fclose(ctx->fout) < 0) { - ctx->fout = NULL; - zip_error_set(&ctx->error, ZIP_ER_WRITE, errno); - } - ctx->fout = NULL; - if (rename(ctx->tmpname, ctx->fname) < 0) { - zip_error_set(&ctx->error, ZIP_ER_RENAME, errno); - return -1; - } - mask = umask(022); - umask(mask); - /* not much we can do if chmod fails except make the whole commit fail */ - (void)chmod(ctx->fname, 0666&~mask); - free(ctx->tmpname); - ctx->tmpname = NULL; - return 0; + case ZIP_SOURCE_BEGIN_WRITE: + if (ctx->fname == NULL) { + zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + return create_temp_output(ctx); + +#ifdef CAN_CLONE + case ZIP_SOURCE_BEGIN_WRITE_CLONING: + if (ctx->fname == NULL) { + zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); + return -1; + } + return create_temp_output_cloning(ctx, len); +#endif + + case ZIP_SOURCE_COMMIT_WRITE: { + mode_t mask; + + if (fclose(ctx->fout) < 0) { + ctx->fout = NULL; + zip_error_set(&ctx->error, ZIP_ER_WRITE, errno); + } + ctx->fout = NULL; + if (rename(ctx->tmpname, ctx->fname) < 0) { + zip_error_set(&ctx->error, ZIP_ER_RENAME, errno); + return -1; + } + mask = umask(022); + umask(mask); + /* not much we can do if chmod fails except make the whole commit fail */ + (void)chmod(ctx->fname, 0666 & ~mask); + free(ctx->tmpname); + ctx->tmpname = NULL; + return 0; + } + + case ZIP_SOURCE_CLOSE: + if (ctx->fname) { + fclose(ctx->f); + ctx->f = NULL; + } + return 0; + + case ZIP_SOURCE_ERROR: + return zip_error_to_data(&ctx->error, data, len); + + case ZIP_SOURCE_FREE: + free(ctx->fname); + free(ctx->tmpname); + if (ctx->f) + fclose(ctx->f); + free(ctx); + return 0; + + case ZIP_SOURCE_OPEN: + if (ctx->fname) { + if ((ctx->f = fopen(ctx->fname, "rb")) == NULL) { + zip_error_set(&ctx->error, ZIP_ER_OPEN, errno); + return -1; + } } - case ZIP_SOURCE_CLOSE: - if (ctx->fname) { - fclose(ctx->f); - ctx->f = NULL; - } - return 0; - - case ZIP_SOURCE_ERROR: - return zip_error_to_data(&ctx->error, data, len); - - case ZIP_SOURCE_FREE: - free(ctx->fname); - free(ctx->tmpname); - if (ctx->f) - fclose(ctx->f); - free(ctx); - return 0; - - case ZIP_SOURCE_OPEN: - if (ctx->fname) { - if ((ctx->f=fopen(ctx->fname, "rb")) == NULL) { - zip_error_set(&ctx->error, ZIP_ER_OPEN, errno); - return -1; - } - } - - if (ctx->start > 0) { - if (_zip_fseek_u(ctx->f, ctx->start, SEEK_SET, &ctx->error) < 0) { - /* TODO: skip by reading */ - return -1; - } - } - ctx->current = 0; - return 0; - - case ZIP_SOURCE_READ: - if (ctx->end > 0) { - n = ctx->end - ctx->current; - if (n > len) { - n = len; - } - } - else { - n = len; - } - - if (n > SIZE_MAX) - n = SIZE_MAX; - - if ((i=fread(buf, 1, (size_t)n, ctx->f)) == 0) { - if (ferror(ctx->f)) { - zip_error_set(&ctx->error, ZIP_ER_READ, errno); - return -1; - } - } - ctx->current += i; - - return (zip_int64_t)i; - - case ZIP_SOURCE_REMOVE: - if (remove(ctx->fname) < 0) { - zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno); - return -1; - } - return 0; - - case ZIP_SOURCE_ROLLBACK_WRITE: - if (ctx->fout) { - fclose(ctx->fout); - ctx->fout = NULL; - } - (void)remove(ctx->tmpname); - free(ctx->tmpname); - ctx->tmpname = NULL; - return 0; - - case ZIP_SOURCE_SEEK: { - zip_int64_t new_current; - int need_seek; - zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); - - if (args == NULL) + if (ctx->start > 0) { + if (_zip_fseek_u(ctx->f, ctx->start, SEEK_SET, &ctx->error) < 0) { + /* TODO: skip by reading */ return -1; + } + } + ctx->current = 0; + return 0; + + case ZIP_SOURCE_READ: + if (ctx->end > 0) { + n = ctx->end - ctx->current; + if (n > len) { + n = len; + } + } + else { + n = len; + } + + if (n > SIZE_MAX) + n = SIZE_MAX; - need_seek = 1; - - switch (args->whence) { - case SEEK_SET: - new_current = args->offset; - break; - - case SEEK_END: - if (ctx->end == 0) { - if (_zip_fseek(ctx->f, args->offset, SEEK_END, &ctx->error) < 0) { - return -1; - } - if ((new_current = ftello(ctx->f)) < 0) { - zip_error_set(&ctx->error, ZIP_ER_SEEK, errno); - return -1; - } - new_current -= (zip_int64_t)ctx->start; - need_seek = 0; - } - else { - new_current = (zip_int64_t)ctx->end + args->offset; - } - break; - - case SEEK_CUR: - new_current = (zip_int64_t)ctx->current + args->offset; - break; - - default: - zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); - return -1; - } - - if (new_current < 0 || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end) - || (zip_uint64_t)new_current + ctx->start < ctx->start) { - zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); - return -1; - } - - ctx->current = (zip_uint64_t)new_current; - - if (need_seek) { - if (_zip_fseek_u(ctx->f, ctx->current + ctx->start, SEEK_SET, &ctx->error) < 0) { - return -1; - } - } - return 0; - } - - case ZIP_SOURCE_SEEK_WRITE: { - zip_source_args_seek_t *args; - - args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); - if (args == NULL) { - return -1; - } - - if (_zip_fseek(ctx->fout, args->offset, args->whence, &ctx->error) < 0) { - return -1; - } - return 0; - } - - case ZIP_SOURCE_STAT: { - if (len < sizeof(ctx->st)) + if ((i = fread(buf, 1, (size_t)n, ctx->f)) == 0) { + if (ferror(ctx->f)) { + zip_error_set(&ctx->error, ZIP_ER_READ, errno); return -1; + } + } + ctx->current += i; + + return (zip_int64_t)i; - if (zip_error_code_zip(&ctx->stat_error) != 0) { - zip_error_set(&ctx->error, zip_error_code_zip(&ctx->stat_error), zip_error_code_system(&ctx->stat_error)); + case ZIP_SOURCE_REMOVE: + if (remove(ctx->fname) < 0) { + zip_error_set(&ctx->error, ZIP_ER_REMOVE, errno); + return -1; + } + return 0; + + case ZIP_SOURCE_ROLLBACK_WRITE: + if (ctx->fout) { + fclose(ctx->fout); + ctx->fout = NULL; + } + (void)remove(ctx->tmpname); + free(ctx->tmpname); + ctx->tmpname = NULL; + return 0; + + case ZIP_SOURCE_SEEK: { + zip_int64_t new_current; + int need_seek; + zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); + + if (args == NULL) + return -1; + + need_seek = 1; + + switch (args->whence) { + case SEEK_SET: + new_current = args->offset; + break; + + case SEEK_END: + if (ctx->end == 0) { + if (_zip_fseek(ctx->f, args->offset, SEEK_END, &ctx->error) < 0) { + return -1; + } + if ((new_current = ftello(ctx->f)) < 0) { + zip_error_set(&ctx->error, ZIP_ER_SEEK, errno); + return -1; + } + new_current -= (zip_int64_t)ctx->start; + need_seek = 0; + } + else { + new_current = (zip_int64_t)ctx->end + args->offset; + } + break; + + case SEEK_CUR: + new_current = (zip_int64_t)ctx->current + args->offset; + break; + + default: + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + + if (new_current < 0 || (ctx->end != 0 && (zip_uint64_t)new_current > ctx->end) || (zip_uint64_t)new_current + ctx->start < ctx->start) { + zip_error_set(&ctx->error, ZIP_ER_INVAL, 0); + return -1; + } + + ctx->current = (zip_uint64_t)new_current; + + if (need_seek) { + if (_zip_fseek_u(ctx->f, ctx->current + ctx->start, SEEK_SET, &ctx->error) < 0) { return -1; } + } + return 0; + } + + case ZIP_SOURCE_SEEK_WRITE: { + zip_source_args_seek_t *args; - memcpy(data, &ctx->st, sizeof(ctx->st)); - return sizeof(ctx->st); + args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); + if (args == NULL) { + return -1; } - case ZIP_SOURCE_SUPPORTS: - return ctx->supports; + if (_zip_fseek(ctx->fout, args->offset, args->whence, &ctx->error) < 0) { + return -1; + } + return 0; + } - case ZIP_SOURCE_TELL: - return (zip_int64_t)ctx->current; + case ZIP_SOURCE_STAT: { + if (len < sizeof(ctx->st)) + return -1; - case ZIP_SOURCE_TELL_WRITE: - { - off_t ret = ftello(ctx->fout); + if (zip_error_code_zip(&ctx->stat_error) != 0) { + zip_error_set(&ctx->error, zip_error_code_zip(&ctx->stat_error), zip_error_code_system(&ctx->stat_error)); + return -1; + } - if (ret < 0) { - zip_error_set(&ctx->error, ZIP_ER_TELL, errno); - return -1; - } - return ret; - } + memcpy(data, &ctx->st, sizeof(ctx->st)); + return sizeof(ctx->st); + } - case ZIP_SOURCE_WRITE: - { - size_t ret; + case ZIP_SOURCE_SUPPORTS: + return ctx->supports; - clearerr(ctx->fout); - ret = fwrite(data, 1, len, ctx->fout); - if (ret != len || ferror(ctx->fout)) { - zip_error_set(&ctx->error, ZIP_ER_WRITE, errno); - return -1; - } + case ZIP_SOURCE_TELL: + return (zip_int64_t)ctx->current; - return (zip_int64_t)ret; - } + case ZIP_SOURCE_TELL_WRITE: { + off_t ret = ftello(ctx->fout); - default: - zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); - return -1; + if (ret < 0) { + zip_error_set(&ctx->error, ZIP_ER_TELL, errno); + return -1; + } + return ret; + } + + case ZIP_SOURCE_WRITE: { + size_t ret; + + clearerr(ctx->fout); + ret = fwrite(data, 1, len, ctx->fout); + if (ret != len || ferror(ctx->fout)) { + zip_error_set(&ctx->error, ZIP_ER_WRITE, errno); + return -1; + } + + return (zip_int64_t)ret; + } + + default: + zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); + return -1; } } static int -_zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error) -{ +_zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error) { if (offset > ZIP_INT64_MAX) { zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW); return -1; @@ -513,8 +638,7 @@ _zip_fseek_u(FILE *f, zip_uint64_t offset, int whence, zip_error_t *error) static int -_zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error) -{ +_zip_fseek(FILE *f, zip_int64_t offset, int whence, zip_error_t *error) { if (offset > ZIP_FSEEK_MAX || offset < ZIP_FSEEK_MIN) { zip_error_set(error, ZIP_ER_SEEK, EOVERFLOW); return -1; -- cgit v1.2.3