blob: aa484cd27ae6db0b431fe8061c5ce1ce2173ed5e [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;
Sen Jiangd87c8352015-11-20 16:14:36 -0800178 std::vector<u_char> old_buf(1024 * 1024);
Alex Deymob870eb52015-10-14 21:39:04 -0700179 while (newpos < newsize) {
Alex Deymo437b7af2015-10-14 20:13:58 -0700180 int64_t i, j;
Alex Deymob870eb52015-10-14 21:39:04 -0700181 // Read control data.
182 for (i = 0; i <= 2; i++) {
183 lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8);
184 if ((lenread < 8) || ((cbz2err != BZ_OK) && (cbz2err != BZ_STREAM_END)))
185 errx(1, "Corrupt patch\n");
Alex Deymo437b7af2015-10-14 20:13:58 -0700186 ctrl[i] = ParseInt64(buf);
Alex Deymob870eb52015-10-14 21:39:04 -0700187 };
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800188
Alex Deymob870eb52015-10-14 21:39:04 -0700189 // Sanity-check.
190 if (ctrl[0] < 0 || ctrl[1] < 0)
191 errx(1, "Corrupt patch\n");
Doug Zongker4d054792014-05-13 08:37:06 -0700192
Alex Deymob870eb52015-10-14 21:39:04 -0700193 // Sanity-check.
194 if (newpos + ctrl[0] > newsize)
195 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800196
Alex Deymob870eb52015-10-14 21:39:04 -0700197 // Read diff string.
198 lenread = BZ2_bzRead(&dbz2err, dpfbz2, new_buf + newpos, ctrl[0]);
199 if ((lenread < ctrl[0]) ||
200 ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END)))
201 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800202
Alex Deymob870eb52015-10-14 21:39:04 -0700203 // Add old data to diff string. It is enough to fseek once, at
204 // the beginning of the sequence, to avoid unnecessary overhead.
205 j = newpos;
206 if ((i = oldpos) < 0) {
207 j -= i;
208 i = 0;
209 }
Alex Deymo437b7af2015-10-14 20:13:58 -0700210 // We just checked that |i| is not negative.
211 if (static_cast<uint64_t>(i) != old_file_pos && !old_file->Seek(i))
212 err(1, "error seeking input file to offset %" PRId64, i);
Alex Deymob870eb52015-10-14 21:39:04 -0700213 if ((old_file_pos = oldpos + ctrl[0]) > oldsize)
214 old_file_pos = oldsize;
Alex Deymo437b7af2015-10-14 20:13:58 -0700215
216 uint64_t chunk_size = old_file_pos - i;
217 while (chunk_size > 0) {
218 size_t read_bytes;
Sen Jiangd87c8352015-11-20 16:14:36 -0800219 size_t bytes_to_read =
220 std::min(chunk_size, static_cast<uint64_t>(old_buf.size()));
221 if (!old_file->Read(old_buf.data(), 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 if (!read_bytes)
224 errx(1, "EOF reached while reading from input file");
Sen Jiangd87c8352015-11-20 16:14:36 -0800225 // new_buf already has data from diff block, adds old data to it.
226 for (size_t k = 0; k < read_bytes; k++)
227 new_buf[j++] += old_buf[k];
Alex Deymo437b7af2015-10-14 20:13:58 -0700228 chunk_size -= read_bytes;
Alex Deymob870eb52015-10-14 21:39:04 -0700229 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800230
Alex Deymob870eb52015-10-14 21:39:04 -0700231 // Adjust pointers.
232 newpos += ctrl[0];
233 oldpos += ctrl[0];
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800234
Alex Deymob870eb52015-10-14 21:39:04 -0700235 // Sanity-check.
236 if (newpos + ctrl[1] > newsize)
237 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800238
Alex Deymob870eb52015-10-14 21:39:04 -0700239 // Read extra string.
240 lenread = BZ2_bzRead(&ebz2err, epfbz2, new_buf + newpos, ctrl[1]);
241 if ((lenread < ctrl[1]) ||
242 ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END)))
243 errx(1, "Corrupt patch\n");
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800244
Alex Deymob870eb52015-10-14 21:39:04 -0700245 // Adjust pointers.
246 newpos += ctrl[1];
247 oldpos += ctrl[2];
248 };
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800249
Alex Deymob870eb52015-10-14 21:39:04 -0700250 // Close input file.
Alex Deymo437b7af2015-10-14 20:13:58 -0700251 old_file->Close();
Gilad Arnold99b53742013-04-30 09:24:14 -0700252
Alex Deymob870eb52015-10-14 21:39:04 -0700253 // Clean up the bzip2 reads.
254 BZ2_bzReadClose(&cbz2err, cpfbz2);
255 BZ2_bzReadClose(&dbz2err, dpfbz2);
256 BZ2_bzReadClose(&ebz2err, epfbz2);
257 if (fclose(cpf) || fclose(dpf) || fclose(epf))
258 err(1, "fclose(%s)", patch_filename);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800259
Alex Deymob870eb52015-10-14 21:39:04 -0700260 // Write the new file.
Alex Deymo437b7af2015-10-14 20:13:58 -0700261 std::unique_ptr<FileInterface> new_file =
262 File::FOpen(new_filename, O_CREAT | O_WRONLY);
263 if (!new_file)
264 err(1, "Error opening the new filename %s", new_filename);
265
Alex Deymob870eb52015-10-14 21:39:04 -0700266 if (using_extents) {
Alex Deymo437b7af2015-10-14 20:13:58 -0700267 std::vector<ex_t> parsed_new_extents;
268 if (!ParseExtentStr(new_extents, &parsed_new_extents))
269 errx(1, "Error parsing the new extents");
270 new_file.reset(new ExtentsFile(std::move(new_file), parsed_new_extents));
271 }
272
Sen Jiangd87c8352015-11-20 16:14:36 -0800273 u_char* temp_new_buf = new_buf; // new_buf needed for free()
Alex Deymo437b7af2015-10-14 20:13:58 -0700274 while (newsize > 0) {
275 size_t bytes_written;
Sen Jiangd87c8352015-11-20 16:14:36 -0800276 if (!new_file->Write(temp_new_buf, newsize, &bytes_written))
Alex Deymo437b7af2015-10-14 20:13:58 -0700277 err(1, "Error writing new file %s", new_filename);
278 newsize -= bytes_written;
Sen Jiangd87c8352015-11-20 16:14:36 -0800279 temp_new_buf += bytes_written;
Alex Deymo437b7af2015-10-14 20:13:58 -0700280 }
281
282 if (!new_file->Close())
283 err(1, "Error closing new file %s", new_filename);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800284
Alex Deymob870eb52015-10-14 21:39:04 -0700285 free(new_buf);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800286
Alex Deymob870eb52015-10-14 21:39:04 -0700287 return 0;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800288}
Alex Deymo20891f92015-10-12 17:28:04 -0700289
290} // namespace bsdiff