2 * Copyright 2003,2004 Colin Percival
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
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.
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.
45 # include <winsock2.h>
48 # include <arpa/inet.h>
56 # define SSIZE_MAX LONG_MAX
60 MBS_ReadHeader(int fd
, MBSPatchHeader
*header
)
62 int s
= read(fd
, header
, sizeof(MBSPatchHeader
));
63 if (s
!= sizeof(MBSPatchHeader
))
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
);
78 if (memcmp(header
->tag
, "MBDIFF10", 8) != 0)
79 return UNEXPECTED_ERROR
;
81 if (sizeof(MBSPatchHeader
) +
84 header
->extralen
!= int(hs
.st_size
))
85 return UNEXPECTED_ERROR
;
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
+
104 int r
= header
->cblen
+ header
->difflen
+ header
->extralen
;
105 unsigned char *wb
= buf
;
107 int c
= read(patchfd
, wb
, (r
> SSIZE_MAX
) ? SSIZE_MAX
: r
);
116 rv
= UNEXPECTED_ERROR
;
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
;
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"
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
;
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
) {
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
;
168 if ((int) write(filefd
, extrasrc
, ctrlsrc
->y
) != ctrlsrc
->y
) {
172 extrasrc
+= ctrlsrc
->y
;
174 /* "seek" forwards in oldfile by z bytes */
176 if (fbuffer
+ ctrlsrc
->z
> fbufend
) {
177 rv
= UNEXPECTED_ERROR
;
180 fbuffer
+= ctrlsrc
->z
;
182 /* and on to the next control block */
185 } while (ctrlsrc
< ctrlend
);
193 int CalculateCrc(const unsigned char *buf
, int size
) {
195 unsigned int crc
= 0xffffffffL
;
196 crc
= ~CrcCalc(buf
, size
);
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. */
212 int ApplyBinaryPatch(const wchar_t *old_file
, const wchar_t *patch_file
,
213 const wchar_t *new_file
) {
217 unsigned char *buf
= NULL
;
219 int pfd
= _wopen(patch_file
, O_RDONLY
| _O_BINARY
);
220 if (pfd
< 0) return READ_ERROR
;
223 MBSPatchHeader header
;
224 if ((ret
= MBS_ReadHeader(pfd
, &header
)))
227 ofd
= _wopen(old_file
, O_RDONLY
| _O_BINARY
);
234 if ((ret
= fstat(ofd
, &os
))) {
239 if (os
.st_size
!= header
.slen
) {
240 ret
= UNEXPECTED_ERROR
;
244 buf
= (unsigned char*) malloc(header
.slen
);
250 if (read(ofd
, buf
, header
.slen
) != header
.slen
) {
255 if (CalculateCrc(buf
, header
.slen
) != header
.scrc32
) {
260 nfd
= _wopen(new_file
, O_WRONLY
| O_TRUNC
| O_CREAT
| _O_BINARY
);
266 ret
= MBS_ApplyPatch(&header
, pfd
, buf
, nfd
);
271 if (ofd
>= 0) close(ofd
);
272 if (nfd
>= 0) close(nfd
);