blob: d7f1710bbe70742ae8f6f1a437abc800370ad9b8 [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 Deymoddf9db52017-03-02 16:10:41 -080031#include "bsdiff/bspatch.h"
Alex Deymob870eb52015-10-14 21:39:04 -070032
Sen Jiang5b372b62016-03-28 16:14:35 -070033#include <errno.h>
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080034#include <fcntl.h>
Gilad Arnold99b53742013-04-30 09:24:14 -070035#include <inttypes.h>
Alex Deymoea72d9f2017-10-26 13:15:13 +020036#include <stdio.h>
Amin Hassani6e40d932019-05-13 11:47:57 -070037#include <stdint.h>
Gilad Arnold99b53742013-04-30 09:24:14 -070038#include <stdlib.h>
39#include <string.h>
Sen Jiang5b372b62016-03-28 16:14:35 -070040#include <sys/stat.h>
Alex Deymob870eb52015-10-14 21:39:04 -070041#include <sys/types.h>
Alex Deymodcd423b2017-09-13 20:54:24 +020042#include <unistd.h>
The Android Open Source Projectc285fea2009-03-03 19:29:20 -080043
Alex Deymo437b7af2015-10-14 20:13:58 -070044#include <algorithm>
Alex Deymodcd423b2017-09-13 20:54:24 +020045#include <memory>
Sen Jiang5b372b62016-03-28 16:14:35 -070046#include <vector>
Alex Deymo437b7af2015-10-14 20:13:58 -070047
Alex Deymodcd423b2017-09-13 20:54:24 +020048#include "bsdiff/buffer_file.h"
Tianjie Xu65288122017-10-13 15:10:58 -070049#include "bsdiff/control_entry.h"
Alex Deymodcd423b2017-09-13 20:54:24 +020050#include "bsdiff/extents.h"
Alex Deymoddf9db52017-03-02 16:10:41 -080051#include "bsdiff/extents_file.h"
Alex Deymodcd423b2017-09-13 20:54:24 +020052#include "bsdiff/file.h"
Alex Deymoddf9db52017-03-02 16:10:41 -080053#include "bsdiff/file_interface.h"
Amin Hassani1106bf72017-11-15 17:26:03 -080054#include "bsdiff/logging.h"
Alex Deymodcd423b2017-09-13 20:54:24 +020055#include "bsdiff/memory_file.h"
Tianjie Xu65288122017-10-13 15:10:58 -070056#include "bsdiff/patch_reader.h"
Alex Deymodcd423b2017-09-13 20:54:24 +020057#include "bsdiff/sink_file.h"
Tianjie Xu65288122017-10-13 15:10:58 -070058#include "bsdiff/utils.h"
Zdenek Behan339e0ee2010-06-14 12:50:53 -070059
Alex Deymo20891f92015-10-12 17:28:04 -070060namespace {
Tianjie Xu65288122017-10-13 15:10:58 -070061// Read the data in |stream| and write |size| decompressed data to |file|;
62// using the buffer in |buf| with size |buf_size|.
63// Returns 0 on success, 1 on I/O error and 2 on data error.
64int ReadStreamAndWriteAll(
65 const std::unique_ptr<bsdiff::FileInterface>& file,
66 size_t size,
67 uint8_t* buf,
68 size_t buf_size,
69 const std::function<bool(uint8_t*, size_t)>& read_func) {
Sen Jiang716d5692016-05-09 16:43:34 -070070 while (size > 0) {
Tianjie Xu65288122017-10-13 15:10:58 -070071 size_t bytes_to_output = std::min(size, buf_size);
72 if (!read_func(buf, bytes_to_output)) {
Amin Hassani1106bf72017-11-15 17:26:03 -080073 LOG(ERROR) << "Failed to read stream.";
Sen Jiangb552c792017-01-20 14:07:49 -080074 return 2;
75 }
Tianjie Xu65288122017-10-13 15:10:58 -070076
77 if (!WriteAll(file, buf, bytes_to_output)) {
Amin Hassani1106bf72017-11-15 17:26:03 -080078 PLOG(ERROR) << "WriteAll() failed.";
Sen Jiangb552c792017-01-20 14:07:49 -080079 return 1;
80 }
Tianjie Xu65288122017-10-13 15:10:58 -070081 size -= bytes_to_output;
Sen Jiang5b372b62016-03-28 16:14:35 -070082 }
Sen Jiangb552c792017-01-20 14:07:49 -080083 return 0;
Sen Jiang5b372b62016-03-28 16:14:35 -070084}
85
Alex Deymo20891f92015-10-12 17:28:04 -070086} // namespace
87
88namespace bsdiff {
89
Sen Jiang716d5692016-05-09 16:43:34 -070090bool ReadAll(const std::unique_ptr<FileInterface>& file,
91 uint8_t* data,
92 size_t size) {
93 size_t offset = 0, read;
94 while (offset < size) {
95 if (!file->Read(data + offset, size - offset, &read) || read == 0)
96 return false;
97 offset += read;
98 }
99 return true;
100}
101
Sen Jiang5b372b62016-03-28 16:14:35 -0700102bool WriteAll(const std::unique_ptr<FileInterface>& file,
103 const uint8_t* data,
104 size_t size) {
105 size_t offset = 0, written;
106 while (offset < size) {
Sen Jiangb14bb552016-04-11 16:08:03 -0700107 if (!file->Write(data + offset, size - offset, &written) || written == 0)
Sen Jiang5b372b62016-03-28 16:14:35 -0700108 return false;
109 offset += written;
110 }
111 return true;
112}
113
114bool IsOverlapping(const char* old_filename,
115 const char* new_filename,
116 const std::vector<ex_t>& old_extents,
117 const std::vector<ex_t>& new_extents) {
118 struct stat old_stat, new_stat;
119 if (stat(new_filename, &new_stat) == -1) {
120 if (errno == ENOENT)
121 return false;
Amin Hassani1106bf72017-11-15 17:26:03 -0800122 PLOG(ERROR) << "Error stat the new file: " << new_filename;
Sen Jiangb552c792017-01-20 14:07:49 -0800123 return true;
Sen Jiang5b372b62016-03-28 16:14:35 -0700124 }
Sen Jiangb552c792017-01-20 14:07:49 -0800125 if (stat(old_filename, &old_stat) == -1) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800126 PLOG(ERROR) << "Error stat the old file: " << old_filename;
Sen Jiangb552c792017-01-20 14:07:49 -0800127 return true;
128 }
Sen Jiang5b372b62016-03-28 16:14:35 -0700129
130 if (old_stat.st_dev != new_stat.st_dev || old_stat.st_ino != new_stat.st_ino)
131 return false;
132
133 if (old_extents.empty() && new_extents.empty())
134 return true;
135
136 for (ex_t old_ex : old_extents)
137 for (ex_t new_ex : new_extents)
138 if (static_cast<uint64_t>(old_ex.off) < new_ex.off + new_ex.len &&
139 static_cast<uint64_t>(new_ex.off) < old_ex.off + old_ex.len)
140 return true;
141
142 return false;
143}
144
Sen Jiangb552c792017-01-20 14:07:49 -0800145// Patch |old_filename| with |patch_filename| and save it to |new_filename|.
146// |old_extents| and |new_extents| are comma-separated lists of "offset:length"
147// extents of |old_filename| and |new_filename|.
148// Returns 0 on success, 1 on I/O error and 2 on data error.
149int bspatch(const char* old_filename,
150 const char* new_filename,
151 const char* patch_filename,
152 const char* old_extents,
153 const char* new_extents) {
Sen Jiang716d5692016-05-09 16:43:34 -0700154 std::unique_ptr<FileInterface> patch_file =
155 File::FOpen(patch_filename, O_RDONLY);
Sen Jiangb552c792017-01-20 14:07:49 -0800156 if (!patch_file) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800157 PLOG(ERROR) << "Error opening the patch file: " << patch_filename;
Sen Jiangb552c792017-01-20 14:07:49 -0800158 return 1;
159 }
Sen Jiang716d5692016-05-09 16:43:34 -0700160 uint64_t patch_size;
161 patch_file->GetSize(&patch_size);
162 std::vector<uint8_t> patch(patch_size);
Sen Jiangb552c792017-01-20 14:07:49 -0800163 if (!ReadAll(patch_file, patch.data(), patch_size)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800164 PLOG(ERROR) << "Error reading the patch file: " << patch_filename;
Sen Jiangb552c792017-01-20 14:07:49 -0800165 return 1;
166 }
Sen Jiang716d5692016-05-09 16:43:34 -0700167 patch_file.reset();
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800168
Sen Jiang62d5e482017-01-24 16:25:25 -0800169 return bspatch(old_filename, new_filename, patch.data(), patch_size,
170 old_extents, new_extents);
171}
172
173// Patch |old_filename| with |patch_data| and save it to |new_filename|.
174// |old_extents| and |new_extents| are comma-separated lists of "offset:length"
175// extents of |old_filename| and |new_filename|.
176// Returns 0 on success, 1 on I/O error and 2 on data error.
177int bspatch(const char* old_filename,
178 const char* new_filename,
179 const uint8_t* patch_data,
180 size_t patch_size,
181 const char* old_extents,
182 const char* new_extents) {
Alex Deymob870eb52015-10-14 21:39:04 -0700183 int using_extents = (old_extents != NULL || new_extents != NULL);
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800184
Alex Deymob870eb52015-10-14 21:39:04 -0700185 // Open input file for reading.
Alex Deymo437b7af2015-10-14 20:13:58 -0700186 std::unique_ptr<FileInterface> old_file = File::FOpen(old_filename, O_RDONLY);
Sen Jiangb552c792017-01-20 14:07:49 -0800187 if (!old_file) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800188 PLOG(ERROR) << "Error opening the old file: " << old_filename;
Sen Jiangb552c792017-01-20 14:07:49 -0800189 return 1;
190 }
Alex Deymo437b7af2015-10-14 20:13:58 -0700191
Sen Jiang5b372b62016-03-28 16:14:35 -0700192 std::vector<ex_t> parsed_old_extents;
Alex Deymob870eb52015-10-14 21:39:04 -0700193 if (using_extents) {
Sen Jiangb552c792017-01-20 14:07:49 -0800194 if (!ParseExtentStr(old_extents, &parsed_old_extents)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800195 LOG(ERROR) << "Error parsing the old extents.";
Sen Jiangb552c792017-01-20 14:07:49 -0800196 return 2;
197 }
Alex Deymo437b7af2015-10-14 20:13:58 -0700198 old_file.reset(new ExtentsFile(std::move(old_file), parsed_old_extents));
199 }
200
Sen Jiang5b372b62016-03-28 16:14:35 -0700201 // Open output file for writing.
202 std::unique_ptr<FileInterface> new_file =
203 File::FOpen(new_filename, O_CREAT | O_WRONLY);
Sen Jiangb552c792017-01-20 14:07:49 -0800204 if (!new_file) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800205 PLOG(ERROR) << "Error opening the new file: " << new_filename;
Sen Jiangb552c792017-01-20 14:07:49 -0800206 return 1;
207 }
Sen Jiang5b372b62016-03-28 16:14:35 -0700208
209 std::vector<ex_t> parsed_new_extents;
210 if (using_extents) {
Sen Jiangb552c792017-01-20 14:07:49 -0800211 if (!ParseExtentStr(new_extents, &parsed_new_extents)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800212 LOG(ERROR) << "Error parsing the new extents.";
Sen Jiangb552c792017-01-20 14:07:49 -0800213 return 2;
214 }
Sen Jiang5b372b62016-03-28 16:14:35 -0700215 new_file.reset(new ExtentsFile(std::move(new_file), parsed_new_extents));
216 }
217
218 if (IsOverlapping(old_filename, new_filename, parsed_old_extents,
219 parsed_new_extents)) {
220 // New and old file is overlapping, we can not stream output to new file,
Sen Jiang716d5692016-05-09 16:43:34 -0700221 // cache it in a buffer and write to the file at the end.
Sen Jiang62d5e482017-01-24 16:25:25 -0800222 uint64_t newsize = ParseInt64(patch_data + 24);
Sen Jiang716d5692016-05-09 16:43:34 -0700223 new_file.reset(new BufferFile(std::move(new_file), newsize));
Sen Jiang5b372b62016-03-28 16:14:35 -0700224 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800225
Sen Jiang62d5e482017-01-24 16:25:25 -0800226 return bspatch(old_file, new_file, patch_data, patch_size);
Sen Jiang716d5692016-05-09 16:43:34 -0700227}
228
Sen Jiangb552c792017-01-20 14:07:49 -0800229// Patch |old_data| with |patch_data| and save it by calling sink function.
230// Returns 0 on success, 1 on I/O error and 2 on data error.
Sen Jiang716d5692016-05-09 16:43:34 -0700231int bspatch(const uint8_t* old_data,
232 size_t old_size,
233 const uint8_t* patch_data,
234 size_t patch_size,
235 const sink_func& sink) {
236 std::unique_ptr<FileInterface> old_file(new MemoryFile(old_data, old_size));
237 std::unique_ptr<FileInterface> new_file(new SinkFile(sink));
238
239 return bspatch(old_file, new_file, patch_data, patch_size);
240}
241
Sen Jiangb552c792017-01-20 14:07:49 -0800242// Patch |old_file| with |patch_data| and save it to |new_file|.
243// Returns 0 on success, 1 on I/O error and 2 on data error.
Sen Jiang716d5692016-05-09 16:43:34 -0700244int bspatch(const std::unique_ptr<FileInterface>& old_file,
245 const std::unique_ptr<FileInterface>& new_file,
246 const uint8_t* patch_data,
247 size_t patch_size) {
Tianjie Xu65288122017-10-13 15:10:58 -0700248 BsdiffPatchReader patch_reader;
249 if (!patch_reader.Init(patch_data, patch_size)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800250 LOG(ERROR) << "Failed to initialize patch reader.";
Sen Jiangb552c792017-01-20 14:07:49 -0800251 return 2;
252 }
Sen Jiang716d5692016-05-09 16:43:34 -0700253
Tianjie Xu65288122017-10-13 15:10:58 -0700254 uint64_t old_file_size;
255 if (!old_file->GetSize(&old_file_size)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800256 LOG(ERROR) << "Cannot obtain the size of old file.";
Sen Jiangb552c792017-01-20 14:07:49 -0800257 return 1;
258 }
Sen Jiang716d5692016-05-09 16:43:34 -0700259
Alex Deymo437b7af2015-10-14 20:13:58 -0700260 // The oldpos can be negative, but the new pos is only incremented linearly.
261 int64_t oldpos = 0;
262 uint64_t newpos = 0;
Tianjie Xu65288122017-10-13 15:10:58 -0700263 std::vector<uint8_t> old_buf(1024 * 1024);
264 std::vector<uint8_t> new_buf(1024 * 1024);
265 uint64_t old_file_pos = 0;
266 while (newpos < patch_reader.new_file_size()) {
267 ControlEntry control_entry(0, 0, 0);
268 if (!patch_reader.ParseControlEntry(&control_entry)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800269 LOG(ERROR) << "Failed to read control stream.";
Sen Jiangb552c792017-01-20 14:07:49 -0800270 return 2;
271 }
Doug Zongker4d054792014-05-13 08:37:06 -0700272
Alex Deymob870eb52015-10-14 21:39:04 -0700273 // Sanity-check.
Tianjie Xu65288122017-10-13 15:10:58 -0700274 if (newpos + control_entry.diff_size > patch_reader.new_file_size()) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800275 LOG(ERROR) << "Corrupt patch.";
Sen Jiangb552c792017-01-20 14:07:49 -0800276 return 2;
277 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800278
Sen Jiangb552c792017-01-20 14:07:49 -0800279 int ret = 0;
Alex Deymob870eb52015-10-14 21:39:04 -0700280 // Add old data to diff string. It is enough to fseek once, at
281 // the beginning of the sequence, to avoid unnecessary overhead.
Tianjie Xu65288122017-10-13 15:10:58 -0700282 int64_t seek_offset = oldpos;
283 if (seek_offset < 0) {
Sen Jiang5b372b62016-03-28 16:14:35 -0700284 // Write diff block directly to new file without adding old data,
285 // because we will skip part where |oldpos| < 0.
Tianjie Xu65288122017-10-13 15:10:58 -0700286 ret = ReadStreamAndWriteAll(
287 new_file, oldpos - old_file_size, new_buf.data(), new_buf.size(),
288 std::bind(&BsdiffPatchReader::ReadDiffStream, &patch_reader,
289 std::placeholders::_1, std::placeholders::_2));
Sen Jiangb552c792017-01-20 14:07:49 -0800290 if (ret)
291 return ret;
Tianjie Xu65288122017-10-13 15:10:58 -0700292 seek_offset = 0;
Alex Deymob870eb52015-10-14 21:39:04 -0700293 }
Sen Jiang5b372b62016-03-28 16:14:35 -0700294
Tianjie Xu65288122017-10-13 15:10:58 -0700295 // We just checked that |seek_offset| is not negative.
296 if (static_cast<uint64_t>(seek_offset) != old_file_pos &&
297 !old_file->Seek(seek_offset)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800298 PLOG(ERROR) << "Error seeking input file to offset: " << seek_offset;
Sen Jiangb552c792017-01-20 14:07:49 -0800299 return 1;
300 }
Alex Deymo437b7af2015-10-14 20:13:58 -0700301
Tianjie Xu65288122017-10-13 15:10:58 -0700302 old_file_pos =
303 std::min<uint64_t>(oldpos + control_entry.diff_size, old_file_size);
304 size_t chunk_size = old_file_pos - seek_offset;
Alex Deymo437b7af2015-10-14 20:13:58 -0700305 while (chunk_size > 0) {
306 size_t read_bytes;
Sen Jiang5b372b62016-03-28 16:14:35 -0700307 size_t bytes_to_read = std::min(chunk_size, old_buf.size());
Sen Jiangb552c792017-01-20 14:07:49 -0800308 if (!old_file->Read(old_buf.data(), bytes_to_read, &read_bytes)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800309 PLOG(ERROR) << "Error reading from input file.";
Sen Jiangb552c792017-01-20 14:07:49 -0800310 return 1;
311 }
312 if (!read_bytes) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800313 LOG(ERROR) << "EOF reached while reading from input file.";
Sen Jiangb552c792017-01-20 14:07:49 -0800314 return 2;
315 }
Sen Jiang5b372b62016-03-28 16:14:35 -0700316 // Read same amount of bytes from diff block
Tianjie Xu65288122017-10-13 15:10:58 -0700317 if (!patch_reader.ReadDiffStream(new_buf.data(), read_bytes)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800318 LOG(ERROR) << "Failed to read diff stream.";
Sen Jiangb552c792017-01-20 14:07:49 -0800319 return 2;
320 }
Sen Jiangd87c8352015-11-20 16:14:36 -0800321 // new_buf already has data from diff block, adds old data to it.
322 for (size_t k = 0; k < read_bytes; k++)
Sen Jiang5b372b62016-03-28 16:14:35 -0700323 new_buf[k] += old_buf[k];
Sen Jiangb552c792017-01-20 14:07:49 -0800324 if (!WriteAll(new_file, new_buf.data(), read_bytes)) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800325 PLOG(ERROR) << "Error writing to new file.";
Sen Jiangb552c792017-01-20 14:07:49 -0800326 return 1;
327 }
Alex Deymo437b7af2015-10-14 20:13:58 -0700328 chunk_size -= read_bytes;
Alex Deymob870eb52015-10-14 21:39:04 -0700329 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800330
Alex Deymob870eb52015-10-14 21:39:04 -0700331 // Adjust pointers.
Tianjie Xu65288122017-10-13 15:10:58 -0700332 newpos += control_entry.diff_size;
Amin Hassani6e40d932019-05-13 11:47:57 -0700333 if (oldpos > INT64_MAX - static_cast<int64_t>(control_entry.diff_size))
334 return 2;
Tianjie Xu65288122017-10-13 15:10:58 -0700335 oldpos += control_entry.diff_size;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800336
Tianjie Xu65288122017-10-13 15:10:58 -0700337 if (oldpos > static_cast<int64_t>(old_file_size)) {
Sen Jiang5b372b62016-03-28 16:14:35 -0700338 // Write diff block directly to new file without adding old data,
Tianjie Xu65288122017-10-13 15:10:58 -0700339 // because we skipped part where |oldpos| > old_file_size.
340 ret = ReadStreamAndWriteAll(
341 new_file, oldpos - old_file_size, new_buf.data(), new_buf.size(),
342 std::bind(&BsdiffPatchReader::ReadDiffStream, &patch_reader,
343 std::placeholders::_1, std::placeholders::_2));
Sen Jiangb552c792017-01-20 14:07:49 -0800344 if (ret)
345 return ret;
Sen Jiang5b372b62016-03-28 16:14:35 -0700346 }
347
Alex Deymob870eb52015-10-14 21:39:04 -0700348 // Sanity-check.
Tianjie Xu65288122017-10-13 15:10:58 -0700349 if (newpos + control_entry.extra_size > patch_reader.new_file_size()) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800350 LOG(ERROR) << "Corrupt patch.";
Sen Jiangb552c792017-01-20 14:07:49 -0800351 return 2;
352 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800353
Sen Jiang5b372b62016-03-28 16:14:35 -0700354 // Read extra block.
Tianjie Xu65288122017-10-13 15:10:58 -0700355 ret = ReadStreamAndWriteAll(
356 new_file, control_entry.extra_size, new_buf.data(), new_buf.size(),
357 std::bind(&BsdiffPatchReader::ReadExtraStream, &patch_reader,
358 std::placeholders::_1, std::placeholders::_2));
Sen Jiangb552c792017-01-20 14:07:49 -0800359 if (ret)
360 return ret;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800361
Alex Deymob870eb52015-10-14 21:39:04 -0700362 // Adjust pointers.
Tianjie Xu65288122017-10-13 15:10:58 -0700363 newpos += control_entry.extra_size;
Amin Hassani6e40d932019-05-13 11:47:57 -0700364 if (control_entry.offset_increment > 0 &&
365 oldpos > INT64_MAX - control_entry.offset_increment)
366 return 2;
Tianjie Xu65288122017-10-13 15:10:58 -0700367 oldpos += control_entry.offset_increment;
Sen Jiang5b372b62016-03-28 16:14:35 -0700368 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800369
Alex Deymob870eb52015-10-14 21:39:04 -0700370 // Close input file.
Alex Deymo437b7af2015-10-14 20:13:58 -0700371 old_file->Close();
Gilad Arnold99b53742013-04-30 09:24:14 -0700372
Tianjie Xu65288122017-10-13 15:10:58 -0700373 if (!patch_reader.Finish()) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800374 LOG(ERROR) << "Failed to finish the patch reader.";
Tianjie Xu65288122017-10-13 15:10:58 -0700375 return 2;
376 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800377
Sen Jiangb552c792017-01-20 14:07:49 -0800378 if (!new_file->Close()) {
Amin Hassani1106bf72017-11-15 17:26:03 -0800379 PLOG(ERROR) << "Error closing new file.";
Sen Jiangb552c792017-01-20 14:07:49 -0800380 return 1;
381 }
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800382
Alex Deymob870eb52015-10-14 21:39:04 -0700383 return 0;
The Android Open Source Projectc285fea2009-03-03 19:29:20 -0800384}
Alex Deymo20891f92015-10-12 17:28:04 -0700385
386} // namespace bsdiff