blob: d33ceeaafe82a5aab489fc9d28374fba29e6f178 [file] [log] [blame]
initial.commit584cd5c2008-07-27 00:38:331/*-
2 * Copyright 2003,2004 Colin Percival
3 * All rights reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 *
26 * Changelog:
27 * 2005-04-26 - Define the header as a C structure, add a CRC32 checksum to
28 * the header, and make all the types 32-bit.
29 * --Benjamin Smedberg <[email protected]>
30 * 2007-11-14 - Added CalculateCrc() and ApplyBinaryPatch() methods.
31 * --Rahul Kuchhal
rickyzdf379102016-08-24 21:45:0632 * 2016-07-27 - Improve validation of diffs.
33 * --Ricky Zhou
initial.commit584cd5c2008-07-27 00:38:3334 */
35
36#include "mbspatch.h"
37
38#include <sys/stat.h>
rickyzdf379102016-08-24 21:45:0639#include <sys/types.h>
initial.commit584cd5c2008-07-27 00:38:3340#include <stdlib.h>
41#include <stdio.h>
42#include <fcntl.h>
43#include <string.h>
44#include <limits.h>
45
46#ifdef _WIN32
47# include <io.h>
48# include <winsock2.h>
49#else
50# include <unistd.h>
51# include <arpa/inet.h>
52#endif
53
54extern "C" {
55#include <7zCrc.h>
56}
57
58#ifndef SSIZE_MAX
59# define SSIZE_MAX LONG_MAX
60#endif
61
62int
63MBS_ReadHeader(int fd, MBSPatchHeader *header)
64{
65 int s = read(fd, header, sizeof(MBSPatchHeader));
66 if (s != sizeof(MBSPatchHeader))
67 return READ_ERROR;
68
69 header->slen = ntohl(header->slen);
70 header->scrc32 = ntohl(header->scrc32);
71 header->dlen = ntohl(header->dlen);
72 header->cblen = ntohl(header->cblen);
73 header->difflen = ntohl(header->difflen);
74 header->extralen = ntohl(header->extralen);
75
76 struct stat hs;
77 s = fstat(fd, &hs);
rickyzdf379102016-08-24 21:45:0678 if (s != 0)
initial.commit584cd5c2008-07-27 00:38:3379 return READ_ERROR;
80
81 if (memcmp(header->tag, "MBDIFF10", 8) != 0)
82 return UNEXPECTED_ERROR;
83
rickyzdf379102016-08-24 21:45:0684 if (hs.st_size > INT_MAX)
85 return UNEXPECTED_ERROR;
86
87 size_t size = static_cast<size_t>(hs.st_size);
88 if (size < sizeof(MBSPatchHeader))
89 return UNEXPECTED_ERROR;
90 size -= sizeof(MBSPatchHeader);
91
92 if (size < header->cblen)
93 return UNEXPECTED_ERROR;
94 size -= header->cblen;
95
96 if (size < header->difflen)
97 return UNEXPECTED_ERROR;
98 size -= header->difflen;
99
100 if (size < header->extralen)
101 return UNEXPECTED_ERROR;
102 size -= header->extralen;
103
104 if (size != 0)
initial.commit584cd5c2008-07-27 00:38:33105 return UNEXPECTED_ERROR;
106
107 return OK;
108}
[email protected]1525e612014-05-14 00:27:21109
initial.commit584cd5c2008-07-27 00:38:33110int
111MBS_ApplyPatch(const MBSPatchHeader *header, int patchfd,
112 unsigned char *fbuffer, int filefd)
113{
rickyzdf379102016-08-24 21:45:06114 unsigned char *fbufstart = fbuffer;
initial.commit584cd5c2008-07-27 00:38:33115 unsigned char *fbufend = fbuffer + header->slen;
116
117 unsigned char *buf = (unsigned char*) malloc(header->cblen +
118 header->difflen +
119 header->extralen);
120 if (!buf)
121 return MEM_ERROR;
122
123 int rv = OK;
124
125 int r = header->cblen + header->difflen + header->extralen;
126 unsigned char *wb = buf;
127 while (r) {
128 int c = read(patchfd, wb, (r > SSIZE_MAX) ? SSIZE_MAX : r);
129 if (c < 0) {
130 rv = READ_ERROR;
131 goto end;
132 }
133
134 r -= c;
rickyzdf379102016-08-24 21:45:06135 wb += c;
initial.commit584cd5c2008-07-27 00:38:33136
137 if (c == 0 && r) {
138 rv = UNEXPECTED_ERROR;
139 goto end;
140 }
141 }
142
143 {
144 MBSPatchTriple *ctrlsrc = (MBSPatchTriple*) buf;
rickyzdf379102016-08-24 21:45:06145 if (header->cblen % sizeof(MBSPatchTriple) != 0) {
146 rv = UNEXPECTED_ERROR;
147 goto end;
148 }
149
initial.commit584cd5c2008-07-27 00:38:33150 unsigned char *diffsrc = buf + header->cblen;
151 unsigned char *extrasrc = diffsrc + header->difflen;
152
153 MBSPatchTriple *ctrlend = (MBSPatchTriple*) diffsrc;
154 unsigned char *diffend = extrasrc;
155 unsigned char *extraend = extrasrc + header->extralen;
156
rickyzdf379102016-08-24 21:45:06157 while (ctrlsrc < ctrlend) {
initial.commit584cd5c2008-07-27 00:38:33158 ctrlsrc->x = ntohl(ctrlsrc->x);
159 ctrlsrc->y = ntohl(ctrlsrc->y);
160 ctrlsrc->z = ntohl(ctrlsrc->z);
161
162#ifdef DEBUG_bsmedberg
163 printf("Applying block:\n"
164 " x: %u\n"
165 " y: %u\n"
166 " z: %i\n",
167 ctrlsrc->x,
168 ctrlsrc->y,
169 ctrlsrc->z);
170#endif
171
172 /* Add x bytes from oldfile to x bytes from the diff block */
173
rickyzdf379102016-08-24 21:45:06174 if (ctrlsrc->x > static_cast<size_t>(fbufend - fbuffer) ||
175 ctrlsrc->x > static_cast<size_t>(diffend - diffsrc)) {
initial.commit584cd5c2008-07-27 00:38:33176 rv = UNEXPECTED_ERROR;
177 goto end;
178 }
179 for (unsigned int i = 0; i < ctrlsrc->x; ++i) {
180 diffsrc[i] += fbuffer[i];
181 }
182 if ((int) write(filefd, diffsrc, ctrlsrc->x) != ctrlsrc->x) {
183 rv = WRITE_ERROR;
184 goto end;
185 }
186 fbuffer += ctrlsrc->x;
187 diffsrc += ctrlsrc->x;
188
189 /* Copy y bytes from the extra block */
190
rickyzdf379102016-08-24 21:45:06191 if (ctrlsrc->y > static_cast<size_t>(extraend - extrasrc)) {
initial.commit584cd5c2008-07-27 00:38:33192 rv = UNEXPECTED_ERROR;
193 goto end;
194 }
195 if ((int) write(filefd, extrasrc, ctrlsrc->y) != ctrlsrc->y) {
196 rv = WRITE_ERROR;
197 goto end;
198 }
199 extrasrc += ctrlsrc->y;
200
201 /* "seek" forwards in oldfile by z bytes */
202
rickyzdf379102016-08-24 21:45:06203 if (ctrlsrc->z < fbufstart - fbuffer ||
204 ctrlsrc->z > fbufend - fbuffer) {
initial.commit584cd5c2008-07-27 00:38:33205 rv = UNEXPECTED_ERROR;
206 goto end;
207 }
208 fbuffer += ctrlsrc->z;
209
210 /* and on to the next control block */
211
212 ++ctrlsrc;
rickyzdf379102016-08-24 21:45:06213 }
initial.commit584cd5c2008-07-27 00:38:33214 }
215
216end:
217 free(buf);
218 return rv;
219}
220
221int CalculateCrc(const unsigned char *buf, int size) {
222 CrcGenerateTable();
223 unsigned int crc = 0xffffffffL;
224 crc = ~CrcCalc(buf, size);
225 return crc;
226}
227
[email protected]ad89a6d2008-07-29 00:21:11228/* _O_BINARY is a MSWindows open() mode flag. When absent, MSWindows
229 * open() translates CR+LF to LF; when present, it passes bytes
230 * through faithfully. Under *nix, we are always in binary mode, so
231 * the following #define turns this flag into a no-op w.r.t. bitwise
232 * OR. Note that this would be DANGEROUS AND UNSOUND if we used
233 * _O_BINARY other than as a bitwise OR mask (e.g., as a bitwise AND
234 * mask to check for binary mode), but it seems OK in the limited
235 * context of the following small function. */
236#ifndef _O_BINARY
237# define _O_BINARY 0
238#endif
239
[email protected]584fa1d2008-09-08 17:40:14240int ApplyBinaryPatch(const wchar_t *old_file, const wchar_t *patch_file,
241 const wchar_t *new_file) {
[email protected]793f23122013-07-31 15:48:52242 int ret = OK;
243 int ofd = -1;
244 int nfd = -1;
245 unsigned char *buf = NULL;
246
[email protected]584fa1d2008-09-08 17:40:14247 int pfd = _wopen(patch_file, O_RDONLY | _O_BINARY);
initial.commit584cd5c2008-07-27 00:38:33248 if (pfd < 0) return READ_ERROR;
249
[email protected]793f23122013-07-31 15:48:52250 do {
251 MBSPatchHeader header;
252 if ((ret = MBS_ReadHeader(pfd, &header)))
253 break;
initial.commit584cd5c2008-07-27 00:38:33254
[email protected]793f23122013-07-31 15:48:52255 ofd = _wopen(old_file, O_RDONLY | _O_BINARY);
256 if (ofd < 0) {
257 ret = READ_ERROR;
258 break;
259 }
initial.commit584cd5c2008-07-27 00:38:33260
[email protected]793f23122013-07-31 15:48:52261 struct stat os;
262 if ((ret = fstat(ofd, &os))) {
263 ret = READ_ERROR;
264 break;
265 }
initial.commit584cd5c2008-07-27 00:38:33266
[email protected]793f23122013-07-31 15:48:52267 if (os.st_size != header.slen) {
268 ret = UNEXPECTED_ERROR;
269 break;
270 }
initial.commit584cd5c2008-07-27 00:38:33271
[email protected]793f23122013-07-31 15:48:52272 buf = (unsigned char*) malloc(header.slen);
273 if (!buf) {
274 ret = MEM_ERROR;
275 break;
276 }
initial.commit584cd5c2008-07-27 00:38:33277
[email protected]793f23122013-07-31 15:48:52278 if (read(ofd, buf, header.slen) != header.slen) {
279 ret = READ_ERROR;
280 break;
281 }
initial.commit584cd5c2008-07-27 00:38:33282
[email protected]793f23122013-07-31 15:48:52283 if (CalculateCrc(buf, header.slen) != header.scrc32) {
284 ret = CRC_ERROR;
285 break;
286 }
287
288 nfd = _wopen(new_file, O_WRONLY | O_TRUNC | O_CREAT | _O_BINARY);
289 if (nfd < 0) {
290 ret = READ_ERROR;
291 break;
292 }
293
[email protected]1525e612014-05-14 00:27:21294 ret = MBS_ApplyPatch(&header, pfd, buf, nfd);
[email protected]793f23122013-07-31 15:48:52295 } while (0);
initial.commit584cd5c2008-07-27 00:38:33296
297 free(buf);
298 close(pfd);
[email protected]793f23122013-07-31 15:48:52299 if (ofd >= 0) close(ofd);
300 if (nfd >= 0) close(nfd);
301 return ret;
initial.commit584cd5c2008-07-27 00:38:33302}