ZIP_EXTERN int zip_source_open(zip_source_t *src) { if (src->source_closed) { return -1; } if (src->write_state == ZIP_SOURCE_WRITE_REMOVED) { zip_error_set(&src->error, ZIP_ER_DELETED, 0); return -1; } if (ZIP_SOURCE_IS_OPEN_READING(src)) { if ((zip_source_supports(src) & ZIP_SOURCE_MAKE_COMMAND_BITMASK(ZIP_SOURCE_SEEK)) == 0) { zip_error_set(&src->error, ZIP_ER_INUSE, 0); return -1; } } else { if (ZIP_SOURCE_IS_LAYERED(src)) { if (zip_source_open(src->src) < 0) { _zip_error_set_from_source(&src->error, src->src); return -1; } } if (_zip_source_call(src, NULL, 0, ZIP_SOURCE_OPEN) < 0) { if (ZIP_SOURCE_IS_LAYERED(src)) { zip_source_close(src->src); } return -1; } } src->eof = false; src->had_read_error = false; _zip_error_clear(&src->error); src->open_count++; return 0; }
ZIP_EXTERN zip_t * zip_open_from_source(zip_source_t *src, int _flags, zip_error_t *error) { static zip_int64_t needed_support_read = -1; static zip_int64_t needed_support_write = -1; unsigned int flags; zip_int64_t supported; exists_t exists; if (_flags < 0 || src == NULL) { zip_error_set(error, ZIP_ER_INVAL, 0); return NULL; } flags = (unsigned int)_flags; supported = zip_source_supports(src); if (needed_support_read == -1) { needed_support_read = zip_source_make_command_bitmap(ZIP_SOURCE_OPEN, ZIP_SOURCE_READ, ZIP_SOURCE_CLOSE, ZIP_SOURCE_SEEK, ZIP_SOURCE_TELL, ZIP_SOURCE_STAT, -1); needed_support_write = zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1); } if ((supported & needed_support_read) != needed_support_read) { zip_error_set(error, ZIP_ER_OPNOTSUPP, 0); return NULL; } if ((supported & needed_support_write) != needed_support_write) { flags |= ZIP_RDONLY; } if ((flags & (ZIP_RDONLY|ZIP_TRUNCATE)) == (ZIP_RDONLY|ZIP_TRUNCATE)) { zip_error_set(error, ZIP_ER_RDONLY, 0); return NULL; } exists = _zip_file_exists(src, error); switch (exists) { case EXISTS_ERROR: return NULL; case EXISTS_NOT: if ((flags & ZIP_CREATE) == 0) { zip_error_set(error, ZIP_ER_NOENT, 0); return NULL; } return _zip_allocate_new(src, flags, error); default: { zip_t *za; if (flags & ZIP_EXCL) { zip_error_set(error, ZIP_ER_EXISTS, 0); return NULL; } if (zip_source_open(src) < 0) { _zip_error_set_from_source(error, src); return NULL; } if (flags & ZIP_TRUNCATE) { za = _zip_allocate_new(src, flags, error); } else { /* ZIP_CREATE gets ignored if file exists and not ZIP_EXCL, just like open() */ za = _zip_open(src, flags, error); } if (za == NULL) { zip_source_close(src); return NULL; } return za; } } }
static zip_int64_t crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd) { struct crc_context *ctx; zip_int64_t n; ctx = (struct crc_context *)_ctx; switch (cmd) { case ZIP_SOURCE_OPEN: ctx->position = 0; return 0; case ZIP_SOURCE_READ: if ((n = zip_source_read(src, data, len)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if (n == 0) { if (ctx->crc_position == ctx->position) { ctx->crc_complete = 1; ctx->size = ctx->position; if (ctx->validate) { struct zip_stat st; if (zip_source_stat(src, &st) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) { zip_error_set(&ctx->error, ZIP_ER_CRC, 0); return -1; } if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) { zip_error_set(&ctx->error, ZIP_ER_INCONS, 0); return -1; } } } } else if (!ctx->crc_complete && ctx->position <= ctx->crc_position) { zip_uint64_t i, nn; for (i = ctx->crc_position - ctx->position; i < (zip_uint64_t)n; i += nn) { nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n-i); ctx->crc = (zip_uint32_t)crc32(ctx->crc, (const Bytef *)data+i, (uInt)nn); ctx->crc_position += nn; } } ctx->position += (zip_uint64_t)n; return n; case ZIP_SOURCE_CLOSE: return 0; case ZIP_SOURCE_STAT: { zip_stat_t *st; st = (zip_stat_t *)data; if (ctx->crc_complete) { /* TODO: Set comp_size, comp_method, encryption_method? After all, this only works for uncompressed data. */ st->size = ctx->size; st->crc = ctx->crc; st->comp_size = ctx->size; st->comp_method = ZIP_CM_STORE; st->encryption_method = ZIP_EM_NONE; st->valid |= ZIP_STAT_SIZE|ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD;; } return 0; } case ZIP_SOURCE_ERROR: return zip_error_to_data(&ctx->error, data, len); case ZIP_SOURCE_FREE: free(ctx); return 0; case ZIP_SOURCE_SUPPORTS: { zip_int64_t mask = zip_source_supports(src); if (mask < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } return mask & ~zip_source_make_command_bitmap(ZIP_SOURCE_BEGIN_WRITE, ZIP_SOURCE_COMMIT_WRITE, ZIP_SOURCE_ROLLBACK_WRITE, ZIP_SOURCE_SEEK_WRITE, ZIP_SOURCE_TELL_WRITE, ZIP_SOURCE_REMOVE, -1); } case ZIP_SOURCE_SEEK: { zip_int64_t new_position; zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error); if (args == NULL) { return -1; } if (zip_source_seek(src, args->offset, args->whence) < 0 || (new_position = zip_source_tell(src)) < 0) { _zip_error_set_from_source(&ctx->error, src); return -1; } ctx->position = (zip_uint64_t)new_position; return 0; } case ZIP_SOURCE_TELL: return (zip_int64_t)ctx->position; default: zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0); return -1; } }