Adding Peter Thatcher to the owners file.
[chromium-blink-merge.git] / third_party / bspatch / mbspatch.cc
blobd00bc99d1297b4cc9bd032f2831f4267b44c7064
1 /*-
2 * Copyright 2003,2004 Colin Percival
3 * All rights reserved
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.
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.
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 <benjamin@smedbergs.us>
30 * 2007-11-14 - Added CalculateCrc() and ApplyBinaryPatch() methods.
31 * --Rahul Kuchhal
34 #include "mbspatch.h"
36 #include <sys/stat.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <fcntl.h>
40 #include <string.h>
41 #include <limits.h>
43 #ifdef _WIN32
44 # include <io.h>
45 # include <winsock2.h>
46 #else
47 # include <unistd.h>
48 # include <arpa/inet.h>
49 #endif
51 extern "C" {
52 #include <7zCrc.h>
55 #ifndef SSIZE_MAX
56 # define SSIZE_MAX LONG_MAX
57 #endif
59 int
60 MBS_ReadHeader(int fd, MBSPatchHeader *header)
62 int s = read(fd, header, sizeof(MBSPatchHeader));
63 if (s != sizeof(MBSPatchHeader))
64 return READ_ERROR;
66 header->slen = ntohl(header->slen);
67 header->scrc32 = ntohl(header->scrc32);
68 header->dlen = ntohl(header->dlen);
69 header->cblen = ntohl(header->cblen);
70 header->difflen = ntohl(header->difflen);
71 header->extralen = ntohl(header->extralen);
73 struct stat hs;
74 s = fstat(fd, &hs);
75 if (s)
76 return READ_ERROR;
78 if (memcmp(header->tag, "MBDIFF10", 8) != 0)
79 return UNEXPECTED_ERROR;
81 if (sizeof(MBSPatchHeader) +
82 header->cblen +
83 header->difflen +
84 header->extralen != int(hs.st_size))
85 return UNEXPECTED_ERROR;
87 return OK;
90 int
91 MBS_ApplyPatch(const MBSPatchHeader *header, int patchfd,
92 unsigned char *fbuffer, int filefd)
94 unsigned char *fbufend = fbuffer + header->slen;
96 unsigned char *buf = (unsigned char*) malloc(header->cblen +
97 header->difflen +
98 header->extralen);
99 if (!buf)
100 return MEM_ERROR;
102 int rv = OK;
104 int r = header->cblen + header->difflen + header->extralen;
105 unsigned char *wb = buf;
106 while (r) {
107 int c = read(patchfd, wb, (r > SSIZE_MAX) ? SSIZE_MAX : r);
108 if (c < 0) {
109 rv = READ_ERROR;
110 goto end;
113 r -= c;
115 if (c == 0 && r) {
116 rv = UNEXPECTED_ERROR;
117 goto end;
122 MBSPatchTriple *ctrlsrc = (MBSPatchTriple*) buf;
123 unsigned char *diffsrc = buf + header->cblen;
124 unsigned char *extrasrc = diffsrc + header->difflen;
126 MBSPatchTriple *ctrlend = (MBSPatchTriple*) diffsrc;
127 unsigned char *diffend = extrasrc;
128 unsigned char *extraend = extrasrc + header->extralen;
130 do {
131 ctrlsrc->x = ntohl(ctrlsrc->x);
132 ctrlsrc->y = ntohl(ctrlsrc->y);
133 ctrlsrc->z = ntohl(ctrlsrc->z);
135 #ifdef DEBUG_bsmedberg
136 printf("Applying block:\n"
137 " x: %u\n"
138 " y: %u\n"
139 " z: %i\n",
140 ctrlsrc->x,
141 ctrlsrc->y,
142 ctrlsrc->z);
143 #endif
145 /* Add x bytes from oldfile to x bytes from the diff block */
147 if (fbuffer + ctrlsrc->x > fbufend ||
148 diffsrc + ctrlsrc->x > diffend) {
149 rv = UNEXPECTED_ERROR;
150 goto end;
152 for (unsigned int i = 0; i < ctrlsrc->x; ++i) {
153 diffsrc[i] += fbuffer[i];
155 if ((int) write(filefd, diffsrc, ctrlsrc->x) != ctrlsrc->x) {
156 rv = WRITE_ERROR;
157 goto end;
159 fbuffer += ctrlsrc->x;
160 diffsrc += ctrlsrc->x;
162 /* Copy y bytes from the extra block */
164 if (extrasrc + ctrlsrc->y > extraend) {
165 rv = UNEXPECTED_ERROR;
166 goto end;
168 if ((int) write(filefd, extrasrc, ctrlsrc->y) != ctrlsrc->y) {
169 rv = WRITE_ERROR;
170 goto end;
172 extrasrc += ctrlsrc->y;
174 /* "seek" forwards in oldfile by z bytes */
176 if (fbuffer + ctrlsrc->z > fbufend) {
177 rv = UNEXPECTED_ERROR;
178 goto end;
180 fbuffer += ctrlsrc->z;
182 /* and on to the next control block */
184 ++ctrlsrc;
185 } while (ctrlsrc < ctrlend);
188 end:
189 free(buf);
190 return rv;
193 int CalculateCrc(const unsigned char *buf, int size) {
194 CrcGenerateTable();
195 unsigned int crc = 0xffffffffL;
196 crc = ~CrcCalc(buf, size);
197 return crc;
200 /* _O_BINARY is a MSWindows open() mode flag. When absent, MSWindows
201 * open() translates CR+LF to LF; when present, it passes bytes
202 * through faithfully. Under *nix, we are always in binary mode, so
203 * the following #define turns this flag into a no-op w.r.t. bitwise
204 * OR. Note that this would be DANGEROUS AND UNSOUND if we used
205 * _O_BINARY other than as a bitwise OR mask (e.g., as a bitwise AND
206 * mask to check for binary mode), but it seems OK in the limited
207 * context of the following small function. */
208 #ifndef _O_BINARY
209 # define _O_BINARY 0
210 #endif
212 int ApplyBinaryPatch(const wchar_t *old_file, const wchar_t *patch_file,
213 const wchar_t *new_file) {
214 int ret = OK;
215 int ofd = -1;
216 int nfd = -1;
217 unsigned char *buf = NULL;
219 int pfd = _wopen(patch_file, O_RDONLY | _O_BINARY);
220 if (pfd < 0) return READ_ERROR;
222 do {
223 MBSPatchHeader header;
224 if ((ret = MBS_ReadHeader(pfd, &header)))
225 break;
227 ofd = _wopen(old_file, O_RDONLY | _O_BINARY);
228 if (ofd < 0) {
229 ret = READ_ERROR;
230 break;
233 struct stat os;
234 if ((ret = fstat(ofd, &os))) {
235 ret = READ_ERROR;
236 break;
239 if (os.st_size != header.slen) {
240 ret = UNEXPECTED_ERROR;
241 break;
244 buf = (unsigned char*) malloc(header.slen);
245 if (!buf) {
246 ret = MEM_ERROR;
247 break;
250 if (read(ofd, buf, header.slen) != header.slen) {
251 ret = READ_ERROR;
252 break;
255 if (CalculateCrc(buf, header.slen) != header.scrc32) {
256 ret = CRC_ERROR;
257 break;
260 nfd = _wopen(new_file, O_WRONLY | O_TRUNC | O_CREAT | _O_BINARY);
261 if (nfd < 0) {
262 ret = READ_ERROR;
263 break;
266 ret = MBS_ApplyPatch(&header, pfd, buf, nfd);
267 } while (0);
269 free(buf);
270 close(pfd);
271 if (ofd >= 0) close(ofd);
272 if (nfd >= 0) close(nfd);
273 return ret;