blob: 3dfd59fa3f2c5ca49a0e306bea3d220b8e968209 [file] [log] [blame]
The Android Open Source Projectc285fea2009-03-03 19:29:20 -08001/*-
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#if 0
28__FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:06 cperciva Exp $");
29#endif
30
Alex Deymob870eb52015-10-14 21:39:04 -070031#include "bspatch.h"
32
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080033#include <bzlib.h>
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080034#include <err.h>
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080035#include <fcntl.h>
Gilad Arnold99b53742013-04-30 09:24:14 -070036#include <inttypes.h>
Gilad Arnold99b53742013-04-30 09:24:14 -070037#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
Alex Deymob870eb52015-10-14 21:39:04 -070040#include <sys/types.h>
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080041
Alex Deymo437b7af2015-10-14 20:13:58 -070042#include <algorithm>
43#include <memory>
44#include <limits>
45
Gilad Arnold99b53742013-04-30 09:24:14 -070046#include "extents.h"
Alex Deymo437b7af2015-10-14 20:13:58 -070047#include "extents_file.h"
48#include "file.h"
49#include "file_interface.h"
Zdenek Behan339e0ee2010-06-14 12:50:53 -070050
Alex Deymo20891f92015-10-12 17:28:04 -070051namespace {
Zdenek Behan339e0ee2010-06-14 12:50:53 -070052
Alex Deymo437b7af2015-10-14 20:13:58 -070053int64_t ParseInt64(u_char* buf) {
54 int64_t y;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080055
Alex Deymob870eb52015-10-14 21:39:04 -070056 y = buf[7] & 0x7F;
57 y = y * 256;
58 y += buf[6];
59 y = y * 256;
60 y += buf[5];
61 y = y * 256;
62 y += buf[4];
63 y = y * 256;
64 y += buf[3];
65 y = y * 256;
66 y += buf[2];
67 y = y * 256;
68 y += buf[1];
69 y = y * 256;
70 y += buf[0];
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080071
Alex Deymob870eb52015-10-14 21:39:04 -070072 if (buf[7] & 0x80)
73 y = -y;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080074
Alex Deymob870eb52015-10-14 21:39:04 -070075 return y;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080076}
77
Alex Deymo20891f92015-10-12 17:28:04 -070078} // namespace
79
80namespace bsdiff {
81
Alex Deymoa5cff222015-04-08 14:10:30 -070082int bspatch(
83 const char* old_filename, const char* new_filename,
84 const char* patch_filename,
85 const char* old_extents, const char* new_extents) {
Alex Deymob870eb52015-10-14 21:39:04 -070086 FILE* f, *cpf, *dpf, *epf;
87 BZFILE* cpfbz2, *dpfbz2, *epfbz2;
88 int cbz2err, dbz2err, ebz2err;
Alex Deymob870eb52015-10-14 21:39:04 -070089 ssize_t bzctrllen, bzdatalen;
90 u_char header[32], buf[8];
91 u_char* new_buf;
Alex Deymob870eb52015-10-14 21:39:04 -070092 off_t ctrl[3];
93 off_t lenread;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080094
Alex Deymob870eb52015-10-14 21:39:04 -070095 int using_extents = (old_extents != NULL || new_extents != NULL);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080096
Alex Deymob870eb52015-10-14 21:39:04 -070097 // Open patch file.
98 if ((f = fopen(patch_filename, "r")) == NULL)
99 err(1, "fopen(%s)", patch_filename);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800100
Alex Deymob870eb52015-10-14 21:39:04 -0700101 // File format:
102 // 0 8 "BSDIFF40"
103 // 8 8 X
104 // 16 8 Y
105 // 24 8 sizeof(new_filename)
106 // 32 X bzip2(control block)
107 // 32+X Y bzip2(diff block)
108 // 32+X+Y ??? bzip2(extra block)
109 // with control block a set of triples (x,y,z) meaning "add x bytes
110 // from oldfile to x bytes from the diff block; copy y bytes from the
111 // extra block; seek forwards in oldfile by z bytes".
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800112
Alex Deymob870eb52015-10-14 21:39:04 -0700113 // Read header.
114 if (fread(header, 1, 32, f) < 32) {
115 if (feof(f))
116 errx(1, "Corrupt patch\n");
117 err(1, "fread(%s)", patch_filename);
118 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800119
Alex Deymob870eb52015-10-14 21:39:04 -0700120 // Check for appropriate magic.
121 if (memcmp(header, "BSDIFF40", 8) != 0)
122 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800123
Alex Deymob870eb52015-10-14 21:39:04 -0700124 // Read lengths from header.
Alex Deymo437b7af2015-10-14 20:13:58 -0700125 uint64_t oldsize, newsize;
126 bzctrllen = ParseInt64(header + 8);
127 bzdatalen = ParseInt64(header + 16);
128 int64_t signed_newsize = ParseInt64(header + 24);
129 newsize = signed_newsize;
130 if ((bzctrllen < 0) || (bzdatalen < 0) || (signed_newsize < 0))
Alex Deymob870eb52015-10-14 21:39:04 -0700131 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800132
Alex Deymob870eb52015-10-14 21:39:04 -0700133 // Close patch file and re-open it via libbzip2 at the right places.
134 if (fclose(f))
135 err(1, "fclose(%s)", patch_filename);
136 if ((cpf = fopen(patch_filename, "r")) == NULL)
137 err(1, "fopen(%s)", patch_filename);
138 if (fseek(cpf, 32, SEEK_SET))
139 err(1, "fseeko(%s, %lld)", patch_filename, (long long)32);
140 if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL)
141 errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err);
142 if ((dpf = fopen(patch_filename, "r")) == NULL)
143 err(1, "fopen(%s)", patch_filename);
144 if (fseek(dpf, 32 + bzctrllen, SEEK_SET))
145 err(1, "fseeko(%s, %lld)", patch_filename, (long long)(32 + bzctrllen));
146 if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL)
147 errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err);
148 if ((epf = fopen(patch_filename, "r")) == NULL)
149 err(1, "fopen(%s)", patch_filename);
150 if (fseek(epf, 32 + bzctrllen + bzdatalen, SEEK_SET))
151 err(1, "fseeko(%s, %lld)", patch_filename,
152 (long long)(32 + bzctrllen + bzdatalen));
153 if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL)
154 errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800155
Alex Deymob870eb52015-10-14 21:39:04 -0700156 // Open input file for reading.
Alex Deymo437b7af2015-10-14 20:13:58 -0700157 std::unique_ptr<FileInterface> old_file = File::FOpen(old_filename, O_RDONLY);
158 if (!old_file)
159 err(1, "Error opening the old filename");
160
Alex Deymob870eb52015-10-14 21:39:04 -0700161 if (using_extents) {
Alex Deymo437b7af2015-10-14 20:13:58 -0700162 std::vector<ex_t> parsed_old_extents;
163 if (!ParseExtentStr(old_extents, &parsed_old_extents))
164 errx(1, "Error parsing the old extents");
165 old_file.reset(new ExtentsFile(std::move(old_file), parsed_old_extents));
166 }
167
168 if (!old_file->GetSize(&oldsize))
Alex Deymob870eb52015-10-14 21:39:04 -0700169 err(1, "cannot obtain the size of %s", old_filename);
Alex Deymo437b7af2015-10-14 20:13:58 -0700170 uint64_t old_file_pos = 0;
Gilad Arnold99b53742013-04-30 09:24:14 -0700171
Alex Deymob870eb52015-10-14 21:39:04 -0700172 if ((new_buf = static_cast<u_char*>(malloc(newsize + 1))) == NULL)
173 err(1, NULL);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800174
Alex Deymo437b7af2015-10-14 20:13:58 -0700175 // The oldpos can be negative, but the new pos is only incremented linearly.
176 int64_t oldpos = 0;
177 uint64_t newpos = 0;
Alex Deymob870eb52015-10-14 21:39:04 -0700178 while (newpos < newsize) {
Alex Deymo437b7af2015-10-14 20:13:58 -0700179 int64_t i, j;
Alex Deymob870eb52015-10-14 21:39:04 -0700180 // Read control data.
181 for (i = 0; i <= 2; i++) {
182 lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
183 if ((lenread < 8) || ((cbz2err != BZ_OK) && (cbz2err != BZ_STREAM_END)))
184 errx(1, "Corrupt patch\n");
Alex Deymo437b7af2015-10-14 20:13:58 -0700185 ctrl[i] = ParseInt64(buf);
Alex Deymob870eb52015-10-14 21:39:04 -0700186 };
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800187
Alex Deymob870eb52015-10-14 21:39:04 -0700188 // Sanity-check.
189 if (ctrl[0] < 0 || ctrl[1] < 0)
190 errx(1, "Corrupt patch\n");
Doug Zongker4d054792014-05-13 08:37:06 -0700191
Alex Deymob870eb52015-10-14 21:39:04 -0700192 // Sanity-check.
193 if (newpos + ctrl[0] > newsize)
194 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800195
Alex Deymob870eb52015-10-14 21:39:04 -0700196 // Read diff string.
197 lenread = BZ2_bzRead(&dbz2err, dpfbz2, new_buf + newpos, ctrl[0]);
198 if ((lenread < ctrl[0]) ||
199 ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
200 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800201
Alex Deymob870eb52015-10-14 21:39:04 -0700202 // Add old data to diff string. It is enough to fseek once, at
203 // the beginning of the sequence, to avoid unnecessary overhead.
204 j = newpos;
205 if ((i = oldpos) < 0) {
206 j -= i;
207 i = 0;
208 }
Alex Deymo437b7af2015-10-14 20:13:58 -0700209 // We just checked that |i| is not negative.
210 if (static_cast<uint64_t>(i) != old_file_pos && !old_file->Seek(i))
211 err(1, "error seeking input file to offset %" PRId64, i);
Alex Deymob870eb52015-10-14 21:39:04 -0700212 if ((old_file_pos = oldpos + ctrl[0]) > oldsize)
213 old_file_pos = oldsize;
Alex Deymo437b7af2015-10-14 20:13:58 -0700214
215 uint64_t chunk_size = old_file_pos - i;
216 while (chunk_size > 0) {
217 size_t read_bytes;
218 size_t bytes_to_read = std::min(
219 chunk_size,
220 static_cast<uint64_t>(std::numeric_limits<size_t>::max()));
221 if (!old_file->Read(new_buf + j, bytes_to_read, &read_bytes)) {
Alex Deymob870eb52015-10-14 21:39:04 -0700222 err(1, "error reading from input file");
Alex Deymo437b7af2015-10-14 20:13:58 -0700223 }
224 if (!read_bytes)
225 errx(1, "EOF reached while reading from input file");
226 j += read_bytes;
227 chunk_size -= read_bytes;
Alex Deymob870eb52015-10-14 21:39:04 -0700228 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800229
Alex Deymob870eb52015-10-14 21:39:04 -0700230 // Adjust pointers.
231 newpos += ctrl[0];
232 oldpos += ctrl[0];
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800233
Alex Deymob870eb52015-10-14 21:39:04 -0700234 // Sanity-check.
235 if (newpos + ctrl[1] > newsize)
236 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800237
Alex Deymob870eb52015-10-14 21:39:04 -0700238 // Read extra string.
239 lenread = BZ2_bzRead(&ebz2err, epfbz2, new_buf + newpos, ctrl[1]);
240 if ((lenread < ctrl[1]) ||
241 ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
242 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800243
Alex Deymob870eb52015-10-14 21:39:04 -0700244 // Adjust pointers.
245 newpos += ctrl[1];
246 oldpos += ctrl[2];
247 };
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800248
Alex Deymob870eb52015-10-14 21:39:04 -0700249 // Close input file.
Alex Deymo437b7af2015-10-14 20:13:58 -0700250 old_file->Close();
Gilad Arnold99b53742013-04-30 09:24:14 -0700251
Alex Deymob870eb52015-10-14 21:39:04 -0700252 // Clean up the bzip2 reads.
253 BZ2_bzReadClose(&cbz2err, cpfbz2);
254 BZ2_bzReadClose(&dbz2err, dpfbz2);
255 BZ2_bzReadClose(&ebz2err, epfbz2);
256 if (fclose(cpf) || fclose(dpf) || fclose(epf))
257 err(1, "fclose(%s)", patch_filename);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800258
Alex Deymob870eb52015-10-14 21:39:04 -0700259 // Write the new file.
Alex Deymo437b7af2015-10-14 20:13:58 -0700260 std::unique_ptr<FileInterface> new_file =
261 File::FOpen(new_filename, O_CREAT | O_WRONLY);
262 if (!new_file)
263 err(1, "Error opening the new filename %s", new_filename);
264
Alex Deymob870eb52015-10-14 21:39:04 -0700265 if (using_extents) {
Alex Deymo437b7af2015-10-14 20:13:58 -0700266 std::vector<ex_t> parsed_new_extents;
267 if (!ParseExtentStr(new_extents, &parsed_new_extents))
268 errx(1, "Error parsing the new extents");
269 new_file.reset(new ExtentsFile(std::move(new_file), parsed_new_extents));
270 }
271
272 while (newsize > 0) {
273 size_t bytes_written;
274 if (!new_file->Write(new_buf, newsize, &bytes_written))
275 err(1, "Error writing new file %s", new_filename);
276 newsize -= bytes_written;
277 new_buf += bytes_written;
278 }
279
280 if (!new_file->Close())
281 err(1, "Error closing new file %s", new_filename);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800282
Alex Deymob870eb52015-10-14 21:39:04 -0700283 free(new_buf);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800284
Alex Deymob870eb52015-10-14 21:39:04 -0700285 return 0;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800286}
Alex Deymo20891f92015-10-12 17:28:04 -0700287
288} // namespace bsdiff