diff options
Diffstat (limited to 'rbutil/bspatch/bspatch.c')
-rw-r--r-- | rbutil/bspatch/bspatch.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/rbutil/bspatch/bspatch.c b/rbutil/bspatch/bspatch.c new file mode 100644 index 0000000000..aab4c1dc6f --- /dev/null +++ b/rbutil/bspatch/bspatch.c | |||
@@ -0,0 +1,217 @@ | |||
1 | /*- | ||
2 | * Copyright 2003-2005 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 | |||
27 | #ifdef WIN32 | ||
28 | #include <io.h> | ||
29 | #else | ||
30 | #include <stdarg.h> | ||
31 | #endif | ||
32 | #include "../bzip2/bzlib.h" | ||
33 | #include <stdlib.h> | ||
34 | #include <stdio.h> | ||
35 | #include <string.h> | ||
36 | #include <fcntl.h> | ||
37 | |||
38 | #define errx err | ||
39 | void err(int exitcode, const char * fmt, ...) | ||
40 | { | ||
41 | va_list valist; | ||
42 | va_start(valist, fmt); | ||
43 | vprintf(fmt, valist); | ||
44 | va_end(valist); | ||
45 | exit(exitcode); | ||
46 | } | ||
47 | |||
48 | static long offtin(u_char *buf) | ||
49 | { | ||
50 | long y; | ||
51 | |||
52 | y = buf[7] & 0x7F; | ||
53 | y = y * 256;y += buf[6]; | ||
54 | y = y * 256;y += buf[5]; | ||
55 | y = y * 256;y += buf[4]; | ||
56 | y = y * 256;y += buf[3]; | ||
57 | y = y * 256;y += buf[2]; | ||
58 | y = y * 256;y += buf[1]; | ||
59 | y = y * 256;y += buf[0]; | ||
60 | |||
61 | if (buf[7] & 0x80) y = -y; | ||
62 | |||
63 | return y; | ||
64 | } | ||
65 | |||
66 | int apply_bspatch(const char *infile, const char *outfile, const char *patchfile) | ||
67 | { | ||
68 | FILE * f, *cpf, *dpf, *epf; | ||
69 | BZFILE * cpfbz2, *dpfbz2, *epfbz2; | ||
70 | int cbz2err, dbz2err, ebz2err; | ||
71 | FILE * fs; | ||
72 | long oldsize, newsize; | ||
73 | long bzctrllen, bzdatalen; | ||
74 | u_char header[32], buf[8]; | ||
75 | u_char *pold, *pnew; | ||
76 | long oldpos, newpos; | ||
77 | long ctrl[3]; | ||
78 | long lenread; | ||
79 | long i; | ||
80 | |||
81 | /* Open patch file */ | ||
82 | if ((f = fopen(patchfile, "r")) == NULL) | ||
83 | err(1, "fopen(%s)", patchfile); | ||
84 | |||
85 | /* | ||
86 | File format: | ||
87 | 0 8 "BSDIFF40" | ||
88 | 8 8 X | ||
89 | 16 8 Y | ||
90 | 24 8 sizeof(newfile) | ||
91 | 32 X bzip2(control block) | ||
92 | 32+X Y bzip2(diff block) | ||
93 | 32+X+Y ??? bzip2(extra block) | ||
94 | with control block a set of triples (x,y,z) meaning "add x bytes | ||
95 | from oldfile to x bytes from the diff block; copy y bytes from the | ||
96 | extra block; seek forwards in oldfile by z bytes". | ||
97 | */ | ||
98 | |||
99 | /* Read header */ | ||
100 | if (fread(header, 1, 32, f) < 32) { | ||
101 | if (feof(f)) | ||
102 | errx(1, "Corrupt patch\n"); | ||
103 | err(1, "fread(%s)", patchfile); | ||
104 | } | ||
105 | |||
106 | /* Check for appropriate magic */ | ||
107 | if (memcmp(header, "BSDIFF40", 8) != 0) | ||
108 | errx(1, "Corrupt patch\n"); | ||
109 | |||
110 | /* Read lengths from header */ | ||
111 | bzctrllen = offtin(header + 8); | ||
112 | bzdatalen = offtin(header + 16); | ||
113 | newsize = offtin(header + 24); | ||
114 | if ((bzctrllen < 0) || (bzdatalen < 0) || (newsize < 0)) | ||
115 | errx(1, "Corrupt patch\n"); | ||
116 | |||
117 | /* Close patch file and re-open it via libbzip2 at the right places */ | ||
118 | if (fclose(f)) | ||
119 | err(1, "fclose(%s)", patchfile); | ||
120 | if ((cpf = fopen(patchfile, "rb")) == NULL) | ||
121 | err(1, "fopen(%s)", patchfile); | ||
122 | if (fseek(cpf, 32, SEEK_SET)) | ||
123 | err(1, "fseeko(%s, %lld)", patchfile, | ||
124 | (long long)32); | ||
125 | if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL) | ||
126 | errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err); | ||
127 | if ((dpf = fopen(patchfile, "rb")) == NULL) | ||
128 | err(1, "fopen(%s)", patchfile); | ||
129 | if (fseek(dpf, 32 + bzctrllen, SEEK_SET)) | ||
130 | err(1, "fseeko(%s, %lld)", patchfile, | ||
131 | (long long)(32 + bzctrllen)); | ||
132 | if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL) | ||
133 | errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err); | ||
134 | if ((epf = fopen(patchfile, "rb")) == NULL) | ||
135 | err(1, "fopen(%s)", patchfile); | ||
136 | if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET)) | ||
137 | err(1, "fseeko(%s, %lld)", patchfile, | ||
138 | (long long)(32 + bzctrllen + bzdatalen)); | ||
139 | if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL) | ||
140 | errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err); | ||
141 | |||
142 | fs = fopen(infile, "rb"); | ||
143 | if (fs == NULL)err(1, "Open failed :%s", infile); | ||
144 | if (fseek(fs, 0, SEEK_END) != 0)err(1, "Seek failed :%s", infile); | ||
145 | oldsize = ftell(fs); | ||
146 | pold = (u_char *)malloc(oldsize + 1); | ||
147 | if (pold == NULL) err(1, "Malloc failed :%s", infile); | ||
148 | fseek(fs, 0, SEEK_SET); | ||
149 | if (fread(pold, 1, oldsize, fs) == -1) err(1, "Read failed :%s", infile); | ||
150 | if (fclose(fs) == -1) err(1, "Close failed :%s", infile); | ||
151 | |||
152 | pnew = malloc(newsize + 1); | ||
153 | if (pnew == NULL)err(1, NULL); | ||
154 | |||
155 | oldpos = 0;newpos = 0; | ||
156 | while (newpos < newsize) { | ||
157 | /* Read control data */ | ||
158 | for (i = 0;i <= 2;i++) { | ||
159 | lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8); | ||
160 | if ((lenread < 8) || ((cbz2err != BZ_OK) && | ||
161 | (cbz2err != BZ_STREAM_END))) | ||
162 | errx(1, "Corrupt patch\n"); | ||
163 | ctrl[i] = offtin(buf); | ||
164 | }; | ||
165 | |||
166 | /* Sanity-check */ | ||
167 | if (newpos + ctrl[0] > newsize) | ||
168 | errx(1, "Corrupt patch\n"); | ||
169 | |||
170 | /* Read diff string */ | ||
171 | lenread = BZ2_bzRead(&dbz2err, dpfbz2, pnew + newpos, ctrl[0]); | ||
172 | if ((lenread < ctrl[0]) || | ||
173 | ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) | ||
174 | errx(1, "Corrupt patch\n"); | ||
175 | |||
176 | /* Add pold data to diff string */ | ||
177 | for (i = 0;i < ctrl[0];i++) | ||
178 | if ((oldpos + i >= 0) && (oldpos + i < oldsize)) | ||
179 | pnew[newpos + i] += pold[oldpos + i]; | ||
180 | |||
181 | /* Adjust pointers */ | ||
182 | newpos += ctrl[0]; | ||
183 | oldpos += ctrl[0]; | ||
184 | |||
185 | /* Sanity-check */ | ||
186 | if (newpos + ctrl[1] > newsize) | ||
187 | errx(1, "Corrupt patch\n"); | ||
188 | |||
189 | /* Read extra string */ | ||
190 | lenread = BZ2_bzRead(&ebz2err, epfbz2, pnew + newpos, ctrl[1]); | ||
191 | if ((lenread < ctrl[1]) || | ||
192 | ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) | ||
193 | errx(1, "Corrupt patch\n"); | ||
194 | |||
195 | /* Adjust pointers */ | ||
196 | newpos += ctrl[1]; | ||
197 | oldpos += ctrl[2]; | ||
198 | }; | ||
199 | |||
200 | /* Clean up the bzip2 reads */ | ||
201 | BZ2_bzReadClose(&cbz2err, cpfbz2); | ||
202 | BZ2_bzReadClose(&dbz2err, dpfbz2); | ||
203 | BZ2_bzReadClose(&ebz2err, epfbz2); | ||
204 | if (fclose(cpf) || fclose(dpf) || fclose(epf)) | ||
205 | err(1, "fclose(%s)", patchfile); | ||
206 | |||
207 | /* Write the pnew file */ | ||
208 | fs = fopen(outfile, "wb"); | ||
209 | if (fs == NULL)err(1, "Create failed :%s", outfile); | ||
210 | if (fwrite(pnew, 1, newsize, fs) == -1)err(1, "Write failed :%s", outfile); | ||
211 | if (fclose(fs) == -1)err(1, "Close failed :%s", outfile); | ||
212 | |||
213 | free(pnew); | ||
214 | free(pold); | ||
215 | |||
216 | return 0; | ||
217 | } | ||