blob: dd6cf0d96ba35498232c331d275c9a7f329a3244 [file] [log] [blame]
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <ctype.h>
18#include <errno.h>
Sami Tolvanen90221202014-12-09 16:39:47 +000019#include <dirent.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070020#include <fcntl.h>
21#include <inttypes.h>
Tao Baoba9a42a2015-06-23 23:23:33 -070022#include <linux/fs.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070023#include <pthread.h>
24#include <stdarg.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
Sami Tolvanen90221202014-12-09 16:39:47 +000028#include <sys/stat.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070029#include <sys/types.h>
30#include <sys/wait.h>
31#include <sys/ioctl.h>
32#include <time.h>
33#include <unistd.h>
Sami Tolvanen0a7b4732015-06-25 10:25:36 +010034#include <fec/io.h>
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070035
Tao Baoe6aa3322015-08-05 15:20:27 -070036#include <memory>
37#include <string>
Tao Bao0940fe12015-08-27 16:41:21 -070038#include <vector>
Tao Baoe6aa3322015-08-05 15:20:27 -070039
Tao Baob15fd222015-09-24 11:10:51 -070040#include <base/parseint.h>
Tao Baoe6aa3322015-08-05 15:20:27 -070041#include <base/strings.h>
42
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070043#include "applypatch/applypatch.h"
44#include "edify/expr.h"
45#include "mincrypt/sha.h"
Sami Tolvanen90221202014-12-09 16:39:47 +000046#include "minzip/Hash.h"
Tao Baoe6aa3322015-08-05 15:20:27 -070047#include "print_sha1.h"
Tao Bao0940fe12015-08-27 16:41:21 -070048#include "unique_fd.h"
49#include "updater.h"
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070050
51#define BLOCKSIZE 4096
52
Sami Tolvanene82fa182015-06-10 15:58:12 +000053// Set this to 0 to interpret 'erase' transfers to mean do a
54// BLKDISCARD ioctl (the normal behavior). Set to 1 to interpret
55// erase to mean fill the region with zeroes.
56#define DEBUG_ERASE 0
57
Sami Tolvanen90221202014-12-09 16:39:47 +000058#define STASH_DIRECTORY_BASE "/cache/recovery"
59#define STASH_DIRECTORY_MODE 0700
60#define STASH_FILE_MODE 0600
61
Tao Bao0940fe12015-08-27 16:41:21 -070062struct RangeSet {
63 size_t count; // Limit is INT_MAX.
Shrinivas Sahukara6153df2015-08-19 13:01:45 +053064 size_t size;
Tao Bao0940fe12015-08-27 16:41:21 -070065 std::vector<size_t> pos; // Actual limit is INT_MAX.
66};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070067
Tao Bao0940fe12015-08-27 16:41:21 -070068static void parse_range(const char* range_text, RangeSet& rs) {
Sami Tolvanenf2bac042015-05-12 12:48:46 +010069
Tao Bao0940fe12015-08-27 16:41:21 -070070 if (range_text == nullptr) {
71 fprintf(stderr, "failed to parse range: null range\n");
72 exit(1);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070073 }
Sami Tolvanenf2bac042015-05-12 12:48:46 +010074
Tao Bao0940fe12015-08-27 16:41:21 -070075 std::vector<std::string> pieces = android::base::Split(std::string(range_text), ",");
76 long int val;
Sami Tolvanenf2bac042015-05-12 12:48:46 +010077
Tao Bao0940fe12015-08-27 16:41:21 -070078 if (pieces.size() < 3) {
Sami Tolvanenf2bac042015-05-12 12:48:46 +010079 goto err;
80 }
81
Tao Baob15fd222015-09-24 11:10:51 -070082 size_t num;
83 if (!android::base::ParseUint(pieces[0].c_str(), &num, static_cast<size_t>(INT_MAX))) {
Sami Tolvanenf2bac042015-05-12 12:48:46 +010084 goto err;
85 }
86
Tao Baob15fd222015-09-24 11:10:51 -070087 if (num == 0 || num % 2) {
88 goto err; // must be even
89 } else if (num != pieces.size() - 1) {
90 goto err;
91 }
Sami Tolvanenf2bac042015-05-12 12:48:46 +010092
Tao Bao0940fe12015-08-27 16:41:21 -070093 rs.pos.resize(num);
94 rs.count = num / 2;
95 rs.size = 0;
Sami Tolvanenf2bac042015-05-12 12:48:46 +010096
Tao Bao0940fe12015-08-27 16:41:21 -070097 for (size_t i = 0; i < num; i += 2) {
Tao Baob15fd222015-09-24 11:10:51 -070098 if (!android::base::ParseUint(pieces[i+1].c_str(), &rs.pos[i],
99 static_cast<size_t>(INT_MAX))) {
Sami Tolvanenf2bac042015-05-12 12:48:46 +0100100 goto err;
101 }
102
Tao Baob15fd222015-09-24 11:10:51 -0700103 if (!android::base::ParseUint(pieces[i+2].c_str(), &rs.pos[i+1],
104 static_cast<size_t>(INT_MAX))) {
Shrinivas Sahukara6153df2015-08-19 13:01:45 +0530105 goto err;
106 }
107
Tao Bao0940fe12015-08-27 16:41:21 -0700108 if (rs.pos[i] >= rs.pos[i+1]) {
Shrinivas Sahukara6153df2015-08-19 13:01:45 +0530109 goto err; // empty or negative range
110 }
111
Tao Bao0940fe12015-08-27 16:41:21 -0700112 size_t sz = rs.pos[i+1] - rs.pos[i];
113 if (rs.size > SIZE_MAX - sz) {
Shrinivas Sahukara6153df2015-08-19 13:01:45 +0530114 goto err; // overflow
115 }
116
Tao Bao0940fe12015-08-27 16:41:21 -0700117 rs.size += sz;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700118 }
119
Tao Bao0940fe12015-08-27 16:41:21 -0700120 return;
Sami Tolvanenf2bac042015-05-12 12:48:46 +0100121
122err:
Tao Bao0940fe12015-08-27 16:41:21 -0700123 fprintf(stderr, "failed to parse range '%s'\n", range_text);
Sami Tolvanenf2bac042015-05-12 12:48:46 +0100124 exit(1);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700125}
126
Tao Baoe6aa3322015-08-05 15:20:27 -0700127static bool range_overlaps(const RangeSet& r1, const RangeSet& r2) {
Shrinivas Sahukara6153df2015-08-19 13:01:45 +0530128 for (size_t i = 0; i < r1.count; ++i) {
129 size_t r1_0 = r1.pos[i * 2];
130 size_t r1_1 = r1.pos[i * 2 + 1];
Sami Tolvanen90221202014-12-09 16:39:47 +0000131
Shrinivas Sahukara6153df2015-08-19 13:01:45 +0530132 for (size_t j = 0; j < r2.count; ++j) {
133 size_t r2_0 = r2.pos[j * 2];
134 size_t r2_1 = r2.pos[j * 2 + 1];
Sami Tolvanen90221202014-12-09 16:39:47 +0000135
Tao Baoc0f56ad2015-06-25 14:00:31 -0700136 if (!(r2_0 >= r1_1 || r1_0 >= r2_1)) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700137 return true;
Sami Tolvanen90221202014-12-09 16:39:47 +0000138 }
139 }
140 }
141
Tao Baoe6aa3322015-08-05 15:20:27 -0700142 return false;
Sami Tolvanen90221202014-12-09 16:39:47 +0000143}
144
145static int read_all(int fd, uint8_t* data, size_t size) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700146 size_t so_far = 0;
147 while (so_far < size) {
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700148 ssize_t r = TEMP_FAILURE_RETRY(read(fd, data+so_far, size-so_far));
149 if (r == -1) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700150 fprintf(stderr, "read failed: %s\n", strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000151 return -1;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700152 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700153 so_far += r;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700154 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000155 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700156}
157
Tao Bao612336d2015-08-27 16:41:21 -0700158static int read_all(int fd, std::vector<uint8_t>& buffer, size_t size) {
159 return read_all(fd, buffer.data(), size);
160}
161
Sami Tolvanen90221202014-12-09 16:39:47 +0000162static int write_all(int fd, const uint8_t* data, size_t size) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700163 size_t written = 0;
164 while (written < size) {
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700165 ssize_t w = TEMP_FAILURE_RETRY(write(fd, data+written, size-written));
166 if (w == -1) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700167 fprintf(stderr, "write failed: %s\n", strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000168 return -1;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700169 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700170 written += w;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700171 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000172
Sami Tolvanen90221202014-12-09 16:39:47 +0000173 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700174}
175
Tao Bao612336d2015-08-27 16:41:21 -0700176static int write_all(int fd, const std::vector<uint8_t>& buffer, size_t size) {
177 return write_all(fd, buffer.data(), size);
178}
179
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700180static bool check_lseek(int fd, off64_t offset, int whence) {
181 off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
182 if (rc == -1) {
183 fprintf(stderr, "lseek64 failed: %s\n", strerror(errno));
184 return false;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700185 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700186 return true;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700187}
188
Tao Bao612336d2015-08-27 16:41:21 -0700189static void allocate(size_t size, std::vector<uint8_t>& buffer) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700190 // if the buffer's big enough, reuse it.
Tao Bao612336d2015-08-27 16:41:21 -0700191 if (size <= buffer.size()) return;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700192
Tao Bao612336d2015-08-27 16:41:21 -0700193 buffer.resize(size);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700194}
195
Tao Bao0940fe12015-08-27 16:41:21 -0700196struct RangeSinkState {
197 RangeSinkState(RangeSet& rs) : tgt(rs) { };
198
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700199 int fd;
Tao Bao0940fe12015-08-27 16:41:21 -0700200 const RangeSet& tgt;
Shrinivas Sahukara6153df2015-08-19 13:01:45 +0530201 size_t p_block;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700202 size_t p_remain;
Tao Bao0940fe12015-08-27 16:41:21 -0700203};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700204
205static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
Tao Bao0940fe12015-08-27 16:41:21 -0700206 RangeSinkState* rss = reinterpret_cast<RangeSinkState*>(token);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700207
Tao Bao0940fe12015-08-27 16:41:21 -0700208 if (rss->p_remain == 0) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700209 fprintf(stderr, "range sink write overrun");
Sami Tolvanen90221202014-12-09 16:39:47 +0000210 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700211 }
212
213 ssize_t written = 0;
214 while (size > 0) {
215 size_t write_now = size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000216
217 if (rss->p_remain < write_now) {
218 write_now = rss->p_remain;
219 }
220
221 if (write_all(rss->fd, data, write_now) == -1) {
222 break;
223 }
224
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700225 data += write_now;
226 size -= write_now;
227
228 rss->p_remain -= write_now;
229 written += write_now;
230
231 if (rss->p_remain == 0) {
232 // move to the next block
233 ++rss->p_block;
Tao Bao0940fe12015-08-27 16:41:21 -0700234 if (rss->p_block < rss->tgt.count) {
235 rss->p_remain = (rss->tgt.pos[rss->p_block * 2 + 1] -
236 rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000237
Tao Bao0940fe12015-08-27 16:41:21 -0700238 if (!check_lseek(rss->fd, (off64_t)rss->tgt.pos[rss->p_block*2] * BLOCKSIZE,
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700239 SEEK_SET)) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000240 break;
241 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700242 } else {
243 // we can't write any more; return how many bytes have
244 // been written so far.
Sami Tolvanen90221202014-12-09 16:39:47 +0000245 break;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700246 }
247 }
248 }
249
250 return written;
251}
252
253// All of the data for all the 'new' transfers is contained in one
254// file in the update package, concatenated together in the order in
255// which transfers.list will need it. We want to stream it out of the
256// archive (it's compressed) without writing it to a temp file, but we
257// can't write each section until it's that transfer's turn to go.
258//
259// To achieve this, we expand the new data from the archive in a
260// background thread, and block that threads 'receive uncompressed
261// data' function until the main thread has reached a point where we
262// want some new data to be written. We signal the background thread
263// with the destination for the data and block the main thread,
264// waiting for the background thread to complete writing that section.
265// Then it signals the main thread to wake up and goes back to
266// blocking waiting for a transfer.
267//
268// NewThreadInfo is the struct used to pass information back and forth
269// between the two threads. When the main thread wants some data
270// written, it sets rss to the destination location and signals the
271// condition. When the background thread is done writing, it clears
272// rss and signals the condition again.
273
Tao Bao0940fe12015-08-27 16:41:21 -0700274struct NewThreadInfo {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700275 ZipArchive* za;
276 const ZipEntry* entry;
277
278 RangeSinkState* rss;
279
280 pthread_mutex_t mu;
281 pthread_cond_t cv;
Tao Bao0940fe12015-08-27 16:41:21 -0700282};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700283
284static bool receive_new_data(const unsigned char* data, int size, void* cookie) {
Tao Bao0940fe12015-08-27 16:41:21 -0700285 NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700286
287 while (size > 0) {
Tao Bao0940fe12015-08-27 16:41:21 -0700288 // Wait for nti->rss to be non-null, indicating some of this
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700289 // data is wanted.
290 pthread_mutex_lock(&nti->mu);
Tao Bao0940fe12015-08-27 16:41:21 -0700291 while (nti->rss == nullptr) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700292 pthread_cond_wait(&nti->cv, &nti->mu);
293 }
294 pthread_mutex_unlock(&nti->mu);
295
296 // At this point nti->rss is set, and we own it. The main
297 // thread is waiting for it to disappear from nti.
298 ssize_t written = RangeSinkWrite(data, size, nti->rss);
299 data += written;
300 size -= written;
301
Tao Bao0940fe12015-08-27 16:41:21 -0700302 if (nti->rss->p_block == nti->rss->tgt.count) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700303 // we have written all the bytes desired by this rss.
304
305 pthread_mutex_lock(&nti->mu);
Tao Bao0940fe12015-08-27 16:41:21 -0700306 nti->rss = nullptr;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700307 pthread_cond_broadcast(&nti->cv);
308 pthread_mutex_unlock(&nti->mu);
309 }
310 }
311
312 return true;
313}
314
315static void* unzip_new_data(void* cookie) {
316 NewThreadInfo* nti = (NewThreadInfo*) cookie;
317 mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti);
Tao Bao0940fe12015-08-27 16:41:21 -0700318 return nullptr;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700319}
320
Tao Bao612336d2015-08-27 16:41:21 -0700321static int ReadBlocks(const RangeSet& src, std::vector<uint8_t>& buffer, int fd) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000322 size_t p = 0;
Tao Bao612336d2015-08-27 16:41:21 -0700323 uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000324
Tao Bao0940fe12015-08-27 16:41:21 -0700325 for (size_t i = 0; i < src.count; ++i) {
326 if (!check_lseek(fd, (off64_t) src.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000327 return -1;
328 }
329
Tao Bao0940fe12015-08-27 16:41:21 -0700330 size_t size = (src.pos[i * 2 + 1] - src.pos[i * 2]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000331
Tao Bao612336d2015-08-27 16:41:21 -0700332 if (read_all(fd, data + p, size) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000333 return -1;
334 }
335
336 p += size;
337 }
338
339 return 0;
340}
341
Tao Bao612336d2015-08-27 16:41:21 -0700342static int WriteBlocks(const RangeSet& tgt, const std::vector<uint8_t>& buffer, int fd) {
343 const uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000344
Tao Bao0940fe12015-08-27 16:41:21 -0700345 size_t p = 0;
346 for (size_t i = 0; i < tgt.count; ++i) {
347 if (!check_lseek(fd, (off64_t) tgt.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000348 return -1;
349 }
350
Tao Bao0940fe12015-08-27 16:41:21 -0700351 size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000352
Tao Bao612336d2015-08-27 16:41:21 -0700353 if (write_all(fd, data + p, size) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000354 return -1;
355 }
356
357 p += size;
358 }
359
360 return 0;
361}
362
Doug Zongker52ae67d2014-09-08 12:22:09 -0700363// Do a source/target load for move/bsdiff/imgdiff in version 1.
364// 'wordsave' is the save_ptr of a strtok_r()-in-progress. We expect
365// to parse the remainder of the string as:
366//
367// <src_range> <tgt_range>
368//
369// The source range is loaded into the provided buffer, reallocating
Tao Bao34847b22015-09-08 11:05:49 -0700370// it to make it larger if necessary.
Doug Zongker52ae67d2014-09-08 12:22:09 -0700371
Tao Bao34847b22015-09-08 11:05:49 -0700372static int LoadSrcTgtVersion1(char** wordsave, RangeSet& tgt, size_t& src_blocks,
Tao Bao612336d2015-08-27 16:41:21 -0700373 std::vector<uint8_t>& buffer, int fd) {
374 // <src_range>
Tao Bao0940fe12015-08-27 16:41:21 -0700375 char* word = strtok_r(nullptr, " ", wordsave);
376 RangeSet src;
377 parse_range(word, src);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700378
Tao Bao612336d2015-08-27 16:41:21 -0700379 // <tgt_range>
Tao Bao34847b22015-09-08 11:05:49 -0700380 word = strtok_r(nullptr, " ", wordsave);
381 parse_range(word, tgt);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700382
Tao Bao612336d2015-08-27 16:41:21 -0700383 allocate(src.size * BLOCKSIZE, buffer);
384 int rc = ReadBlocks(src, buffer, fd);
Tao Bao0940fe12015-08-27 16:41:21 -0700385 src_blocks = src.size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000386
Sami Tolvanen90221202014-12-09 16:39:47 +0000387 return rc;
388}
389
Tao Bao612336d2015-08-27 16:41:21 -0700390static int VerifyBlocks(const std::string& expected, const std::vector<uint8_t>& buffer,
Tao Bao0940fe12015-08-27 16:41:21 -0700391 const size_t blocks, bool printerror) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000392 uint8_t digest[SHA_DIGEST_SIZE];
Tao Bao612336d2015-08-27 16:41:21 -0700393 const uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000394
Tao Bao612336d2015-08-27 16:41:21 -0700395 SHA_hash(data, blocks * BLOCKSIZE, digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000396
Tao Baoe6aa3322015-08-05 15:20:27 -0700397 std::string hexdigest = print_sha1(digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000398
Tao Bao0940fe12015-08-27 16:41:21 -0700399 if (hexdigest != expected) {
400 if (printerror) {
401 fprintf(stderr, "failed to verify blocks (expected %s, read %s)\n",
402 expected.c_str(), hexdigest.c_str());
403 }
404 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000405 }
406
Tao Bao0940fe12015-08-27 16:41:21 -0700407 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000408}
409
Tao Bao0940fe12015-08-27 16:41:21 -0700410static std::string GetStashFileName(const std::string& base, const std::string& id,
411 const std::string& postfix) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700412 if (base.empty()) {
413 return "";
Sami Tolvanen90221202014-12-09 16:39:47 +0000414 }
415
Tao Baoe6aa3322015-08-05 15:20:27 -0700416 std::string fn(STASH_DIRECTORY_BASE);
417 fn += "/" + base + "/" + id + postfix;
Sami Tolvanen90221202014-12-09 16:39:47 +0000418
419 return fn;
420}
421
Tao Baoe6aa3322015-08-05 15:20:27 -0700422typedef void (*StashCallback)(const std::string&, void*);
Sami Tolvanen90221202014-12-09 16:39:47 +0000423
424// Does a best effort enumeration of stash files. Ignores possible non-file
425// items in the stash directory and continues despite of errors. Calls the
426// 'callback' function for each file and passes 'data' to the function as a
427// parameter.
428
Tao Baoe6aa3322015-08-05 15:20:27 -0700429static void EnumerateStash(const std::string& dirname, StashCallback callback, void* data) {
Tao Bao0940fe12015-08-27 16:41:21 -0700430 if (dirname.empty() || callback == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000431 return;
432 }
433
Tao Baoe6aa3322015-08-05 15:20:27 -0700434 std::unique_ptr<DIR, int(*)(DIR*)> directory(opendir(dirname.c_str()), closedir);
Sami Tolvanen90221202014-12-09 16:39:47 +0000435
Tao Bao0940fe12015-08-27 16:41:21 -0700436 if (directory == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000437 if (errno != ENOENT) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700438 fprintf(stderr, "opendir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000439 }
440 return;
441 }
442
Tao Baoe6aa3322015-08-05 15:20:27 -0700443 struct dirent* item;
Tao Bao0940fe12015-08-27 16:41:21 -0700444 while ((item = readdir(directory.get())) != nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000445 if (item->d_type != DT_REG) {
446 continue;
447 }
448
Tao Baoe6aa3322015-08-05 15:20:27 -0700449 std::string fn = dirname + "/" + std::string(item->d_name);
Sami Tolvanen90221202014-12-09 16:39:47 +0000450 callback(fn, data);
Sami Tolvanen90221202014-12-09 16:39:47 +0000451 }
452}
453
Tao Baoe6aa3322015-08-05 15:20:27 -0700454static void UpdateFileSize(const std::string& fn, void* data) {
455 if (fn.empty() || !data) {
456 return;
457 }
458
Tao Bao0940fe12015-08-27 16:41:21 -0700459 struct stat sb;
460 if (stat(fn.c_str(), &sb) == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700461 fprintf(stderr, "stat \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000462 return;
463 }
464
Tao Baoe6aa3322015-08-05 15:20:27 -0700465 int* size = reinterpret_cast<int*>(data);
Tao Bao0940fe12015-08-27 16:41:21 -0700466 *size += sb.st_size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000467}
468
469// Deletes the stash directory and all files in it. Assumes that it only
470// contains files. There is nothing we can do about unlikely, but possible
471// errors, so they are merely logged.
472
Tao Bao0940fe12015-08-27 16:41:21 -0700473static void DeleteFile(const std::string& fn, void* /* data */) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700474 if (!fn.empty()) {
475 fprintf(stderr, "deleting %s\n", fn.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000476
Tao Baoe6aa3322015-08-05 15:20:27 -0700477 if (unlink(fn.c_str()) == -1 && errno != ENOENT) {
478 fprintf(stderr, "unlink \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000479 }
480 }
481}
482
Tao Baoe6aa3322015-08-05 15:20:27 -0700483static void DeletePartial(const std::string& fn, void* data) {
484 if (android::base::EndsWith(fn, ".partial")) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000485 DeleteFile(fn, data);
486 }
487}
488
Tao Baoe6aa3322015-08-05 15:20:27 -0700489static void DeleteStash(const std::string& base) {
490 if (base.empty()) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000491 return;
492 }
493
Tao Baoe6aa3322015-08-05 15:20:27 -0700494 fprintf(stderr, "deleting stash %s\n", base.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000495
Tao Baoe6aa3322015-08-05 15:20:27 -0700496 std::string dirname = GetStashFileName(base, "", "");
Tao Bao0940fe12015-08-27 16:41:21 -0700497 EnumerateStash(dirname, DeleteFile, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +0000498
Tao Baoe6aa3322015-08-05 15:20:27 -0700499 if (rmdir(dirname.c_str()) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000500 if (errno != ENOENT && errno != ENOTDIR) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700501 fprintf(stderr, "rmdir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000502 }
503 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000504}
505
Tao Bao0940fe12015-08-27 16:41:21 -0700506static int LoadStash(const std::string& base, const std::string& id, bool verify, size_t* blocks,
Tao Bao612336d2015-08-27 16:41:21 -0700507 std::vector<uint8_t>& buffer, bool printnoent) {
508 if (base.empty()) {
Tao Bao0940fe12015-08-27 16:41:21 -0700509 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000510 }
511
Tao Bao0940fe12015-08-27 16:41:21 -0700512 size_t blockcount = 0;
513
Sami Tolvanen90221202014-12-09 16:39:47 +0000514 if (!blocks) {
515 blocks = &blockcount;
516 }
517
Tao Bao0940fe12015-08-27 16:41:21 -0700518 std::string fn = GetStashFileName(base, id, "");
Sami Tolvanen90221202014-12-09 16:39:47 +0000519
Tao Bao0940fe12015-08-27 16:41:21 -0700520 struct stat sb;
521 int res = stat(fn.c_str(), &sb);
Sami Tolvanen90221202014-12-09 16:39:47 +0000522
523 if (res == -1) {
524 if (errno != ENOENT || printnoent) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700525 fprintf(stderr, "stat \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000526 }
Tao Bao0940fe12015-08-27 16:41:21 -0700527 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000528 }
529
Tao Baoe6aa3322015-08-05 15:20:27 -0700530 fprintf(stderr, " loading %s\n", fn.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000531
Tao Bao0940fe12015-08-27 16:41:21 -0700532 if ((sb.st_size % BLOCKSIZE) != 0) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700533 fprintf(stderr, "%s size %" PRId64 " not multiple of block size %d",
Tao Bao0940fe12015-08-27 16:41:21 -0700534 fn.c_str(), static_cast<int64_t>(sb.st_size), BLOCKSIZE);
535 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000536 }
537
Tao Bao0940fe12015-08-27 16:41:21 -0700538 int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY));
539 unique_fd fd_holder(fd);
Sami Tolvanen90221202014-12-09 16:39:47 +0000540
541 if (fd == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700542 fprintf(stderr, "open \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700543 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000544 }
545
Tao Bao612336d2015-08-27 16:41:21 -0700546 allocate(sb.st_size, buffer);
Sami Tolvanen90221202014-12-09 16:39:47 +0000547
Tao Bao612336d2015-08-27 16:41:21 -0700548 if (read_all(fd, buffer, sb.st_size) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700549 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000550 }
551
Tao Bao0940fe12015-08-27 16:41:21 -0700552 *blocks = sb.st_size / BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000553
Tao Bao612336d2015-08-27 16:41:21 -0700554 if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700555 fprintf(stderr, "unexpected contents in %s\n", fn.c_str());
Tao Bao0940fe12015-08-27 16:41:21 -0700556 DeleteFile(fn, nullptr);
557 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000558 }
559
Tao Bao0940fe12015-08-27 16:41:21 -0700560 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000561}
562
Tao Bao612336d2015-08-27 16:41:21 -0700563static int WriteStash(const std::string& base, const std::string& id, int blocks,
564 std::vector<uint8_t>& buffer, bool checkspace, bool *exists) {
565 if (base.empty()) {
Tao Bao0940fe12015-08-27 16:41:21 -0700566 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000567 }
568
569 if (checkspace && CacheSizeCheck(blocks * BLOCKSIZE) != 0) {
570 fprintf(stderr, "not enough space to write stash\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700571 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000572 }
573
Tao Bao0940fe12015-08-27 16:41:21 -0700574 std::string fn = GetStashFileName(base, id, ".partial");
575 std::string cn = GetStashFileName(base, id, "");
Sami Tolvanen90221202014-12-09 16:39:47 +0000576
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100577 if (exists) {
Tao Bao0940fe12015-08-27 16:41:21 -0700578 struct stat sb;
579 int res = stat(cn.c_str(), &sb);
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100580
581 if (res == 0) {
582 // The file already exists and since the name is the hash of the contents,
583 // it's safe to assume the contents are identical (accidental hash collisions
584 // are unlikely)
Tao Baoe6aa3322015-08-05 15:20:27 -0700585 fprintf(stderr, " skipping %d existing blocks in %s\n", blocks, cn.c_str());
Tao Bao0940fe12015-08-27 16:41:21 -0700586 *exists = true;
587 return 0;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100588 }
589
Tao Bao0940fe12015-08-27 16:41:21 -0700590 *exists = false;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100591 }
592
Tao Baoe6aa3322015-08-05 15:20:27 -0700593 fprintf(stderr, " writing %d blocks to %s\n", blocks, cn.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000594
Tao Bao0940fe12015-08-27 16:41:21 -0700595 int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE));
596 unique_fd fd_holder(fd);
Sami Tolvanen90221202014-12-09 16:39:47 +0000597
598 if (fd == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700599 fprintf(stderr, "failed to create \"%s\": %s\n", fn.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700600 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000601 }
602
603 if (write_all(fd, buffer, blocks * BLOCKSIZE) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700604 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000605 }
606
607 if (fsync(fd) == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700608 fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700609 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000610 }
611
Tao Baoe6aa3322015-08-05 15:20:27 -0700612 if (rename(fn.c_str(), cn.c_str()) == -1) {
613 fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", fn.c_str(), cn.c_str(),
614 strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700615 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000616 }
617
Tao Bao0940fe12015-08-27 16:41:21 -0700618 std::string dname = GetStashFileName(base, "", "");
619 int dfd = TEMP_FAILURE_RETRY(open(dname.c_str(), O_RDONLY | O_DIRECTORY));
620 unique_fd dfd_holder(dfd);
Tao Baodc392262015-07-31 15:56:44 -0700621
622 if (dfd == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700623 fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700624 return -1;
Tao Baodc392262015-07-31 15:56:44 -0700625 }
626
627 if (fsync(dfd) == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700628 fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700629 return -1;
Tao Baodc392262015-07-31 15:56:44 -0700630 }
631
Tao Bao0940fe12015-08-27 16:41:21 -0700632 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000633}
634
635// Creates a directory for storing stash files and checks if the /cache partition
636// hash enough space for the expected amount of blocks we need to store. Returns
637// >0 if we created the directory, zero if it existed already, and <0 of failure.
638
Tao Bao0940fe12015-08-27 16:41:21 -0700639static int CreateStash(State* state, int maxblocks, const char* blockdev, std::string& base) {
640 if (blockdev == nullptr) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700641 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000642 }
643
644 // Stash directory should be different for each partition to avoid conflicts
645 // when updating multiple partitions at the same time, so we use the hash of
646 // the block device name as the base directory
Tao Baoe6aa3322015-08-05 15:20:27 -0700647 SHA_CTX ctx;
Sami Tolvanen90221202014-12-09 16:39:47 +0000648 SHA_init(&ctx);
649 SHA_update(&ctx, blockdev, strlen(blockdev));
Tao Baoe6aa3322015-08-05 15:20:27 -0700650 const uint8_t* digest = SHA_final(&ctx);
651 base = print_sha1(digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000652
Tao Baoe6aa3322015-08-05 15:20:27 -0700653 std::string dirname = GetStashFileName(base, "", "");
Tao Bao0940fe12015-08-27 16:41:21 -0700654 struct stat sb;
655 int res = stat(dirname.c_str(), &sb);
Sami Tolvanen90221202014-12-09 16:39:47 +0000656
657 if (res == -1 && errno != ENOENT) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700658 ErrorAbort(state, "stat \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
659 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000660 } else if (res != 0) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700661 fprintf(stderr, "creating stash %s\n", dirname.c_str());
662 res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE);
Sami Tolvanen90221202014-12-09 16:39:47 +0000663
664 if (res != 0) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700665 ErrorAbort(state, "mkdir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
666 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000667 }
668
669 if (CacheSizeCheck(maxblocks * BLOCKSIZE) != 0) {
670 ErrorAbort(state, "not enough space for stash\n");
Tao Baoe6aa3322015-08-05 15:20:27 -0700671 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000672 }
673
Tao Baoe6aa3322015-08-05 15:20:27 -0700674 return 1; // Created directory
Sami Tolvanen90221202014-12-09 16:39:47 +0000675 }
676
Tao Baoe6aa3322015-08-05 15:20:27 -0700677 fprintf(stderr, "using existing stash %s\n", dirname.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000678
679 // If the directory already exists, calculate the space already allocated to
680 // stash files and check if there's enough for all required blocks. Delete any
681 // partially completed stash files first.
682
Tao Bao0940fe12015-08-27 16:41:21 -0700683 EnumerateStash(dirname, DeletePartial, nullptr);
Tao Baoe6aa3322015-08-05 15:20:27 -0700684 int size = 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000685 EnumerateStash(dirname, UpdateFileSize, &size);
686
Tao Bao0940fe12015-08-27 16:41:21 -0700687 size = maxblocks * BLOCKSIZE - size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000688
689 if (size > 0 && CacheSizeCheck(size) != 0) {
690 ErrorAbort(state, "not enough space for stash (%d more needed)\n", size);
Tao Baoe6aa3322015-08-05 15:20:27 -0700691 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000692 }
693
Tao Baoe6aa3322015-08-05 15:20:27 -0700694 return 0; // Using existing directory
Sami Tolvanen90221202014-12-09 16:39:47 +0000695}
696
Tao Bao612336d2015-08-27 16:41:21 -0700697static int SaveStash(const std::string& base, char** wordsave, std::vector<uint8_t>& buffer,
698 int fd, bool usehash) {
699 if (!wordsave) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000700 return -1;
701 }
702
Tao Bao0940fe12015-08-27 16:41:21 -0700703 char *id_tok = strtok_r(nullptr, " ", wordsave);
704 if (id_tok == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000705 fprintf(stderr, "missing id field in stash command\n");
706 return -1;
707 }
Tao Bao0940fe12015-08-27 16:41:21 -0700708 std::string id(id_tok);
Sami Tolvanen90221202014-12-09 16:39:47 +0000709
Tao Bao0940fe12015-08-27 16:41:21 -0700710 size_t blocks = 0;
Tao Bao612336d2015-08-27 16:41:21 -0700711 if (usehash && LoadStash(base, id, true, &blocks, buffer, false) == 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000712 // Stash file already exists and has expected contents. Do not
713 // read from source again, as the source may have been already
714 // overwritten during a previous attempt.
715 return 0;
716 }
717
Tao Bao34847b22015-09-08 11:05:49 -0700718 char* word = strtok_r(nullptr, " ", wordsave);
719 RangeSet src;
720 parse_range(word, src);
721
Tao Bao612336d2015-08-27 16:41:21 -0700722 allocate(src.size * BLOCKSIZE, buffer);
723 if (ReadBlocks(src, buffer, fd) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000724 return -1;
725 }
Tao Bao34847b22015-09-08 11:05:49 -0700726 blocks = src.size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000727
Tao Bao612336d2015-08-27 16:41:21 -0700728 if (usehash && VerifyBlocks(id, buffer, blocks, true) != 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000729 // Source blocks have unexpected contents. If we actually need this
730 // data later, this is an unrecoverable error. However, the command
731 // that uses the data may have already completed previously, so the
732 // possible failure will occur during source block verification.
Tao Bao0940fe12015-08-27 16:41:21 -0700733 fprintf(stderr, "failed to load source blocks for stash %s\n", id.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000734 return 0;
735 }
736
Tao Bao0940fe12015-08-27 16:41:21 -0700737 fprintf(stderr, "stashing %zu blocks to %s\n", blocks, id.c_str());
Tao Bao612336d2015-08-27 16:41:21 -0700738 return WriteStash(base, id, blocks, buffer, false, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +0000739}
740
Tao Baoe6aa3322015-08-05 15:20:27 -0700741static int FreeStash(const std::string& base, const char* id) {
Tao Bao0940fe12015-08-27 16:41:21 -0700742 if (base.empty() || id == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000743 return -1;
744 }
745
Tao Baoe6aa3322015-08-05 15:20:27 -0700746 std::string fn = GetStashFileName(base, std::string(id), "");
Sami Tolvanen90221202014-12-09 16:39:47 +0000747
Tao Bao0940fe12015-08-27 16:41:21 -0700748 DeleteFile(fn, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +0000749
750 return 0;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700751}
752
Tao Bao612336d2015-08-27 16:41:21 -0700753static void MoveRange(std::vector<uint8_t>& dest, const RangeSet& locs,
754 const std::vector<uint8_t>& source) {
Doug Zongker52ae67d2014-09-08 12:22:09 -0700755 // source contains packed data, which we want to move to the
Tao Bao612336d2015-08-27 16:41:21 -0700756 // locations given in locs in the dest buffer. source and dest
Doug Zongker52ae67d2014-09-08 12:22:09 -0700757 // may be the same buffer.
758
Tao Bao612336d2015-08-27 16:41:21 -0700759 const uint8_t* from = source.data();
760 uint8_t* to = dest.data();
Tao Bao0940fe12015-08-27 16:41:21 -0700761 size_t start = locs.size;
762 for (int i = locs.count-1; i >= 0; --i) {
763 size_t blocks = locs.pos[i*2+1] - locs.pos[i*2];
Doug Zongker52ae67d2014-09-08 12:22:09 -0700764 start -= blocks;
Tao Bao612336d2015-08-27 16:41:21 -0700765 memmove(to + (locs.pos[i*2] * BLOCKSIZE), from + (start * BLOCKSIZE),
Doug Zongker52ae67d2014-09-08 12:22:09 -0700766 blocks * BLOCKSIZE);
767 }
768}
769
770// Do a source/target load for move/bsdiff/imgdiff in version 2.
771// 'wordsave' is the save_ptr of a strtok_r()-in-progress. We expect
772// to parse the remainder of the string as one of:
773//
774// <tgt_range> <src_block_count> <src_range>
775// (loads data from source image only)
776//
777// <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
778// (loads data from stashes only)
779//
780// <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
781// (loads data from both source image and stashes)
782//
783// On return, buffer is filled with the loaded source data (rearranged
784// and combined with stashed data as necessary). buffer may be
785// reallocated if needed to accommodate the source data. *tgt is the
Sami Tolvanen90221202014-12-09 16:39:47 +0000786// target RangeSet. Any stashes required are loaded using LoadStash.
Doug Zongker52ae67d2014-09-08 12:22:09 -0700787
Tao Bao612336d2015-08-27 16:41:21 -0700788static int LoadSrcTgtVersion2(char** wordsave, RangeSet& tgt, size_t& src_blocks,
789 std::vector<uint8_t>& buffer, int fd, const std::string& stashbase, bool* overlap) {
790 // <tgt_range>
791 char* word = strtok_r(nullptr, " ", wordsave);
Tao Bao34847b22015-09-08 11:05:49 -0700792 parse_range(word, tgt);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700793
Tao Bao612336d2015-08-27 16:41:21 -0700794 // <src_block_count>
Tao Bao0940fe12015-08-27 16:41:21 -0700795 word = strtok_r(nullptr, " ", wordsave);
Tao Baob15fd222015-09-24 11:10:51 -0700796 android::base::ParseUint(word, &src_blocks);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700797
Tao Bao612336d2015-08-27 16:41:21 -0700798 allocate(src_blocks * BLOCKSIZE, buffer);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700799
Tao Bao612336d2015-08-27 16:41:21 -0700800 // "-" or <src_range> [<src_loc>]
Tao Bao0940fe12015-08-27 16:41:21 -0700801 word = strtok_r(nullptr, " ", wordsave);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700802 if (word[0] == '-' && word[1] == '\0') {
803 // no source ranges, only stashes
804 } else {
Tao Bao0940fe12015-08-27 16:41:21 -0700805 RangeSet src;
806 parse_range(word, src);
Tao Bao612336d2015-08-27 16:41:21 -0700807 int res = ReadBlocks(src, buffer, fd);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700808
Tao Bao34847b22015-09-08 11:05:49 -0700809 if (overlap) {
810 *overlap = range_overlaps(src, tgt);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700811 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000812
Sami Tolvanen90221202014-12-09 16:39:47 +0000813 if (res == -1) {
814 return -1;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700815 }
816
Tao Bao0940fe12015-08-27 16:41:21 -0700817 word = strtok_r(nullptr, " ", wordsave);
818 if (word == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000819 // no stashes, only source range
820 return 0;
821 }
822
Tao Bao612336d2015-08-27 16:41:21 -0700823 RangeSet locs;
Tao Bao0940fe12015-08-27 16:41:21 -0700824 parse_range(word, locs);
Tao Bao612336d2015-08-27 16:41:21 -0700825 MoveRange(buffer, locs, buffer);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700826 }
827
Tao Bao612336d2015-08-27 16:41:21 -0700828 // <[stash_id:stash-range]>
829 char* colonsave;
Tao Bao0940fe12015-08-27 16:41:21 -0700830 while ((word = strtok_r(nullptr, " ", wordsave)) != nullptr) {
Doug Zongker52ae67d2014-09-08 12:22:09 -0700831 // Each word is a an index into the stash table, a colon, and
832 // then a rangeset describing where in the source block that
833 // stashed data should go.
Tao Bao0940fe12015-08-27 16:41:21 -0700834 colonsave = nullptr;
Tao Bao612336d2015-08-27 16:41:21 -0700835 char* colon = strtok_r(word, ":", &colonsave);
Sami Tolvanen90221202014-12-09 16:39:47 +0000836
Tao Bao612336d2015-08-27 16:41:21 -0700837 std::vector<uint8_t> stash;
838 int res = LoadStash(stashbase, std::string(colon), false, nullptr, stash, true);
Sami Tolvanen90221202014-12-09 16:39:47 +0000839
840 if (res == -1) {
841 // These source blocks will fail verification if used later, but we
842 // will let the caller decide if this is a fatal failure
843 fprintf(stderr, "failed to load stash %s\n", colon);
844 continue;
845 }
846
Tao Bao0940fe12015-08-27 16:41:21 -0700847 colon = strtok_r(nullptr, ":", &colonsave);
Tao Bao612336d2015-08-27 16:41:21 -0700848 RangeSet locs;
Tao Bao0940fe12015-08-27 16:41:21 -0700849 parse_range(colon, locs);
Sami Tolvanen90221202014-12-09 16:39:47 +0000850
Tao Bao612336d2015-08-27 16:41:21 -0700851 MoveRange(buffer, locs, stash);
Sami Tolvanen90221202014-12-09 16:39:47 +0000852 }
853
854 return 0;
855}
856
857// Parameters for transfer list command functions
Tao Bao0940fe12015-08-27 16:41:21 -0700858struct CommandParameters {
Sami Tolvanen90221202014-12-09 16:39:47 +0000859 char* cmdname;
860 char* cpos;
861 char* freestash;
Tao Baoe6aa3322015-08-05 15:20:27 -0700862 std::string stashbase;
863 bool canwrite;
Sami Tolvanen90221202014-12-09 16:39:47 +0000864 int createdstash;
865 int fd;
Tao Bao0940fe12015-08-27 16:41:21 -0700866 bool foundwrites;
Tao Baoe6aa3322015-08-05 15:20:27 -0700867 bool isunresumable;
Sami Tolvanen90221202014-12-09 16:39:47 +0000868 int version;
Tao Bao0940fe12015-08-27 16:41:21 -0700869 size_t written;
Sami Tolvanen90221202014-12-09 16:39:47 +0000870 NewThreadInfo nti;
871 pthread_t thread;
Tao Bao612336d2015-08-27 16:41:21 -0700872 std::vector<uint8_t> buffer;
Sami Tolvanen90221202014-12-09 16:39:47 +0000873 uint8_t* patch_start;
Tao Bao0940fe12015-08-27 16:41:21 -0700874};
Sami Tolvanen90221202014-12-09 16:39:47 +0000875
876// Do a source/target load for move/bsdiff/imgdiff in version 3.
877//
878// Parameters are the same as for LoadSrcTgtVersion2, except for 'onehash', which
879// tells the function whether to expect separate source and targe block hashes, or
880// if they are both the same and only one hash should be expected, and
881// 'isunresumable', which receives a non-zero value if block verification fails in
882// a way that the update cannot be resumed anymore.
883//
884// If the function is unable to load the necessary blocks or their contents don't
885// match the hashes, the return value is -1 and the command should be aborted.
886//
887// If the return value is 1, the command has already been completed according to
888// the contents of the target blocks, and should not be performed again.
889//
890// If the return value is 0, source blocks have expected content and the command
891// can be performed.
892
Tao Bao34847b22015-09-08 11:05:49 -0700893static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
Tao Bao0940fe12015-08-27 16:41:21 -0700894 bool onehash, bool& overlap) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000895
Tao Bao0940fe12015-08-27 16:41:21 -0700896 char* srchash = strtok_r(nullptr, " ", &params.cpos);
897 if (srchash == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000898 fprintf(stderr, "missing source hash\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700899 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000900 }
901
Tao Bao0940fe12015-08-27 16:41:21 -0700902 char* tgthash = nullptr;
Sami Tolvanen90221202014-12-09 16:39:47 +0000903 if (onehash) {
904 tgthash = srchash;
905 } else {
Tao Bao0940fe12015-08-27 16:41:21 -0700906 tgthash = strtok_r(nullptr, " ", &params.cpos);
Sami Tolvanen90221202014-12-09 16:39:47 +0000907
Tao Bao0940fe12015-08-27 16:41:21 -0700908 if (tgthash == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000909 fprintf(stderr, "missing target hash\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700910 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000911 }
912 }
913
Tao Bao612336d2015-08-27 16:41:21 -0700914 if (LoadSrcTgtVersion2(&params.cpos, tgt, src_blocks, params.buffer, params.fd,
915 params.stashbase, &overlap) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700916 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000917 }
918
Tao Bao34847b22015-09-08 11:05:49 -0700919 std::vector<uint8_t> tgtbuffer(tgt.size * BLOCKSIZE);
Sami Tolvanen90221202014-12-09 16:39:47 +0000920
Tao Bao612336d2015-08-27 16:41:21 -0700921 if (ReadBlocks(tgt, tgtbuffer, params.fd) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700922 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000923 }
924
Tao Bao612336d2015-08-27 16:41:21 -0700925 if (VerifyBlocks(tgthash, tgtbuffer, tgt.size, false) == 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000926 // Target blocks already have expected content, command should be skipped
Tao Bao0940fe12015-08-27 16:41:21 -0700927 return 1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000928 }
929
Tao Bao0940fe12015-08-27 16:41:21 -0700930 if (VerifyBlocks(srchash, params.buffer, src_blocks, true) == 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000931 // If source and target blocks overlap, stash the source blocks so we can
932 // resume from possible write errors
Tao Bao0940fe12015-08-27 16:41:21 -0700933 if (overlap) {
934 fprintf(stderr, "stashing %zu overlapping blocks to %s\n", src_blocks, srchash);
Sami Tolvanen90221202014-12-09 16:39:47 +0000935
Tao Bao0940fe12015-08-27 16:41:21 -0700936 bool stash_exists = false;
Tao Bao612336d2015-08-27 16:41:21 -0700937 if (WriteStash(params.stashbase, srchash, src_blocks, params.buffer, true,
Tao Bao0940fe12015-08-27 16:41:21 -0700938 &stash_exists) != 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000939 fprintf(stderr, "failed to stash overlapping source blocks\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700940 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000941 }
942
943 // Can be deleted when the write has completed
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100944 if (!stash_exists) {
Tao Bao0940fe12015-08-27 16:41:21 -0700945 params.freestash = srchash;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100946 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000947 }
948
949 // Source blocks have expected content, command can proceed
Tao Bao0940fe12015-08-27 16:41:21 -0700950 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000951 }
952
Tao Bao612336d2015-08-27 16:41:21 -0700953 if (overlap && LoadStash(params.stashbase, srchash, true, nullptr, params.buffer, true) == 0) {
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100954 // Overlapping source blocks were previously stashed, command can proceed.
955 // We are recovering from an interrupted command, so we don't know if the
956 // stash can safely be deleted after this command.
Tao Bao0940fe12015-08-27 16:41:21 -0700957 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000958 }
959
960 // Valid source data not available, update cannot be resumed
961 fprintf(stderr, "partition has unexpected contents\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700962 params.isunresumable = true;
Sami Tolvanen90221202014-12-09 16:39:47 +0000963
Tao Bao0940fe12015-08-27 16:41:21 -0700964 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000965}
966
Tao Bao0940fe12015-08-27 16:41:21 -0700967static int PerformCommandMove(CommandParameters& params) {
968 size_t blocks = 0;
Tao Baoe6aa3322015-08-05 15:20:27 -0700969 bool overlap = false;
Sami Tolvanen90221202014-12-09 16:39:47 +0000970 int status = 0;
Tao Bao0940fe12015-08-27 16:41:21 -0700971 RangeSet tgt;
Sami Tolvanen90221202014-12-09 16:39:47 +0000972
Tao Bao0940fe12015-08-27 16:41:21 -0700973 if (params.version == 1) {
Tao Bao612336d2015-08-27 16:41:21 -0700974 status = LoadSrcTgtVersion1(&params.cpos, tgt, blocks, params.buffer, params.fd);
Tao Bao0940fe12015-08-27 16:41:21 -0700975 } else if (params.version == 2) {
Tao Bao612336d2015-08-27 16:41:21 -0700976 status = LoadSrcTgtVersion2(&params.cpos, tgt, blocks, params.buffer, params.fd,
977 params.stashbase, nullptr);
Tao Bao0940fe12015-08-27 16:41:21 -0700978 } else if (params.version >= 3) {
Tao Bao34847b22015-09-08 11:05:49 -0700979 status = LoadSrcTgtVersion3(params, tgt, blocks, true, overlap);
Sami Tolvanen90221202014-12-09 16:39:47 +0000980 }
981
982 if (status == -1) {
983 fprintf(stderr, "failed to read blocks for move\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700984 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000985 }
986
987 if (status == 0) {
Tao Bao0940fe12015-08-27 16:41:21 -0700988 params.foundwrites = true;
989 } else if (params.foundwrites) {
990 fprintf(stderr, "warning: commands executed out of order [%s]\n", params.cmdname);
Sami Tolvanen90221202014-12-09 16:39:47 +0000991 }
992
Tao Bao0940fe12015-08-27 16:41:21 -0700993 if (params.canwrite) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000994 if (status == 0) {
Tao Bao0940fe12015-08-27 16:41:21 -0700995 fprintf(stderr, " moving %zu blocks\n", blocks);
Sami Tolvanen90221202014-12-09 16:39:47 +0000996
Tao Bao0940fe12015-08-27 16:41:21 -0700997 if (WriteBlocks(tgt, params.buffer, params.fd) == -1) {
998 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000999 }
1000 } else {
Tao Bao0940fe12015-08-27 16:41:21 -07001001 fprintf(stderr, "skipping %zu already moved blocks\n", blocks);
Sami Tolvanen90221202014-12-09 16:39:47 +00001002 }
1003
1004 }
1005
Tao Bao0940fe12015-08-27 16:41:21 -07001006 if (params.freestash) {
1007 FreeStash(params.stashbase, params.freestash);
1008 params.freestash = nullptr;
Sami Tolvanen90221202014-12-09 16:39:47 +00001009 }
1010
Tao Bao0940fe12015-08-27 16:41:21 -07001011 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001012
Tao Bao0940fe12015-08-27 16:41:21 -07001013 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001014}
1015
Tao Bao0940fe12015-08-27 16:41:21 -07001016static int PerformCommandStash(CommandParameters& params) {
Tao Bao612336d2015-08-27 16:41:21 -07001017 return SaveStash(params.stashbase, &params.cpos, params.buffer, params.fd,
1018 (params.version >= 3));
Sami Tolvanen90221202014-12-09 16:39:47 +00001019}
1020
Tao Bao0940fe12015-08-27 16:41:21 -07001021static int PerformCommandFree(CommandParameters& params) {
1022 if (params.createdstash || params.canwrite) {
1023 return FreeStash(params.stashbase, params.cpos);
Sami Tolvanen90221202014-12-09 16:39:47 +00001024 }
1025
1026 return 0;
1027}
1028
Tao Bao0940fe12015-08-27 16:41:21 -07001029static int PerformCommandZero(CommandParameters& params) {
1030 char* range = strtok_r(nullptr, " ", &params.cpos);
Sami Tolvanen90221202014-12-09 16:39:47 +00001031
Tao Bao0940fe12015-08-27 16:41:21 -07001032 if (range == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001033 fprintf(stderr, "missing target blocks for zero\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001034 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001035 }
1036
Tao Bao0940fe12015-08-27 16:41:21 -07001037 RangeSet tgt;
1038 parse_range(range, tgt);
Sami Tolvanen90221202014-12-09 16:39:47 +00001039
Tao Bao0940fe12015-08-27 16:41:21 -07001040 fprintf(stderr, " zeroing %zu blocks\n", tgt.size);
Sami Tolvanen90221202014-12-09 16:39:47 +00001041
Tao Bao612336d2015-08-27 16:41:21 -07001042 allocate(BLOCKSIZE, params.buffer);
1043 memset(params.buffer.data(), 0, BLOCKSIZE);
Sami Tolvanen90221202014-12-09 16:39:47 +00001044
Tao Bao0940fe12015-08-27 16:41:21 -07001045 if (params.canwrite) {
1046 for (size_t i = 0; i < tgt.count; ++i) {
1047 if (!check_lseek(params.fd, (off64_t) tgt.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
1048 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001049 }
1050
Tao Bao0940fe12015-08-27 16:41:21 -07001051 for (size_t j = tgt.pos[i * 2]; j < tgt.pos[i * 2 + 1]; ++j) {
1052 if (write_all(params.fd, params.buffer, BLOCKSIZE) == -1) {
1053 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001054 }
1055 }
1056 }
1057 }
1058
Tao Bao0940fe12015-08-27 16:41:21 -07001059 if (params.cmdname[0] == 'z') {
Sami Tolvanene82fa182015-06-10 15:58:12 +00001060 // Update only for the zero command, as the erase command will call
1061 // this if DEBUG_ERASE is defined.
Tao Bao0940fe12015-08-27 16:41:21 -07001062 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001063 }
1064
Tao Bao0940fe12015-08-27 16:41:21 -07001065 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001066}
1067
Tao Bao0940fe12015-08-27 16:41:21 -07001068static int PerformCommandNew(CommandParameters& params) {
1069 char* range = strtok_r(nullptr, " ", &params.cpos);
Sami Tolvanen90221202014-12-09 16:39:47 +00001070
Tao Bao0940fe12015-08-27 16:41:21 -07001071 if (range == nullptr) {
1072 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001073 }
1074
Tao Bao0940fe12015-08-27 16:41:21 -07001075 RangeSet tgt;
1076 parse_range(range, tgt);
Sami Tolvanen90221202014-12-09 16:39:47 +00001077
Tao Bao0940fe12015-08-27 16:41:21 -07001078 if (params.canwrite) {
1079 fprintf(stderr, " writing %zu blocks of new data\n", tgt.size);
Sami Tolvanen90221202014-12-09 16:39:47 +00001080
Tao Bao0940fe12015-08-27 16:41:21 -07001081 RangeSinkState rss(tgt);
1082 rss.fd = params.fd;
Sami Tolvanen90221202014-12-09 16:39:47 +00001083 rss.p_block = 0;
Tao Bao0940fe12015-08-27 16:41:21 -07001084 rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001085
Tao Bao0940fe12015-08-27 16:41:21 -07001086 if (!check_lseek(params.fd, (off64_t) tgt.pos[0] * BLOCKSIZE, SEEK_SET)) {
1087 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001088 }
1089
Tao Bao0940fe12015-08-27 16:41:21 -07001090 pthread_mutex_lock(&params.nti.mu);
1091 params.nti.rss = &rss;
1092 pthread_cond_broadcast(&params.nti.cv);
Sami Tolvanen90221202014-12-09 16:39:47 +00001093
Tao Bao0940fe12015-08-27 16:41:21 -07001094 while (params.nti.rss) {
1095 pthread_cond_wait(&params.nti.cv, &params.nti.mu);
Sami Tolvanen90221202014-12-09 16:39:47 +00001096 }
1097
Tao Bao0940fe12015-08-27 16:41:21 -07001098 pthread_mutex_unlock(&params.nti.mu);
Sami Tolvanen90221202014-12-09 16:39:47 +00001099 }
1100
Tao Bao0940fe12015-08-27 16:41:21 -07001101 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001102
Tao Bao0940fe12015-08-27 16:41:21 -07001103 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001104}
1105
Tao Bao0940fe12015-08-27 16:41:21 -07001106static int PerformCommandDiff(CommandParameters& params) {
Tao Bao0940fe12015-08-27 16:41:21 -07001107
1108 const std::string logparams(params.cpos);
Tao Bao612336d2015-08-27 16:41:21 -07001109 char* value = strtok_r(nullptr, " ", &params.cpos);
Tao Bao0940fe12015-08-27 16:41:21 -07001110
1111 if (value == nullptr) {
1112 fprintf(stderr, "missing patch offset for %s\n", params.cmdname);
1113 return -1;
1114 }
1115
1116 size_t offset = strtoul(value, nullptr, 0);
1117
1118 value = strtok_r(nullptr, " ", &params.cpos);
1119
1120 if (value == nullptr) {
1121 fprintf(stderr, "missing patch length for %s\n", params.cmdname);
1122 return -1;
1123 }
1124
1125 size_t len = strtoul(value, nullptr, 0);
1126
Tao Bao612336d2015-08-27 16:41:21 -07001127 RangeSet tgt;
Tao Bao0940fe12015-08-27 16:41:21 -07001128 size_t blocks = 0;
Tao Bao612336d2015-08-27 16:41:21 -07001129 bool overlap = false;
Sami Tolvanen90221202014-12-09 16:39:47 +00001130 int status = 0;
Tao Bao0940fe12015-08-27 16:41:21 -07001131 if (params.version == 1) {
Tao Bao612336d2015-08-27 16:41:21 -07001132 status = LoadSrcTgtVersion1(&params.cpos, tgt, blocks, params.buffer, params.fd);
Tao Bao0940fe12015-08-27 16:41:21 -07001133 } else if (params.version == 2) {
Tao Bao612336d2015-08-27 16:41:21 -07001134 status = LoadSrcTgtVersion2(&params.cpos, tgt, blocks, params.buffer, params.fd,
1135 params.stashbase, nullptr);
Tao Bao0940fe12015-08-27 16:41:21 -07001136 } else if (params.version >= 3) {
Tao Bao34847b22015-09-08 11:05:49 -07001137 status = LoadSrcTgtVersion3(params, tgt, blocks, false, overlap);
Sami Tolvanen90221202014-12-09 16:39:47 +00001138 }
1139
1140 if (status == -1) {
1141 fprintf(stderr, "failed to read blocks for diff\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001142 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001143 }
1144
1145 if (status == 0) {
Tao Bao0940fe12015-08-27 16:41:21 -07001146 params.foundwrites = true;
1147 } else if (params.foundwrites) {
1148 fprintf(stderr, "warning: commands executed out of order [%s]\n", params.cmdname);
Sami Tolvanen90221202014-12-09 16:39:47 +00001149 }
1150
Tao Bao0940fe12015-08-27 16:41:21 -07001151 if (params.canwrite) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001152 if (status == 0) {
Tao Bao0940fe12015-08-27 16:41:21 -07001153 fprintf(stderr, "patching %zu blocks to %zu\n", blocks, tgt.size);
Sami Tolvanen90221202014-12-09 16:39:47 +00001154
Tao Bao0940fe12015-08-27 16:41:21 -07001155 Value patch_value;
Sami Tolvanen90221202014-12-09 16:39:47 +00001156 patch_value.type = VAL_BLOB;
1157 patch_value.size = len;
Tao Bao0940fe12015-08-27 16:41:21 -07001158 patch_value.data = (char*) (params.patch_start + offset);
Sami Tolvanen90221202014-12-09 16:39:47 +00001159
Tao Bao0940fe12015-08-27 16:41:21 -07001160 RangeSinkState rss(tgt);
1161 rss.fd = params.fd;
Sami Tolvanen90221202014-12-09 16:39:47 +00001162 rss.p_block = 0;
Tao Bao0940fe12015-08-27 16:41:21 -07001163 rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001164
Tao Bao0940fe12015-08-27 16:41:21 -07001165 if (!check_lseek(params.fd, (off64_t) tgt.pos[0] * BLOCKSIZE, SEEK_SET)) {
1166 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001167 }
1168
Tao Bao0940fe12015-08-27 16:41:21 -07001169 if (params.cmdname[0] == 'i') { // imgdiff
Tao Bao612336d2015-08-27 16:41:21 -07001170 ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value,
Tao Bao0940fe12015-08-27 16:41:21 -07001171 &RangeSinkWrite, &rss, nullptr, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +00001172 } else {
Tao Bao612336d2015-08-27 16:41:21 -07001173 ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, 0,
1174 &RangeSinkWrite, &rss, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +00001175 }
1176
1177 // We expect the output of the patcher to fill the tgt ranges exactly.
Tao Bao0940fe12015-08-27 16:41:21 -07001178 if (rss.p_block != tgt.count || rss.p_remain != 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001179 fprintf(stderr, "range sink underrun?\n");
1180 }
1181 } else {
Tao Bao0940fe12015-08-27 16:41:21 -07001182 fprintf(stderr, "skipping %zu blocks already patched to %zu [%s]\n",
1183 blocks, tgt.size, logparams.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +00001184 }
1185 }
1186
Tao Bao0940fe12015-08-27 16:41:21 -07001187 if (params.freestash) {
1188 FreeStash(params.stashbase, params.freestash);
1189 params.freestash = nullptr;
Sami Tolvanen90221202014-12-09 16:39:47 +00001190 }
1191
Tao Bao0940fe12015-08-27 16:41:21 -07001192 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001193
Tao Bao0940fe12015-08-27 16:41:21 -07001194 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001195}
1196
Tao Bao0940fe12015-08-27 16:41:21 -07001197static int PerformCommandErase(CommandParameters& params) {
Sami Tolvanene82fa182015-06-10 15:58:12 +00001198 if (DEBUG_ERASE) {
1199 return PerformCommandZero(params);
Sami Tolvanen90221202014-12-09 16:39:47 +00001200 }
1201
Tao Bao0940fe12015-08-27 16:41:21 -07001202 struct stat sb;
1203 if (fstat(params.fd, &sb) == -1) {
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001204 fprintf(stderr, "failed to fstat device to erase: %s\n", strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -07001205 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001206 }
1207
Tao Bao0940fe12015-08-27 16:41:21 -07001208 if (!S_ISBLK(sb.st_mode)) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001209 fprintf(stderr, "not a block device; skipping erase\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001210 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001211 }
1212
Tao Bao0940fe12015-08-27 16:41:21 -07001213 char* range = strtok_r(nullptr, " ", &params.cpos);
Sami Tolvanen90221202014-12-09 16:39:47 +00001214
Tao Bao0940fe12015-08-27 16:41:21 -07001215 if (range == nullptr) {
Tao Baoba9a42a2015-06-23 23:23:33 -07001216 fprintf(stderr, "missing target blocks for erase\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001217 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001218 }
1219
Tao Bao0940fe12015-08-27 16:41:21 -07001220 RangeSet tgt;
1221 parse_range(range, tgt);
Sami Tolvanen90221202014-12-09 16:39:47 +00001222
Tao Bao0940fe12015-08-27 16:41:21 -07001223 if (params.canwrite) {
1224 fprintf(stderr, " erasing %zu blocks\n", tgt.size);
Sami Tolvanen90221202014-12-09 16:39:47 +00001225
Tao Bao0940fe12015-08-27 16:41:21 -07001226 for (size_t i = 0; i < tgt.count; ++i) {
1227 uint64_t blocks[2];
Sami Tolvanen90221202014-12-09 16:39:47 +00001228 // offset in bytes
Tao Bao0940fe12015-08-27 16:41:21 -07001229 blocks[0] = tgt.pos[i * 2] * (uint64_t) BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001230 // length in bytes
Tao Bao0940fe12015-08-27 16:41:21 -07001231 blocks[1] = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * (uint64_t) BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001232
Tao Bao0940fe12015-08-27 16:41:21 -07001233 if (ioctl(params.fd, BLKDISCARD, &blocks) == -1) {
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001234 fprintf(stderr, "BLKDISCARD ioctl failed: %s\n", strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -07001235 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001236 }
1237 }
1238 }
1239
Tao Bao0940fe12015-08-27 16:41:21 -07001240 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001241}
1242
1243// Definitions for transfer list command functions
Tao Bao0940fe12015-08-27 16:41:21 -07001244typedef int (*CommandFunction)(CommandParameters&);
Sami Tolvanen90221202014-12-09 16:39:47 +00001245
Tao Bao612336d2015-08-27 16:41:21 -07001246struct Command {
Sami Tolvanen90221202014-12-09 16:39:47 +00001247 const char* name;
1248 CommandFunction f;
Tao Bao612336d2015-08-27 16:41:21 -07001249};
Sami Tolvanen90221202014-12-09 16:39:47 +00001250
1251// CompareCommands and CompareCommandNames are for the hash table
1252
1253static int CompareCommands(const void* c1, const void* c2) {
1254 return strcmp(((const Command*) c1)->name, ((const Command*) c2)->name);
1255}
1256
1257static int CompareCommandNames(const void* c1, const void* c2) {
1258 return strcmp(((const Command*) c1)->name, (const char*) c2);
1259}
1260
1261// HashString is used to hash command names for the hash table
1262
1263static unsigned int HashString(const char *s) {
1264 unsigned int hash = 0;
1265 if (s) {
1266 while (*s) {
1267 hash = hash * 33 + *s++;
1268 }
1269 }
1270 return hash;
Doug Zongker52ae67d2014-09-08 12:22:09 -07001271}
1272
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001273// args:
1274// - block device (or file) to modify in-place
1275// - transfer list (blob)
1276// - new data stream (filename within package.zip)
1277// - patch stream (filename within package.zip, must be uncompressed)
1278
Tao Bao0940fe12015-08-27 16:41:21 -07001279static Value* PerformBlockImageUpdate(const char* name, State* state, int /* argc */, Expr* argv[],
1280 const Command* commands, size_t cmdcount, bool dryrun) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001281
Sami Tolvanen90221202014-12-09 16:39:47 +00001282 CommandParameters params;
Sami Tolvanen90221202014-12-09 16:39:47 +00001283 memset(&params, 0, sizeof(params));
1284 params.canwrite = !dryrun;
1285
1286 fprintf(stderr, "performing %s\n", dryrun ? "verification" : "update");
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001287
Tao Bao612336d2015-08-27 16:41:21 -07001288 Value* blockdev_filename = nullptr;
1289 Value* transfer_list_value = nullptr;
1290 Value* new_data_fn = nullptr;
1291 Value* patch_data_fn = nullptr;
Doug Zongker1d5d6092014-08-21 10:47:24 -07001292 if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value,
Sami Tolvanen90221202014-12-09 16:39:47 +00001293 &new_data_fn, &patch_data_fn) < 0) {
Tao Bao612336d2015-08-27 16:41:21 -07001294 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001295 }
Tao Bao612336d2015-08-27 16:41:21 -07001296 std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename,
1297 FreeValue);
1298 std::unique_ptr<Value, decltype(&FreeValue)> transfer_list_value_holder(transfer_list_value,
1299 FreeValue);
1300 std::unique_ptr<Value, decltype(&FreeValue)> new_data_fn_holder(new_data_fn, FreeValue);
1301 std::unique_ptr<Value, decltype(&FreeValue)> patch_data_fn_holder(patch_data_fn, FreeValue);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001302
1303 if (blockdev_filename->type != VAL_STRING) {
1304 ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
Tao Bao612336d2015-08-27 16:41:21 -07001305 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001306 }
Doug Zongker1d5d6092014-08-21 10:47:24 -07001307 if (transfer_list_value->type != VAL_BLOB) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001308 ErrorAbort(state, "transfer_list argument to %s must be blob", name);
Tao Bao612336d2015-08-27 16:41:21 -07001309 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001310 }
1311 if (new_data_fn->type != VAL_STRING) {
1312 ErrorAbort(state, "new_data_fn argument to %s must be string", name);
Tao Bao612336d2015-08-27 16:41:21 -07001313 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001314 }
1315 if (patch_data_fn->type != VAL_STRING) {
1316 ErrorAbort(state, "patch_data_fn argument to %s must be string", name);
Tao Bao612336d2015-08-27 16:41:21 -07001317 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001318 }
1319
Tao Bao612336d2015-08-27 16:41:21 -07001320 UpdaterInfo* ui = reinterpret_cast<UpdaterInfo*>(state->cookie);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001321
Tao Bao0940fe12015-08-27 16:41:21 -07001322 if (ui == nullptr) {
Tao Bao612336d2015-08-27 16:41:21 -07001323 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001324 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001325
Tao Bao612336d2015-08-27 16:41:21 -07001326 FILE* cmd_pipe = ui->cmd_pipe;
1327 ZipArchive* za = ui->package_zip;
Sami Tolvanen90221202014-12-09 16:39:47 +00001328
Tao Bao0940fe12015-08-27 16:41:21 -07001329 if (cmd_pipe == nullptr || za == nullptr) {
Tao Bao612336d2015-08-27 16:41:21 -07001330 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001331 }
1332
Tao Bao612336d2015-08-27 16:41:21 -07001333 const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data);
Tao Bao0940fe12015-08-27 16:41:21 -07001334 if (patch_entry == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001335 fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data);
Tao Bao612336d2015-08-27 16:41:21 -07001336 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001337 }
1338
Sami Tolvanen90221202014-12-09 16:39:47 +00001339 params.patch_start = ui->package_zip_addr + mzGetZipEntryOffset(patch_entry);
Tao Bao612336d2015-08-27 16:41:21 -07001340 const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data);
Tao Bao0940fe12015-08-27 16:41:21 -07001341 if (new_entry == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001342 fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data);
Tao Bao612336d2015-08-27 16:41:21 -07001343 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001344 }
1345
Sami Tolvanen90221202014-12-09 16:39:47 +00001346 params.fd = TEMP_FAILURE_RETRY(open(blockdev_filename->data, O_RDWR));
Tao Bao612336d2015-08-27 16:41:21 -07001347 unique_fd fd_holder(params.fd);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001348
Sami Tolvanen90221202014-12-09 16:39:47 +00001349 if (params.fd == -1) {
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001350 fprintf(stderr, "open \"%s\" failed: %s\n", blockdev_filename->data, strerror(errno));
Tao Bao612336d2015-08-27 16:41:21 -07001351 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001352 }
1353
Sami Tolvanen90221202014-12-09 16:39:47 +00001354 if (params.canwrite) {
1355 params.nti.za = za;
1356 params.nti.entry = new_entry;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001357
Tao Bao0940fe12015-08-27 16:41:21 -07001358 pthread_mutex_init(&params.nti.mu, nullptr);
1359 pthread_cond_init(&params.nti.cv, nullptr);
Tao Bao612336d2015-08-27 16:41:21 -07001360 pthread_attr_t attr;
Sami Tolvanen90221202014-12-09 16:39:47 +00001361 pthread_attr_init(&attr);
1362 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1363
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001364 int error = pthread_create(&params.thread, &attr, unzip_new_data, &params.nti);
1365 if (error != 0) {
1366 fprintf(stderr, "pthread_create failed: %s\n", strerror(error));
Tao Bao612336d2015-08-27 16:41:21 -07001367 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001368 }
1369 }
1370
1371 // The data in transfer_list_value is not necessarily null-terminated, so we need
1372 // to copy it to a new buffer and add the null that strtok_r will need.
Tao Bao612336d2015-08-27 16:41:21 -07001373 const std::string transfer_list(transfer_list_value->data, transfer_list_value->size);
1374 std::vector<std::string> lines = android::base::Split(transfer_list, "\n");
Doug Zongker1d5d6092014-08-21 10:47:24 -07001375
Sami Tolvanen90221202014-12-09 16:39:47 +00001376 // First line in transfer list is the version number
Tao Bao1fdec862015-10-21 14:57:44 -07001377 if (!android::base::ParseInt(lines[0].c_str(), &params.version, 1, 4)) {
Tao Bao612336d2015-08-27 16:41:21 -07001378 fprintf(stderr, "unexpected transfer list version [%s]\n", lines[0].c_str());
1379 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001380 }
1381
Sami Tolvanen90221202014-12-09 16:39:47 +00001382 fprintf(stderr, "blockimg version is %d\n", params.version);
1383
1384 // Second line in transfer list is the total number of blocks we expect to write
Tao Baob15fd222015-09-24 11:10:51 -07001385 int total_blocks;
1386 if (!android::base::ParseInt(lines[1].c_str(), &total_blocks, 0)) {
Tao Bao612336d2015-08-27 16:41:21 -07001387 ErrorAbort(state, "unexpected block count [%s]\n", lines[1].c_str());
1388 return StringValue(strdup(""));
Tao Baob15fd222015-09-24 11:10:51 -07001389 }
1390
1391 if (total_blocks == 0) {
Tao Bao612336d2015-08-27 16:41:21 -07001392 return StringValue(strdup("t"));
Sami Tolvanen90221202014-12-09 16:39:47 +00001393 }
1394
Tao Bao612336d2015-08-27 16:41:21 -07001395 size_t start = 2;
Sami Tolvanen90221202014-12-09 16:39:47 +00001396 if (params.version >= 2) {
1397 // Third line is how many stash entries are needed simultaneously
Tao Bao612336d2015-08-27 16:41:21 -07001398 fprintf(stderr, "maximum stash entries %s\n", lines[2].c_str());
Doug Zongker52ae67d2014-09-08 12:22:09 -07001399
Sami Tolvanen90221202014-12-09 16:39:47 +00001400 // Fourth line is the maximum number of blocks that will be stashed simultaneously
Tao Baob15fd222015-09-24 11:10:51 -07001401 int stash_max_blocks;
1402 if (!android::base::ParseInt(lines[3].c_str(), &stash_max_blocks, 0)) {
Tao Bao612336d2015-08-27 16:41:21 -07001403 ErrorAbort(state, "unexpected maximum stash blocks [%s]\n", lines[3].c_str());
1404 return StringValue(strdup(""));
Doug Zongker52ae67d2014-09-08 12:22:09 -07001405 }
1406
Tao Baob15fd222015-09-24 11:10:51 -07001407 int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase);
Sami Tolvanen90221202014-12-09 16:39:47 +00001408
Tao Baob15fd222015-09-24 11:10:51 -07001409 if (res == -1) {
1410 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001411 }
Tao Bao612336d2015-08-27 16:41:21 -07001412
Tao Baob15fd222015-09-24 11:10:51 -07001413 params.createdstash = res;
1414
Tao Bao612336d2015-08-27 16:41:21 -07001415 start += 2;
Doug Zongker52ae67d2014-09-08 12:22:09 -07001416 }
1417
Sami Tolvanen90221202014-12-09 16:39:47 +00001418 // Build a hash table of the available commands
Tao Bao612336d2015-08-27 16:41:21 -07001419 HashTable* cmdht = mzHashTableCreate(cmdcount, nullptr);
1420 std::unique_ptr<HashTable, decltype(&mzHashTableFree)> cmdht_holder(cmdht, mzHashTableFree);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001421
Tao Bao0940fe12015-08-27 16:41:21 -07001422 for (size_t i = 0; i < cmdcount; ++i) {
1423 unsigned int cmdhash = HashString(commands[i].name);
Sami Tolvanen90221202014-12-09 16:39:47 +00001424 mzHashTableLookup(cmdht, cmdhash, (void*) &commands[i], CompareCommands, true);
1425 }
1426
Tao Bao612336d2015-08-27 16:41:21 -07001427 int rc = -1;
Doug Zongker52ae67d2014-09-08 12:22:09 -07001428
Tao Bao612336d2015-08-27 16:41:21 -07001429 // Subsequent lines are all individual transfer commands
1430 for (auto it = lines.cbegin() + start; it != lines.cend(); it++) {
1431 const std::string& line_str(*it);
Tao Bao6a47dff2015-09-25 17:12:28 -07001432 if (line_str.empty()) {
1433 continue;
1434 }
1435
Tao Bao612336d2015-08-27 16:41:21 -07001436 char* line = strdup(line_str.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +00001437 params.cmdname = strtok_r(line, " ", &params.cpos);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001438
Tao Bao0940fe12015-08-27 16:41:21 -07001439 if (params.cmdname == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001440 fprintf(stderr, "missing command [%s]\n", line);
1441 goto pbiudone;
1442 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001443
Tao Bao0940fe12015-08-27 16:41:21 -07001444 unsigned int cmdhash = HashString(params.cmdname);
Tao Bao612336d2015-08-27 16:41:21 -07001445 const Command* cmd = reinterpret_cast<const Command*>(mzHashTableLookup(cmdht, cmdhash,
1446 params.cmdname, CompareCommandNames, false));
Doug Zongker52ae67d2014-09-08 12:22:09 -07001447
Tao Bao0940fe12015-08-27 16:41:21 -07001448 if (cmd == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001449 fprintf(stderr, "unexpected command [%s]\n", params.cmdname);
1450 goto pbiudone;
1451 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001452
Tao Bao0940fe12015-08-27 16:41:21 -07001453 if (cmd->f != nullptr && cmd->f(params) == -1) {
Tao Bao612336d2015-08-27 16:41:21 -07001454 fprintf(stderr, "failed to execute command [%s]\n", line_str.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +00001455 goto pbiudone;
1456 }
1457
Sami Tolvanen90221202014-12-09 16:39:47 +00001458 if (params.canwrite) {
Tao Bao187efff2015-07-27 14:07:08 -07001459 if (fsync(params.fd) == -1) {
1460 fprintf(stderr, "fsync failed: %s\n", strerror(errno));
1461 goto pbiudone;
1462 }
Sami Tolvanen90221202014-12-09 16:39:47 +00001463 fprintf(cmd_pipe, "set_progress %.4f\n", (double) params.written / total_blocks);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001464 fflush(cmd_pipe);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001465 }
1466 }
1467
Sami Tolvanen90221202014-12-09 16:39:47 +00001468 if (params.canwrite) {
Tao Bao0940fe12015-08-27 16:41:21 -07001469 pthread_join(params.thread, nullptr);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001470
Tao Bao0940fe12015-08-27 16:41:21 -07001471 fprintf(stderr, "wrote %zu blocks; expected %d\n", params.written, total_blocks);
Tao Bao612336d2015-08-27 16:41:21 -07001472 fprintf(stderr, "max alloc needed was %zu\n", params.buffer.size());
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001473
Sami Tolvanen90221202014-12-09 16:39:47 +00001474 // Delete stash only after successfully completing the update, as it
1475 // may contain blocks needed to complete the update later.
1476 DeleteStash(params.stashbase);
1477 } else {
1478 fprintf(stderr, "verified partition contents; update may be resumed\n");
1479 }
1480
1481 rc = 0;
1482
1483pbiudone:
1484 if (params.fd != -1) {
1485 if (fsync(params.fd) == -1) {
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001486 fprintf(stderr, "fsync failed: %s\n", strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +00001487 }
Elliott Hughesb47afed2015-05-15 16:19:20 -07001488 close(params.fd);
Sami Tolvanen90221202014-12-09 16:39:47 +00001489 }
1490
Sami Tolvanen90221202014-12-09 16:39:47 +00001491 // Only delete the stash if the update cannot be resumed, or it's
1492 // a verification run and we created the stash.
1493 if (params.isunresumable || (!params.canwrite && params.createdstash)) {
1494 DeleteStash(params.stashbase);
1495 }
1496
Sami Tolvanen90221202014-12-09 16:39:47 +00001497 return StringValue(rc == 0 ? strdup("t") : strdup(""));
1498}
1499
1500// The transfer list is a text file containing commands to
1501// transfer data from one place to another on the target
1502// partition. We parse it and execute the commands in order:
1503//
1504// zero [rangeset]
1505// - fill the indicated blocks with zeros
1506//
1507// new [rangeset]
1508// - fill the blocks with data read from the new_data file
1509//
1510// erase [rangeset]
1511// - mark the given blocks as empty
1512//
1513// move <...>
1514// bsdiff <patchstart> <patchlen> <...>
1515// imgdiff <patchstart> <patchlen> <...>
1516// - read the source blocks, apply a patch (or not in the
1517// case of move), write result to target blocks. bsdiff or
1518// imgdiff specifies the type of patch; move means no patch
1519// at all.
1520//
1521// The format of <...> differs between versions 1 and 2;
1522// see the LoadSrcTgtVersion{1,2}() functions for a
1523// description of what's expected.
1524//
1525// stash <stash_id> <src_range>
1526// - (version 2+ only) load the given source range and stash
1527// the data in the given slot of the stash table.
1528//
1529// The creator of the transfer list will guarantee that no block
1530// is read (ie, used as the source for a patch or move) after it
1531// has been written.
1532//
1533// In version 2, the creator will guarantee that a given stash is
1534// loaded (with a stash command) before it's used in a
1535// move/bsdiff/imgdiff command.
1536//
1537// Within one command the source and target ranges may overlap so
1538// in general we need to read the entire source into memory before
1539// writing anything to the target blocks.
1540//
1541// All the patch data is concatenated into one patch_data file in
1542// the update package. It must be stored uncompressed because we
1543// memory-map it in directly from the archive. (Since patches are
1544// already compressed, we lose very little by not compressing
1545// their concatenation.)
1546//
1547// In version 3, commands that read data from the partition (i.e.
1548// move/bsdiff/imgdiff/stash) have one or more additional hashes
1549// before the range parameters, which are used to check if the
1550// command has already been completed and verify the integrity of
1551// the source data.
1552
1553Value* BlockImageVerifyFn(const char* name, State* state, int argc, Expr* argv[]) {
Tao Bao0940fe12015-08-27 16:41:21 -07001554 // Commands which are not tested are set to nullptr to skip them completely
Sami Tolvanen90221202014-12-09 16:39:47 +00001555 const Command commands[] = {
1556 { "bsdiff", PerformCommandDiff },
Tao Bao0940fe12015-08-27 16:41:21 -07001557 { "erase", nullptr },
Sami Tolvanen90221202014-12-09 16:39:47 +00001558 { "free", PerformCommandFree },
1559 { "imgdiff", PerformCommandDiff },
1560 { "move", PerformCommandMove },
Tao Bao0940fe12015-08-27 16:41:21 -07001561 { "new", nullptr },
Sami Tolvanen90221202014-12-09 16:39:47 +00001562 { "stash", PerformCommandStash },
Tao Bao0940fe12015-08-27 16:41:21 -07001563 { "zero", nullptr }
Sami Tolvanen90221202014-12-09 16:39:47 +00001564 };
1565
1566 // Perform a dry run without writing to test if an update can proceed
1567 return PerformBlockImageUpdate(name, state, argc, argv, commands,
Tao Baoe6aa3322015-08-05 15:20:27 -07001568 sizeof(commands) / sizeof(commands[0]), true);
Sami Tolvanen90221202014-12-09 16:39:47 +00001569}
1570
1571Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]) {
1572 const Command commands[] = {
1573 { "bsdiff", PerformCommandDiff },
1574 { "erase", PerformCommandErase },
1575 { "free", PerformCommandFree },
1576 { "imgdiff", PerformCommandDiff },
1577 { "move", PerformCommandMove },
1578 { "new", PerformCommandNew },
1579 { "stash", PerformCommandStash },
1580 { "zero", PerformCommandZero }
1581 };
1582
1583 return PerformBlockImageUpdate(name, state, argc, argv, commands,
Tao Baoe6aa3322015-08-05 15:20:27 -07001584 sizeof(commands) / sizeof(commands[0]), false);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001585}
1586
Tao Bao0940fe12015-08-27 16:41:21 -07001587Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001588 Value* blockdev_filename;
1589 Value* ranges;
Tao Bao0940fe12015-08-27 16:41:21 -07001590
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001591 if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) {
Tao Bao612336d2015-08-27 16:41:21 -07001592 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001593 }
Tao Bao612336d2015-08-27 16:41:21 -07001594 std::unique_ptr<Value, decltype(&FreeValue)> ranges_holder(ranges, FreeValue);
1595 std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename,
1596 FreeValue);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001597
1598 if (blockdev_filename->type != VAL_STRING) {
1599 ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
Tao Bao612336d2015-08-27 16:41:21 -07001600 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001601 }
1602 if (ranges->type != VAL_STRING) {
1603 ErrorAbort(state, "ranges argument to %s must be string", name);
Tao Bao612336d2015-08-27 16:41:21 -07001604 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001605 }
1606
Tao Bao612336d2015-08-27 16:41:21 -07001607 int fd = open(blockdev_filename->data, O_RDWR);
1608 unique_fd fd_holder(fd);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001609 if (fd < 0) {
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001610 ErrorAbort(state, "open \"%s\" failed: %s", blockdev_filename->data, strerror(errno));
Tao Bao612336d2015-08-27 16:41:21 -07001611 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001612 }
1613
Tao Bao612336d2015-08-27 16:41:21 -07001614 RangeSet rs;
Tao Bao0940fe12015-08-27 16:41:21 -07001615 parse_range(ranges->data, rs);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001616
1617 SHA_CTX ctx;
1618 SHA_init(&ctx);
1619
Tao Bao612336d2015-08-27 16:41:21 -07001620 std::vector<uint8_t> buffer(BLOCKSIZE);
Tao Bao0940fe12015-08-27 16:41:21 -07001621 for (size_t i = 0; i < rs.count; ++i) {
1622 if (!check_lseek(fd, (off64_t)rs.pos[i*2] * BLOCKSIZE, SEEK_SET)) {
Tao Bao612336d2015-08-27 16:41:21 -07001623 ErrorAbort(state, "failed to seek %s: %s", blockdev_filename->data, strerror(errno));
1624 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001625 }
1626
Tao Bao0940fe12015-08-27 16:41:21 -07001627 for (size_t j = rs.pos[i*2]; j < rs.pos[i*2+1]; ++j) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001628 if (read_all(fd, buffer, BLOCKSIZE) == -1) {
1629 ErrorAbort(state, "failed to read %s: %s", blockdev_filename->data,
Tao Bao0940fe12015-08-27 16:41:21 -07001630 strerror(errno));
Tao Bao612336d2015-08-27 16:41:21 -07001631 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001632 }
1633
Tao Bao612336d2015-08-27 16:41:21 -07001634 SHA_update(&ctx, buffer.data(), BLOCKSIZE);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001635 }
1636 }
Tao Bao612336d2015-08-27 16:41:21 -07001637 const uint8_t* digest = SHA_final(&ctx);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001638
Tao Bao612336d2015-08-27 16:41:21 -07001639 return StringValue(strdup(print_sha1(digest).c_str()));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001640}
1641
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001642Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[]) {
1643 Value* arg_filename;
1644 Value* arg_ranges;
1645
1646 if (ReadValueArgs(state, argv, 2, &arg_filename, &arg_ranges) < 0) {
1647 return NULL;
1648 }
1649
1650 std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue);
1651 std::unique_ptr<Value, decltype(&FreeValue)> ranges(arg_ranges, FreeValue);
1652
1653 if (filename->type != VAL_STRING) {
1654 ErrorAbort(state, "filename argument to %s must be string", name);
1655 return StringValue(strdup(""));
1656 }
1657 if (ranges->type != VAL_STRING) {
1658 ErrorAbort(state, "ranges argument to %s must be string", name);
1659 return StringValue(strdup(""));
1660 }
1661
1662 // When opened with O_RDWR, libfec rewrites corrupted blocks when they are read
1663 fec::io fh(filename->data, O_RDWR);
1664
1665 if (!fh) {
1666 ErrorAbort(state, "fec_open \"%s\" failed: %s", filename->data, strerror(errno));
1667 return StringValue(strdup(""));
1668 }
1669
1670 if (!fh.has_ecc() || !fh.has_verity()) {
1671 ErrorAbort(state, "unable to use metadata to correct errors");
1672 return StringValue(strdup(""));
1673 }
1674
1675 fec_status status;
1676
1677 if (!fh.get_status(status)) {
1678 ErrorAbort(state, "failed to read FEC status");
1679 return StringValue(strdup(""));
1680 }
1681
1682 RangeSet rs;
1683 parse_range(ranges->data, rs);
1684
1685 uint8_t buffer[BLOCKSIZE];
1686
1687 for (size_t i = 0; i < rs.count; ++i) {
1688 for (size_t j = rs.pos[i * 2]; j < rs.pos[i * 2 + 1]; ++j) {
1689 // Stay within the data area, libfec validates and corrects metadata
1690 if (status.data_size <= (uint64_t)j * BLOCKSIZE) {
1691 continue;
1692 }
1693
1694 if (fh.pread(buffer, BLOCKSIZE, (off64_t)j * BLOCKSIZE) != BLOCKSIZE) {
1695 ErrorAbort(state, "failed to recover %s (block %d): %s", filename->data,
1696 j, strerror(errno));
1697 return StringValue(strdup(""));
1698 }
1699
1700 // If we want to be able to recover from a situation where rewriting a corrected
1701 // block doesn't guarantee the same data will be returned when re-read later, we
1702 // can save a copy of corrected blocks to /cache. Note:
1703 //
1704 // 1. Maximum space required from /cache is the same as the maximum number of
1705 // corrupted blocks we can correct. For RS(255, 253) and a 2 GiB partition,
1706 // this would be ~16 MiB, for example.
1707 //
1708 // 2. To find out if this block was corrupted, call fec_get_status after each
1709 // read and check if the errors field value has increased.
1710 }
1711 }
1712
1713 return StringValue(strdup("t"));
1714}
1715
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001716void RegisterBlockImageFunctions() {
Sami Tolvanen90221202014-12-09 16:39:47 +00001717 RegisterFunction("block_image_verify", BlockImageVerifyFn);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001718 RegisterFunction("block_image_update", BlockImageUpdateFn);
Sami Tolvanen0a7b4732015-06-25 10:25:36 +01001719 RegisterFunction("block_image_recover", BlockImageRecoverFn);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001720 RegisterFunction("range_sha1", RangeSha1Fn);
1721}