blob: 01f526c647a732b3c69da23b0669a74c54eeee50 [file] [log] [blame]
Dieter Baron3291dac2009-03-12 15:56:36 +01001/*
Dieter Baronba98df02009-03-30 00:03:53 +02002 zip_source_crc.c -- pass-through source that calculates CRC32 and size
Thomas Klausner00ff6bb2016-01-08 08:21:22 +01003 Copyright (C) 2009-2016 Dieter Baron and Thomas Klausner
Dieter Baron3291dac2009-03-12 15:56:36 +01004
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
Dieter Baron3291dac2009-03-12 15:56:36 +010034
35#include <stdlib.h>
36#include <string.h>
Thomas Klausnerea8ba492014-09-23 16:54:47 +020037#include <limits.h>
Dieter Baron3291dac2009-03-12 15:56:36 +010038
39#include "zipint.h"
40
Thomas Klausnerea60f352013-03-19 11:08:32 +010041struct crc_context {
Thomas Klausnerdacdcce2015-12-29 20:18:48 +010042 int validate; /* whether to check CRC on EOF and return error on mismatch */
43 int crc_complete; /* whether CRC was computed for complete file */
Thomas Klausnerea8ba492014-09-23 16:54:47 +020044 zip_error_t error;
Dieter Baron3291dac2009-03-12 15:56:36 +010045 zip_uint64_t size;
Thomas Klausnerdacdcce2015-12-29 20:18:48 +010046 zip_uint64_t position; /* current reading position */
47 zip_uint64_t crc_position; /* how far we've computed the CRC */
Dieter Baron3291dac2009-03-12 15:56:36 +010048 zip_uint32_t crc;
49};
50
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020051static zip_int64_t crc_read(zip_source_t *, void *, void *, zip_uint64_t, zip_source_cmd_t);
Dieter Baron3291dac2009-03-12 15:56:36 +010052
Dieter Baron3291dac2009-03-12 15:56:36 +010053
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020054zip_source_t *
55zip_source_crc(zip_t *za, zip_source_t *src, int validate)
Dieter Baron3291dac2009-03-12 15:56:36 +010056{
Thomas Klausnerea60f352013-03-19 11:08:32 +010057 struct crc_context *ctx;
Dieter Baron3291dac2009-03-12 15:56:36 +010058
Dieter Baron2c4f9b72009-03-31 23:55:42 +020059 if (src == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +020060 zip_error_set(&za->error, ZIP_ER_INVAL, 0);
Dieter Baron3291dac2009-03-12 15:56:36 +010061 return NULL;
62 }
63
Thomas Klausnerea60f352013-03-19 11:08:32 +010064 if ((ctx=(struct crc_context *)malloc(sizeof(*ctx))) == NULL) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +020065 zip_error_set(&za->error, ZIP_ER_MEMORY, 0);
Dieter Baron3291dac2009-03-12 15:56:36 +010066 return NULL;
67 }
68
Thomas Klausnerea8ba492014-09-23 16:54:47 +020069 zip_error_init(&ctx->error);
Dieter Barondf3089b2015-07-12 11:14:22 +020070 ctx->validate = validate;
71 ctx->crc_complete = 0;
72 ctx->crc_position = 0;
73 ctx->crc = (zip_uint32_t)crc32(0, NULL, 0);
Dieter Baron362713b2013-04-27 12:23:38 +020074 ctx->size = 0;
Dieter Barondf3089b2015-07-12 11:14:22 +020075
Dieter Baronba98df02009-03-30 00:03:53 +020076 return zip_source_layered(za, src, crc_read, ctx);
Dieter Baron3291dac2009-03-12 15:56:36 +010077}
78
Dieter Baron3291dac2009-03-12 15:56:36 +010079
80static zip_int64_t
Dieter Baron1d9dfeb2014-09-28 23:02:54 +020081crc_read(zip_source_t *src, void *_ctx, void *data, zip_uint64_t len, zip_source_cmd_t cmd)
Dieter Baron3291dac2009-03-12 15:56:36 +010082{
Thomas Klausnerea60f352013-03-19 11:08:32 +010083 struct crc_context *ctx;
Dieter Baron3291dac2009-03-12 15:56:36 +010084 zip_int64_t n;
85
Thomas Klausnerea60f352013-03-19 11:08:32 +010086 ctx = (struct crc_context *)_ctx;
Dieter Baron3291dac2009-03-12 15:56:36 +010087
88 switch (cmd) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +020089 case ZIP_SOURCE_OPEN:
Dieter Barondf3089b2015-07-12 11:14:22 +020090 ctx->position = 0;
Thomas Klausnerea8ba492014-09-23 16:54:47 +020091 return 0;
92
93 case ZIP_SOURCE_READ:
Dieter Barondf3089b2015-07-12 11:14:22 +020094 if ((n = zip_source_read(src, data, len)) < 0) {
Thomas Klausnerd97f5442014-09-23 17:02:03 +020095 _zip_error_set_from_source(&ctx->error, src);
Thomas Klausnerea8ba492014-09-23 16:54:47 +020096 return -1;
97 }
98
99 if (n == 0) {
Dieter Barondf3089b2015-07-12 11:14:22 +0200100 if (ctx->crc_position == ctx->position) {
101 ctx->crc_complete = 1;
102 ctx->size = ctx->position;
103
104 if (ctx->validate) {
105 struct zip_stat st;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200106
Dieter Barondf3089b2015-07-12 11:14:22 +0200107 if (zip_source_stat(src, &st) < 0) {
108 _zip_error_set_from_source(&ctx->error, src);
109 return -1;
110 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200111
Dieter Barondf3089b2015-07-12 11:14:22 +0200112 if ((st.valid & ZIP_STAT_CRC) && st.crc != ctx->crc) {
113 zip_error_set(&ctx->error, ZIP_ER_CRC, 0);
114 return -1;
115 }
116 if ((st.valid & ZIP_STAT_SIZE) && st.size != ctx->size) {
117 zip_error_set(&ctx->error, ZIP_ER_INCONS, 0);
118 return -1;
119 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200120 }
121 }
122 }
Dieter Barondf3089b2015-07-12 11:14:22 +0200123 else if (!ctx->crc_complete && ctx->position <= ctx->crc_position) {
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200124 zip_uint64_t i, nn;
Dieter Baron301472c2009-03-12 16:09:09 +0100125
Dieter Barondf3089b2015-07-12 11:14:22 +0200126 for (i = ctx->crc_position - ctx->position; i < (zip_uint64_t)n; i += nn) {
Thomas Klausner03ca1c12014-09-24 01:02:15 +0200127 nn = ZIP_MIN(UINT_MAX, (zip_uint64_t)n-i);
Dieter Baron3291dac2009-03-12 15:56:36 +0100128
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200129 ctx->crc = (zip_uint32_t)crc32(ctx->crc, (const Bytef *)data+i, (uInt)nn);
Dieter Barondf3089b2015-07-12 11:14:22 +0200130 ctx->crc_position += nn;
Dieter Baronba98df02009-03-30 00:03:53 +0200131 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200132 }
Dieter Barondf3089b2015-07-12 11:14:22 +0200133 ctx->position += (zip_uint64_t)n;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200134 return n;
Dieter Baron3291dac2009-03-12 15:56:36 +0100135
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200136 case ZIP_SOURCE_CLOSE:
137 return 0;
Dieter Baron3291dac2009-03-12 15:56:36 +0100138
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200139 case ZIP_SOURCE_STAT:
140 {
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200141 zip_stat_t *st;
Dieter Baron3291dac2009-03-12 15:56:36 +0100142
Dieter Baron1d9dfeb2014-09-28 23:02:54 +0200143 st = (zip_stat_t *)data;
Dieter Baron3291dac2009-03-12 15:56:36 +0100144
Dieter Barondf3089b2015-07-12 11:14:22 +0200145 if (ctx->crc_complete) {
Thomas Klausnerb52bda02013-11-28 18:01:40 +0100146 /* TODO: Set comp_size, comp_method, encryption_method?
Dieter Baron35f2b682009-03-12 18:36:34 +0100147 After all, this only works for uncompressed data. */
Dieter Baron3291dac2009-03-12 15:56:36 +0100148 st->size = ctx->size;
149 st->crc = ctx->crc;
Dieter Baron3efab992012-05-04 09:29:29 +0200150 st->comp_size = ctx->size;
151 st->comp_method = ZIP_CM_STORE;
152 st->encryption_method = ZIP_EM_NONE;
153 st->valid |= ZIP_STAT_SIZE|ZIP_STAT_CRC|ZIP_STAT_COMP_SIZE|ZIP_STAT_COMP_METHOD|ZIP_STAT_ENCRYPTION_METHOD;;
Dieter Baron3291dac2009-03-12 15:56:36 +0100154 }
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200155 return 0;
156 }
157
158 case ZIP_SOURCE_ERROR:
159 return zip_error_to_data(&ctx->error, data, len);
Dieter Baron3291dac2009-03-12 15:56:36 +0100160
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200161 case ZIP_SOURCE_FREE:
162 free(ctx);
163 return 0;
164
165 case ZIP_SOURCE_SUPPORTS:
Dieter Barondf3089b2015-07-12 11:14:22 +0200166 {
167 zip_int64_t mask = zip_source_supports(src);
168
169 if (mask < 0) {
170 _zip_error_set_from_source(&ctx->error, src);
171 return -1;
172 }
173
174 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);
175 }
176
177 case ZIP_SOURCE_SEEK:
178 {
Dieter Barondf3089b2015-07-12 11:14:22 +0200179 zip_int64_t new_position;
Thomas Klausnerea69ac12016-01-05 14:49:33 +0100180 zip_source_args_seek_t *args = ZIP_SOURCE_GET_ARGS(zip_source_args_seek_t, data, len, &ctx->error);
Dieter Barondf3089b2015-07-12 11:14:22 +0200181
Thomas Klausnerea69ac12016-01-05 14:49:33 +0100182 if (args == NULL) {
183 return -1;
184 }
Dieter Barondf3089b2015-07-12 11:14:22 +0200185 if (zip_source_seek(src, args->offset, args->whence) < 0 || (new_position = zip_source_tell(src)) < 0) {
186 _zip_error_set_from_source(&ctx->error, src);
187 return -1;
188 }
189
190 ctx->position = (zip_uint64_t)new_position;
191
192 return 0;
193 }
194
195 case ZIP_SOURCE_TELL:
196 return (zip_int64_t)ctx->position;
Thomas Klausnerea8ba492014-09-23 16:54:47 +0200197
198 default:
199 zip_error_set(&ctx->error, ZIP_ER_OPNOTSUPP, 0);
200 return -1;
Dieter Baron3291dac2009-03-12 15:56:36 +0100201 }
Dieter Baron3291dac2009-03-12 15:56:36 +0100202}