blob: 2efa1cd477cbb4cbd0e5557b1f07531e01c019a9 [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
Tianjie Xu01889352016-03-22 18:08:12 -070036#include <map>
Tao Baoe6aa3322015-08-05 15:20:27 -070037#include <memory>
38#include <string>
Tao Bao0940fe12015-08-27 16:41:21 -070039#include <vector>
Tao Baoe6aa3322015-08-05 15:20:27 -070040
Elliott Hughes4b166f02015-12-04 15:30:20 -080041#include <android-base/parseint.h>
42#include <android-base/strings.h>
Tao Baoe6aa3322015-08-05 15:20:27 -070043
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070044#include "applypatch/applypatch.h"
45#include "edify/expr.h"
Tianjie Xu16255832016-04-30 11:49:59 -070046#include "error_code.h"
Tianjie Xu30bf4762015-12-15 11:47:30 -080047#include "install.h"
Sen Jiangc48cb5e2016-02-04 16:23:21 +080048#include "openssl/sha.h"
Sami Tolvanen90221202014-12-09 16:39:47 +000049#include "minzip/Hash.h"
Jed Estepf73abf32015-12-15 16:04:53 -080050#include "ota_io.h"
Tao Baoe6aa3322015-08-05 15:20:27 -070051#include "print_sha1.h"
Tao Bao0940fe12015-08-27 16:41:21 -070052#include "unique_fd.h"
53#include "updater.h"
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070054
55#define BLOCKSIZE 4096
56
Sami Tolvanene82fa182015-06-10 15:58:12 +000057// Set this to 0 to interpret 'erase' transfers to mean do a
58// BLKDISCARD ioctl (the normal behavior). Set to 1 to interpret
59// erase to mean fill the region with zeroes.
60#define DEBUG_ERASE 0
61
Sami Tolvanen90221202014-12-09 16:39:47 +000062#define STASH_DIRECTORY_BASE "/cache/recovery"
63#define STASH_DIRECTORY_MODE 0700
64#define STASH_FILE_MODE 0600
65
Tao Bao0940fe12015-08-27 16:41:21 -070066struct RangeSet {
67 size_t count; // Limit is INT_MAX.
Shrinivas Sahukara6153df2015-08-19 13:01:45 +053068 size_t size;
Tao Bao0940fe12015-08-27 16:41:21 -070069 std::vector<size_t> pos; // Actual limit is INT_MAX.
70};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -070071
Tianjie Xu16255832016-04-30 11:49:59 -070072static CauseCode failure_type = kNoCause;
Tianjie Xu01889352016-03-22 18:08:12 -070073static std::map<std::string, RangeSet> stash_map;
74
Tao Baobaad2d42015-12-06 16:56:27 -080075static void parse_range(const std::string& range_text, RangeSet& rs) {
Sami Tolvanenf2bac042015-05-12 12:48:46 +010076
Tao Baobaad2d42015-12-06 16:56:27 -080077 std::vector<std::string> pieces = android::base::Split(range_text, ",");
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 Baobaad2d42015-12-06 16:56:27 -0800123 fprintf(stderr, "failed to parse range '%s'\n", range_text.c_str());
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) {
Jed Estepf1fc48c2015-12-15 16:04:53 -0800148 ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far));
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700149 if (r == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700150 failure_type = kFreadFailure;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700151 fprintf(stderr, "read failed: %s\n", strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000152 return -1;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700153 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700154 so_far += r;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700155 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000156 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700157}
158
Tao Bao612336d2015-08-27 16:41:21 -0700159static int read_all(int fd, std::vector<uint8_t>& buffer, size_t size) {
160 return read_all(fd, buffer.data(), size);
161}
162
Sami Tolvanen90221202014-12-09 16:39:47 +0000163static int write_all(int fd, const uint8_t* data, size_t size) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700164 size_t written = 0;
165 while (written < size) {
Jed Estepf1fc48c2015-12-15 16:04:53 -0800166 ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written));
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700167 if (w == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700168 failure_type = kFwriteFailure;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700169 fprintf(stderr, "write failed: %s\n", strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000170 return -1;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700171 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700172 written += w;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700173 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000174
Sami Tolvanen90221202014-12-09 16:39:47 +0000175 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700176}
177
Tao Bao612336d2015-08-27 16:41:21 -0700178static int write_all(int fd, const std::vector<uint8_t>& buffer, size_t size) {
179 return write_all(fd, buffer.data(), size);
180}
181
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700182static bool check_lseek(int fd, off64_t offset, int whence) {
183 off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
184 if (rc == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700185 failure_type = kLseekFailure;
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700186 fprintf(stderr, "lseek64 failed: %s\n", strerror(errno));
187 return false;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700188 }
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700189 return true;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700190}
191
Tao Bao612336d2015-08-27 16:41:21 -0700192static void allocate(size_t size, std::vector<uint8_t>& buffer) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700193 // if the buffer's big enough, reuse it.
Tao Bao612336d2015-08-27 16:41:21 -0700194 if (size <= buffer.size()) return;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700195
Tao Bao612336d2015-08-27 16:41:21 -0700196 buffer.resize(size);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700197}
198
Tao Bao0940fe12015-08-27 16:41:21 -0700199struct RangeSinkState {
200 RangeSinkState(RangeSet& rs) : tgt(rs) { };
201
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700202 int fd;
Tao Bao0940fe12015-08-27 16:41:21 -0700203 const RangeSet& tgt;
Shrinivas Sahukara6153df2015-08-19 13:01:45 +0530204 size_t p_block;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700205 size_t p_remain;
Tao Bao0940fe12015-08-27 16:41:21 -0700206};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700207
208static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
Tao Bao0940fe12015-08-27 16:41:21 -0700209 RangeSinkState* rss = reinterpret_cast<RangeSinkState*>(token);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700210
Tao Bao0940fe12015-08-27 16:41:21 -0700211 if (rss->p_remain == 0) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700212 fprintf(stderr, "range sink write overrun");
Sami Tolvanen90221202014-12-09 16:39:47 +0000213 return 0;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700214 }
215
216 ssize_t written = 0;
217 while (size > 0) {
218 size_t write_now = size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000219
220 if (rss->p_remain < write_now) {
221 write_now = rss->p_remain;
222 }
223
224 if (write_all(rss->fd, data, write_now) == -1) {
225 break;
226 }
227
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700228 data += write_now;
229 size -= write_now;
230
231 rss->p_remain -= write_now;
232 written += write_now;
233
234 if (rss->p_remain == 0) {
235 // move to the next block
236 ++rss->p_block;
Tao Bao0940fe12015-08-27 16:41:21 -0700237 if (rss->p_block < rss->tgt.count) {
238 rss->p_remain = (rss->tgt.pos[rss->p_block * 2 + 1] -
239 rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000240
Tao Bao0940fe12015-08-27 16:41:21 -0700241 if (!check_lseek(rss->fd, (off64_t)rss->tgt.pos[rss->p_block*2] * BLOCKSIZE,
Elliott Hughes7bad7c42015-04-28 17:24:24 -0700242 SEEK_SET)) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000243 break;
244 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700245 } else {
246 // we can't write any more; return how many bytes have
247 // been written so far.
Sami Tolvanen90221202014-12-09 16:39:47 +0000248 break;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700249 }
250 }
251 }
252
253 return written;
254}
255
256// All of the data for all the 'new' transfers is contained in one
257// file in the update package, concatenated together in the order in
258// which transfers.list will need it. We want to stream it out of the
259// archive (it's compressed) without writing it to a temp file, but we
260// can't write each section until it's that transfer's turn to go.
261//
262// To achieve this, we expand the new data from the archive in a
263// background thread, and block that threads 'receive uncompressed
264// data' function until the main thread has reached a point where we
265// want some new data to be written. We signal the background thread
266// with the destination for the data and block the main thread,
267// waiting for the background thread to complete writing that section.
268// Then it signals the main thread to wake up and goes back to
269// blocking waiting for a transfer.
270//
271// NewThreadInfo is the struct used to pass information back and forth
272// between the two threads. When the main thread wants some data
273// written, it sets rss to the destination location and signals the
274// condition. When the background thread is done writing, it clears
275// rss and signals the condition again.
276
Tao Bao0940fe12015-08-27 16:41:21 -0700277struct NewThreadInfo {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700278 ZipArchive* za;
279 const ZipEntry* entry;
280
281 RangeSinkState* rss;
282
283 pthread_mutex_t mu;
284 pthread_cond_t cv;
Tao Bao0940fe12015-08-27 16:41:21 -0700285};
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700286
287static bool receive_new_data(const unsigned char* data, int size, void* cookie) {
Tao Bao0940fe12015-08-27 16:41:21 -0700288 NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700289
290 while (size > 0) {
Tao Bao0940fe12015-08-27 16:41:21 -0700291 // Wait for nti->rss to be non-null, indicating some of this
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700292 // data is wanted.
293 pthread_mutex_lock(&nti->mu);
Tao Bao0940fe12015-08-27 16:41:21 -0700294 while (nti->rss == nullptr) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700295 pthread_cond_wait(&nti->cv, &nti->mu);
296 }
297 pthread_mutex_unlock(&nti->mu);
298
299 // At this point nti->rss is set, and we own it. The main
300 // thread is waiting for it to disappear from nti.
301 ssize_t written = RangeSinkWrite(data, size, nti->rss);
302 data += written;
303 size -= written;
304
Tao Bao0940fe12015-08-27 16:41:21 -0700305 if (nti->rss->p_block == nti->rss->tgt.count) {
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700306 // we have written all the bytes desired by this rss.
307
308 pthread_mutex_lock(&nti->mu);
Tao Bao0940fe12015-08-27 16:41:21 -0700309 nti->rss = nullptr;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700310 pthread_cond_broadcast(&nti->cv);
311 pthread_mutex_unlock(&nti->mu);
312 }
313 }
314
315 return true;
316}
317
318static void* unzip_new_data(void* cookie) {
319 NewThreadInfo* nti = (NewThreadInfo*) cookie;
320 mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti);
Tao Bao0940fe12015-08-27 16:41:21 -0700321 return nullptr;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -0700322}
323
Tao Bao612336d2015-08-27 16:41:21 -0700324static int ReadBlocks(const RangeSet& src, std::vector<uint8_t>& buffer, int fd) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000325 size_t p = 0;
Tao Bao612336d2015-08-27 16:41:21 -0700326 uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000327
Tao Bao0940fe12015-08-27 16:41:21 -0700328 for (size_t i = 0; i < src.count; ++i) {
329 if (!check_lseek(fd, (off64_t) src.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000330 return -1;
331 }
332
Tao Bao0940fe12015-08-27 16:41:21 -0700333 size_t size = (src.pos[i * 2 + 1] - src.pos[i * 2]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000334
Tao Bao612336d2015-08-27 16:41:21 -0700335 if (read_all(fd, data + p, size) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000336 return -1;
337 }
338
339 p += size;
340 }
341
342 return 0;
343}
344
Tao Bao612336d2015-08-27 16:41:21 -0700345static int WriteBlocks(const RangeSet& tgt, const std::vector<uint8_t>& buffer, int fd) {
346 const uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000347
Tao Bao0940fe12015-08-27 16:41:21 -0700348 size_t p = 0;
349 for (size_t i = 0; i < tgt.count; ++i) {
350 if (!check_lseek(fd, (off64_t) tgt.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000351 return -1;
352 }
353
Tao Bao0940fe12015-08-27 16:41:21 -0700354 size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000355
Tao Bao612336d2015-08-27 16:41:21 -0700356 if (write_all(fd, data + p, size) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000357 return -1;
358 }
359
360 p += size;
361 }
362
363 return 0;
364}
365
Tao Baobaad2d42015-12-06 16:56:27 -0800366// Parameters for transfer list command functions
367struct CommandParameters {
368 std::vector<std::string> tokens;
369 size_t cpos;
370 const char* cmdname;
371 const char* cmdline;
372 std::string freestash;
373 std::string stashbase;
374 bool canwrite;
375 int createdstash;
376 int fd;
377 bool foundwrites;
378 bool isunresumable;
379 int version;
380 size_t written;
Tianjie Xudd874b12016-05-13 12:13:15 -0700381 size_t stashed;
Tao Baobaad2d42015-12-06 16:56:27 -0800382 NewThreadInfo nti;
383 pthread_t thread;
384 std::vector<uint8_t> buffer;
385 uint8_t* patch_start;
386};
387
Doug Zongker52ae67d2014-09-08 12:22:09 -0700388// Do a source/target load for move/bsdiff/imgdiff in version 1.
Tao Baobaad2d42015-12-06 16:56:27 -0800389// We expect to parse the remainder of the parameter tokens as:
Doug Zongker52ae67d2014-09-08 12:22:09 -0700390//
391// <src_range> <tgt_range>
392//
393// The source range is loaded into the provided buffer, reallocating
Tao Bao34847b22015-09-08 11:05:49 -0700394// it to make it larger if necessary.
Doug Zongker52ae67d2014-09-08 12:22:09 -0700395
Tao Baobaad2d42015-12-06 16:56:27 -0800396static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
Tao Bao612336d2015-08-27 16:41:21 -0700397 std::vector<uint8_t>& buffer, int fd) {
Tao Baobaad2d42015-12-06 16:56:27 -0800398
399 if (params.cpos + 1 >= params.tokens.size()) {
400 fprintf(stderr, "invalid parameters\n");
401 return -1;
402 }
403
Tao Bao612336d2015-08-27 16:41:21 -0700404 // <src_range>
Tao Bao0940fe12015-08-27 16:41:21 -0700405 RangeSet src;
Tao Baobaad2d42015-12-06 16:56:27 -0800406 parse_range(params.tokens[params.cpos++], src);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700407
Tao Bao612336d2015-08-27 16:41:21 -0700408 // <tgt_range>
Tao Baobaad2d42015-12-06 16:56:27 -0800409 parse_range(params.tokens[params.cpos++], tgt);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700410
Tao Bao612336d2015-08-27 16:41:21 -0700411 allocate(src.size * BLOCKSIZE, buffer);
412 int rc = ReadBlocks(src, buffer, fd);
Tao Bao0940fe12015-08-27 16:41:21 -0700413 src_blocks = src.size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000414
Sami Tolvanen90221202014-12-09 16:39:47 +0000415 return rc;
416}
417
Tao Bao612336d2015-08-27 16:41:21 -0700418static int VerifyBlocks(const std::string& expected, const std::vector<uint8_t>& buffer,
Tao Bao0940fe12015-08-27 16:41:21 -0700419 const size_t blocks, bool printerror) {
Sen Jiangc48cb5e2016-02-04 16:23:21 +0800420 uint8_t digest[SHA_DIGEST_LENGTH];
Tao Bao612336d2015-08-27 16:41:21 -0700421 const uint8_t* data = buffer.data();
Sami Tolvanen90221202014-12-09 16:39:47 +0000422
Sen Jiangc48cb5e2016-02-04 16:23:21 +0800423 SHA1(data, blocks * BLOCKSIZE, digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000424
Tao Baoe6aa3322015-08-05 15:20:27 -0700425 std::string hexdigest = print_sha1(digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000426
Tao Bao0940fe12015-08-27 16:41:21 -0700427 if (hexdigest != expected) {
428 if (printerror) {
429 fprintf(stderr, "failed to verify blocks (expected %s, read %s)\n",
430 expected.c_str(), hexdigest.c_str());
431 }
432 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000433 }
434
Tao Bao0940fe12015-08-27 16:41:21 -0700435 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000436}
437
Tao Bao0940fe12015-08-27 16:41:21 -0700438static std::string GetStashFileName(const std::string& base, const std::string& id,
439 const std::string& postfix) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700440 if (base.empty()) {
441 return "";
Sami Tolvanen90221202014-12-09 16:39:47 +0000442 }
443
Tao Baoe6aa3322015-08-05 15:20:27 -0700444 std::string fn(STASH_DIRECTORY_BASE);
445 fn += "/" + base + "/" + id + postfix;
Sami Tolvanen90221202014-12-09 16:39:47 +0000446
447 return fn;
448}
449
Tao Baoe6aa3322015-08-05 15:20:27 -0700450typedef void (*StashCallback)(const std::string&, void*);
Sami Tolvanen90221202014-12-09 16:39:47 +0000451
452// Does a best effort enumeration of stash files. Ignores possible non-file
453// items in the stash directory and continues despite of errors. Calls the
454// 'callback' function for each file and passes 'data' to the function as a
455// parameter.
456
Tao Baoe6aa3322015-08-05 15:20:27 -0700457static void EnumerateStash(const std::string& dirname, StashCallback callback, void* data) {
Tao Bao0940fe12015-08-27 16:41:21 -0700458 if (dirname.empty() || callback == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000459 return;
460 }
461
Tao Baoe6aa3322015-08-05 15:20:27 -0700462 std::unique_ptr<DIR, int(*)(DIR*)> directory(opendir(dirname.c_str()), closedir);
Sami Tolvanen90221202014-12-09 16:39:47 +0000463
Tao Bao0940fe12015-08-27 16:41:21 -0700464 if (directory == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000465 if (errno != ENOENT) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700466 fprintf(stderr, "opendir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000467 }
468 return;
469 }
470
Tao Baoe6aa3322015-08-05 15:20:27 -0700471 struct dirent* item;
Tao Bao0940fe12015-08-27 16:41:21 -0700472 while ((item = readdir(directory.get())) != nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000473 if (item->d_type != DT_REG) {
474 continue;
475 }
476
Tao Baoe6aa3322015-08-05 15:20:27 -0700477 std::string fn = dirname + "/" + std::string(item->d_name);
Sami Tolvanen90221202014-12-09 16:39:47 +0000478 callback(fn, data);
Sami Tolvanen90221202014-12-09 16:39:47 +0000479 }
480}
481
Tao Baoe6aa3322015-08-05 15:20:27 -0700482static void UpdateFileSize(const std::string& fn, void* data) {
483 if (fn.empty() || !data) {
484 return;
485 }
486
Tao Bao0940fe12015-08-27 16:41:21 -0700487 struct stat sb;
488 if (stat(fn.c_str(), &sb) == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700489 fprintf(stderr, "stat \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000490 return;
491 }
492
Tao Baoe6aa3322015-08-05 15:20:27 -0700493 int* size = reinterpret_cast<int*>(data);
Tao Bao0940fe12015-08-27 16:41:21 -0700494 *size += sb.st_size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000495}
496
497// Deletes the stash directory and all files in it. Assumes that it only
498// contains files. There is nothing we can do about unlikely, but possible
499// errors, so they are merely logged.
500
Tao Bao0940fe12015-08-27 16:41:21 -0700501static void DeleteFile(const std::string& fn, void* /* data */) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700502 if (!fn.empty()) {
503 fprintf(stderr, "deleting %s\n", fn.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000504
Tao Baoe6aa3322015-08-05 15:20:27 -0700505 if (unlink(fn.c_str()) == -1 && errno != ENOENT) {
506 fprintf(stderr, "unlink \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000507 }
508 }
509}
510
Tao Baoe6aa3322015-08-05 15:20:27 -0700511static void DeletePartial(const std::string& fn, void* data) {
512 if (android::base::EndsWith(fn, ".partial")) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000513 DeleteFile(fn, data);
514 }
515}
516
Tao Baoe6aa3322015-08-05 15:20:27 -0700517static void DeleteStash(const std::string& base) {
518 if (base.empty()) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000519 return;
520 }
521
Tao Baoe6aa3322015-08-05 15:20:27 -0700522 fprintf(stderr, "deleting stash %s\n", base.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000523
Tao Baoe6aa3322015-08-05 15:20:27 -0700524 std::string dirname = GetStashFileName(base, "", "");
Tao Bao0940fe12015-08-27 16:41:21 -0700525 EnumerateStash(dirname, DeleteFile, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +0000526
Tao Baoe6aa3322015-08-05 15:20:27 -0700527 if (rmdir(dirname.c_str()) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000528 if (errno != ENOENT && errno != ENOTDIR) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700529 fprintf(stderr, "rmdir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000530 }
531 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000532}
533
Tianjie Xu01889352016-03-22 18:08:12 -0700534static int LoadStash(CommandParameters& params, const std::string& base, const std::string& id,
535 bool verify, size_t* blocks, std::vector<uint8_t>& buffer, bool printnoent) {
536 // In verify mode, if source range_set was saved for the given hash,
537 // check contents in the source blocks first. If the check fails,
538 // search for the stashed files on /cache as usual.
539 if (!params.canwrite) {
540 if (stash_map.find(id) != stash_map.end()) {
541 const RangeSet& src = stash_map[id];
542 allocate(src.size * BLOCKSIZE, buffer);
543
544 if (ReadBlocks(src, buffer, params.fd) == -1) {
545 fprintf(stderr, "failed to read source blocks in stash map.\n");
546 return -1;
547 }
548 if (VerifyBlocks(id, buffer, src.size, true) != 0) {
549 fprintf(stderr, "failed to verify loaded source blocks in stash map.\n");
550 return -1;
551 }
552 return 0;
553 }
554 }
555
Tao Bao612336d2015-08-27 16:41:21 -0700556 if (base.empty()) {
Tao Bao0940fe12015-08-27 16:41:21 -0700557 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000558 }
559
Tao Bao0940fe12015-08-27 16:41:21 -0700560 size_t blockcount = 0;
561
Sami Tolvanen90221202014-12-09 16:39:47 +0000562 if (!blocks) {
563 blocks = &blockcount;
564 }
565
Tao Bao0940fe12015-08-27 16:41:21 -0700566 std::string fn = GetStashFileName(base, id, "");
Sami Tolvanen90221202014-12-09 16:39:47 +0000567
Tao Bao0940fe12015-08-27 16:41:21 -0700568 struct stat sb;
569 int res = stat(fn.c_str(), &sb);
Sami Tolvanen90221202014-12-09 16:39:47 +0000570
571 if (res == -1) {
572 if (errno != ENOENT || printnoent) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700573 fprintf(stderr, "stat \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Sami Tolvanen90221202014-12-09 16:39:47 +0000574 }
Tao Bao0940fe12015-08-27 16:41:21 -0700575 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000576 }
577
Tao Baoe6aa3322015-08-05 15:20:27 -0700578 fprintf(stderr, " loading %s\n", fn.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000579
Tao Bao0940fe12015-08-27 16:41:21 -0700580 if ((sb.st_size % BLOCKSIZE) != 0) {
Tao Baoba9a42a2015-06-23 23:23:33 -0700581 fprintf(stderr, "%s size %" PRId64 " not multiple of block size %d",
Tao Bao0940fe12015-08-27 16:41:21 -0700582 fn.c_str(), static_cast<int64_t>(sb.st_size), BLOCKSIZE);
583 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000584 }
585
Tao Bao0940fe12015-08-27 16:41:21 -0700586 int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY));
587 unique_fd fd_holder(fd);
Sami Tolvanen90221202014-12-09 16:39:47 +0000588
589 if (fd == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700590 fprintf(stderr, "open \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700591 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000592 }
593
Tao Bao612336d2015-08-27 16:41:21 -0700594 allocate(sb.st_size, buffer);
Sami Tolvanen90221202014-12-09 16:39:47 +0000595
Tao Bao612336d2015-08-27 16:41:21 -0700596 if (read_all(fd, buffer, sb.st_size) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700597 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000598 }
599
Tao Bao0940fe12015-08-27 16:41:21 -0700600 *blocks = sb.st_size / BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +0000601
Tao Bao612336d2015-08-27 16:41:21 -0700602 if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700603 fprintf(stderr, "unexpected contents in %s\n", fn.c_str());
Tao Bao0940fe12015-08-27 16:41:21 -0700604 DeleteFile(fn, nullptr);
605 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000606 }
607
Tao Bao0940fe12015-08-27 16:41:21 -0700608 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000609}
610
Tao Bao612336d2015-08-27 16:41:21 -0700611static int WriteStash(const std::string& base, const std::string& id, int blocks,
612 std::vector<uint8_t>& buffer, bool checkspace, bool *exists) {
613 if (base.empty()) {
Tao Bao0940fe12015-08-27 16:41:21 -0700614 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000615 }
616
617 if (checkspace && CacheSizeCheck(blocks * BLOCKSIZE) != 0) {
618 fprintf(stderr, "not enough space to write stash\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700619 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000620 }
621
Tao Bao0940fe12015-08-27 16:41:21 -0700622 std::string fn = GetStashFileName(base, id, ".partial");
623 std::string cn = GetStashFileName(base, id, "");
Sami Tolvanen90221202014-12-09 16:39:47 +0000624
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100625 if (exists) {
Tao Bao0940fe12015-08-27 16:41:21 -0700626 struct stat sb;
627 int res = stat(cn.c_str(), &sb);
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100628
629 if (res == 0) {
630 // The file already exists and since the name is the hash of the contents,
631 // it's safe to assume the contents are identical (accidental hash collisions
632 // are unlikely)
Tao Baoe6aa3322015-08-05 15:20:27 -0700633 fprintf(stderr, " skipping %d existing blocks in %s\n", blocks, cn.c_str());
Tao Bao0940fe12015-08-27 16:41:21 -0700634 *exists = true;
635 return 0;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100636 }
637
Tao Bao0940fe12015-08-27 16:41:21 -0700638 *exists = false;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100639 }
640
Tao Baoe6aa3322015-08-05 15:20:27 -0700641 fprintf(stderr, " writing %d blocks to %s\n", blocks, cn.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000642
Tao Bao0940fe12015-08-27 16:41:21 -0700643 int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE));
644 unique_fd fd_holder(fd);
Sami Tolvanen90221202014-12-09 16:39:47 +0000645
646 if (fd == -1) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700647 fprintf(stderr, "failed to create \"%s\": %s\n", fn.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700648 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000649 }
650
651 if (write_all(fd, buffer, blocks * BLOCKSIZE) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700652 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000653 }
654
Jed Estepf1fc48c2015-12-15 16:04:53 -0800655 if (ota_fsync(fd) == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700656 failure_type = kFsyncFailure;
Tao Baoe6aa3322015-08-05 15:20:27 -0700657 fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700658 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000659 }
660
Tao Baoe6aa3322015-08-05 15:20:27 -0700661 if (rename(fn.c_str(), cn.c_str()) == -1) {
662 fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", fn.c_str(), cn.c_str(),
663 strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700664 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000665 }
666
Tao Bao0940fe12015-08-27 16:41:21 -0700667 std::string dname = GetStashFileName(base, "", "");
668 int dfd = TEMP_FAILURE_RETRY(open(dname.c_str(), O_RDONLY | O_DIRECTORY));
669 unique_fd dfd_holder(dfd);
Tao Baodc392262015-07-31 15:56:44 -0700670
671 if (dfd == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700672 failure_type = kFileOpenFailure;
Tao Baoe6aa3322015-08-05 15:20:27 -0700673 fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700674 return -1;
Tao Baodc392262015-07-31 15:56:44 -0700675 }
676
Jed Estepf1fc48c2015-12-15 16:04:53 -0800677 if (ota_fsync(dfd) == -1) {
Tianjie Xu16255832016-04-30 11:49:59 -0700678 failure_type = kFsyncFailure;
Tao Baoe6aa3322015-08-05 15:20:27 -0700679 fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -0700680 return -1;
Tao Baodc392262015-07-31 15:56:44 -0700681 }
682
Tao Bao0940fe12015-08-27 16:41:21 -0700683 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000684}
685
686// Creates a directory for storing stash files and checks if the /cache partition
687// hash enough space for the expected amount of blocks we need to store. Returns
688// >0 if we created the directory, zero if it existed already, and <0 of failure.
689
Tao Bao0940fe12015-08-27 16:41:21 -0700690static int CreateStash(State* state, int maxblocks, const char* blockdev, std::string& base) {
691 if (blockdev == nullptr) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700692 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000693 }
694
695 // Stash directory should be different for each partition to avoid conflicts
696 // when updating multiple partitions at the same time, so we use the hash of
697 // the block device name as the base directory
Sen Jiangc48cb5e2016-02-04 16:23:21 +0800698 uint8_t digest[SHA_DIGEST_LENGTH];
699 SHA1(reinterpret_cast<const uint8_t*>(blockdev), strlen(blockdev), digest);
Tao Baoe6aa3322015-08-05 15:20:27 -0700700 base = print_sha1(digest);
Sami Tolvanen90221202014-12-09 16:39:47 +0000701
Tao Baoe6aa3322015-08-05 15:20:27 -0700702 std::string dirname = GetStashFileName(base, "", "");
Tao Bao0940fe12015-08-27 16:41:21 -0700703 struct stat sb;
704 int res = stat(dirname.c_str(), &sb);
Sami Tolvanen90221202014-12-09 16:39:47 +0000705
706 if (res == -1 && errno != ENOENT) {
Tianjie Xu16255832016-04-30 11:49:59 -0700707 ErrorAbort(state, kStashCreationFailure, "stat \"%s\" failed: %s\n",
708 dirname.c_str(), strerror(errno));
Tao Baoe6aa3322015-08-05 15:20:27 -0700709 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000710 } else if (res != 0) {
Tao Baoe6aa3322015-08-05 15:20:27 -0700711 fprintf(stderr, "creating stash %s\n", dirname.c_str());
712 res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE);
Sami Tolvanen90221202014-12-09 16:39:47 +0000713
714 if (res != 0) {
Tianjie Xu16255832016-04-30 11:49:59 -0700715 ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s\n",
716 dirname.c_str(), strerror(errno));
Tao Baoe6aa3322015-08-05 15:20:27 -0700717 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000718 }
719
720 if (CacheSizeCheck(maxblocks * BLOCKSIZE) != 0) {
Tianjie Xu16255832016-04-30 11:49:59 -0700721 ErrorAbort(state, kStashCreationFailure, "not enough space for stash\n");
Tao Baoe6aa3322015-08-05 15:20:27 -0700722 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000723 }
724
Tao Baoe6aa3322015-08-05 15:20:27 -0700725 return 1; // Created directory
Sami Tolvanen90221202014-12-09 16:39:47 +0000726 }
727
Tao Baoe6aa3322015-08-05 15:20:27 -0700728 fprintf(stderr, "using existing stash %s\n", dirname.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000729
730 // If the directory already exists, calculate the space already allocated to
731 // stash files and check if there's enough for all required blocks. Delete any
732 // partially completed stash files first.
733
Tao Bao0940fe12015-08-27 16:41:21 -0700734 EnumerateStash(dirname, DeletePartial, nullptr);
Tao Baoe6aa3322015-08-05 15:20:27 -0700735 int size = 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000736 EnumerateStash(dirname, UpdateFileSize, &size);
737
Tao Bao0940fe12015-08-27 16:41:21 -0700738 size = maxblocks * BLOCKSIZE - size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000739
740 if (size > 0 && CacheSizeCheck(size) != 0) {
Tianjie Xu16255832016-04-30 11:49:59 -0700741 ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%d more needed)\n",
742 size);
Tao Baoe6aa3322015-08-05 15:20:27 -0700743 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000744 }
745
Tao Baoe6aa3322015-08-05 15:20:27 -0700746 return 0; // Using existing directory
Sami Tolvanen90221202014-12-09 16:39:47 +0000747}
748
Tao Baobaad2d42015-12-06 16:56:27 -0800749static int SaveStash(CommandParameters& params, const std::string& base,
750 std::vector<uint8_t>& buffer, int fd, bool usehash) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000751
Tao Baobaad2d42015-12-06 16:56:27 -0800752 // <stash_id> <src_range>
753 if (params.cpos + 1 >= params.tokens.size()) {
754 fprintf(stderr, "missing id and/or src range fields in stash command\n");
Sami Tolvanen90221202014-12-09 16:39:47 +0000755 return -1;
756 }
Tao Baobaad2d42015-12-06 16:56:27 -0800757 const std::string& id = params.tokens[params.cpos++];
Sami Tolvanen90221202014-12-09 16:39:47 +0000758
Tao Bao0940fe12015-08-27 16:41:21 -0700759 size_t blocks = 0;
Tianjie Xu01889352016-03-22 18:08:12 -0700760 if (usehash && LoadStash(params, base, id, true, &blocks, buffer, false) == 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000761 // Stash file already exists and has expected contents. Do not
762 // read from source again, as the source may have been already
763 // overwritten during a previous attempt.
764 return 0;
765 }
766
Tao Bao34847b22015-09-08 11:05:49 -0700767 RangeSet src;
Tao Baobaad2d42015-12-06 16:56:27 -0800768 parse_range(params.tokens[params.cpos++], src);
Tao Bao34847b22015-09-08 11:05:49 -0700769
Tao Bao612336d2015-08-27 16:41:21 -0700770 allocate(src.size * BLOCKSIZE, buffer);
771 if (ReadBlocks(src, buffer, fd) == -1) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000772 return -1;
773 }
Tao Bao34847b22015-09-08 11:05:49 -0700774 blocks = src.size;
Sami Tolvanen90221202014-12-09 16:39:47 +0000775
Tao Bao612336d2015-08-27 16:41:21 -0700776 if (usehash && VerifyBlocks(id, buffer, blocks, true) != 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000777 // Source blocks have unexpected contents. If we actually need this
778 // data later, this is an unrecoverable error. However, the command
779 // that uses the data may have already completed previously, so the
780 // possible failure will occur during source block verification.
Tao Bao0940fe12015-08-27 16:41:21 -0700781 fprintf(stderr, "failed to load source blocks for stash %s\n", id.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000782 return 0;
783 }
784
Tianjie Xu01889352016-03-22 18:08:12 -0700785 // In verify mode, save source range_set instead of stashing blocks.
786 if (!params.canwrite && usehash) {
787 stash_map[id] = src;
788 return 0;
789 }
790
Tao Bao0940fe12015-08-27 16:41:21 -0700791 fprintf(stderr, "stashing %zu blocks to %s\n", blocks, id.c_str());
Tianjie Xudd874b12016-05-13 12:13:15 -0700792 params.stashed += blocks;
Tao Bao612336d2015-08-27 16:41:21 -0700793 return WriteStash(base, id, blocks, buffer, false, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +0000794}
795
Tao Baobaad2d42015-12-06 16:56:27 -0800796static int FreeStash(const std::string& base, const std::string& id) {
797 if (base.empty() || id.empty()) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000798 return -1;
799 }
800
Tao Baobaad2d42015-12-06 16:56:27 -0800801 std::string fn = GetStashFileName(base, id, "");
Tao Bao0940fe12015-08-27 16:41:21 -0700802 DeleteFile(fn, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +0000803
804 return 0;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700805}
806
Tao Bao612336d2015-08-27 16:41:21 -0700807static void MoveRange(std::vector<uint8_t>& dest, const RangeSet& locs,
808 const std::vector<uint8_t>& source) {
Doug Zongker52ae67d2014-09-08 12:22:09 -0700809 // source contains packed data, which we want to move to the
Tao Bao612336d2015-08-27 16:41:21 -0700810 // locations given in locs in the dest buffer. source and dest
Doug Zongker52ae67d2014-09-08 12:22:09 -0700811 // may be the same buffer.
812
Tao Bao612336d2015-08-27 16:41:21 -0700813 const uint8_t* from = source.data();
814 uint8_t* to = dest.data();
Tao Bao0940fe12015-08-27 16:41:21 -0700815 size_t start = locs.size;
816 for (int i = locs.count-1; i >= 0; --i) {
817 size_t blocks = locs.pos[i*2+1] - locs.pos[i*2];
Doug Zongker52ae67d2014-09-08 12:22:09 -0700818 start -= blocks;
Tao Bao612336d2015-08-27 16:41:21 -0700819 memmove(to + (locs.pos[i*2] * BLOCKSIZE), from + (start * BLOCKSIZE),
Doug Zongker52ae67d2014-09-08 12:22:09 -0700820 blocks * BLOCKSIZE);
821 }
822}
823
824// Do a source/target load for move/bsdiff/imgdiff in version 2.
Tao Baobaad2d42015-12-06 16:56:27 -0800825// We expect to parse the remainder of the parameter tokens as one of:
Doug Zongker52ae67d2014-09-08 12:22:09 -0700826//
827// <tgt_range> <src_block_count> <src_range>
828// (loads data from source image only)
829//
830// <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
831// (loads data from stashes only)
832//
833// <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
834// (loads data from both source image and stashes)
835//
836// On return, buffer is filled with the loaded source data (rearranged
837// and combined with stashed data as necessary). buffer may be
838// reallocated if needed to accommodate the source data. *tgt is the
Sami Tolvanen90221202014-12-09 16:39:47 +0000839// target RangeSet. Any stashes required are loaded using LoadStash.
Doug Zongker52ae67d2014-09-08 12:22:09 -0700840
Tao Baobaad2d42015-12-06 16:56:27 -0800841static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
Tao Bao612336d2015-08-27 16:41:21 -0700842 std::vector<uint8_t>& buffer, int fd, const std::string& stashbase, bool* overlap) {
Tao Baobaad2d42015-12-06 16:56:27 -0800843
844 // At least it needs to provide three parameters: <tgt_range>,
845 // <src_block_count> and "-"/<src_range>.
846 if (params.cpos + 2 >= params.tokens.size()) {
847 fprintf(stderr, "invalid parameters\n");
848 return -1;
849 }
850
Tao Bao612336d2015-08-27 16:41:21 -0700851 // <tgt_range>
Tao Baobaad2d42015-12-06 16:56:27 -0800852 parse_range(params.tokens[params.cpos++], tgt);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700853
Tao Bao612336d2015-08-27 16:41:21 -0700854 // <src_block_count>
Tao Baobaad2d42015-12-06 16:56:27 -0800855 const std::string& token = params.tokens[params.cpos++];
856 if (!android::base::ParseUint(token.c_str(), &src_blocks)) {
857 fprintf(stderr, "invalid src_block_count \"%s\"\n", token.c_str());
858 return -1;
859 }
Doug Zongker52ae67d2014-09-08 12:22:09 -0700860
Tao Bao612336d2015-08-27 16:41:21 -0700861 allocate(src_blocks * BLOCKSIZE, buffer);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700862
Tao Bao612336d2015-08-27 16:41:21 -0700863 // "-" or <src_range> [<src_loc>]
Tao Baobaad2d42015-12-06 16:56:27 -0800864 if (params.tokens[params.cpos] == "-") {
Doug Zongker52ae67d2014-09-08 12:22:09 -0700865 // no source ranges, only stashes
Tao Baobaad2d42015-12-06 16:56:27 -0800866 params.cpos++;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700867 } else {
Tao Bao0940fe12015-08-27 16:41:21 -0700868 RangeSet src;
Tao Baobaad2d42015-12-06 16:56:27 -0800869 parse_range(params.tokens[params.cpos++], src);
Tao Bao612336d2015-08-27 16:41:21 -0700870 int res = ReadBlocks(src, buffer, fd);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700871
Tao Bao34847b22015-09-08 11:05:49 -0700872 if (overlap) {
873 *overlap = range_overlaps(src, tgt);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700874 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000875
Sami Tolvanen90221202014-12-09 16:39:47 +0000876 if (res == -1) {
877 return -1;
Doug Zongker52ae67d2014-09-08 12:22:09 -0700878 }
879
Tao Baobaad2d42015-12-06 16:56:27 -0800880 if (params.cpos >= params.tokens.size()) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000881 // no stashes, only source range
882 return 0;
883 }
884
Tao Bao612336d2015-08-27 16:41:21 -0700885 RangeSet locs;
Tao Baobaad2d42015-12-06 16:56:27 -0800886 parse_range(params.tokens[params.cpos++], locs);
Tao Bao612336d2015-08-27 16:41:21 -0700887 MoveRange(buffer, locs, buffer);
Doug Zongker52ae67d2014-09-08 12:22:09 -0700888 }
889
Tao Baobaad2d42015-12-06 16:56:27 -0800890 // <[stash_id:stash_range]>
891 while (params.cpos < params.tokens.size()) {
Doug Zongker52ae67d2014-09-08 12:22:09 -0700892 // Each word is a an index into the stash table, a colon, and
893 // then a rangeset describing where in the source block that
894 // stashed data should go.
Tao Baobaad2d42015-12-06 16:56:27 -0800895 std::vector<std::string> tokens = android::base::Split(params.tokens[params.cpos++], ":");
896 if (tokens.size() != 2) {
897 fprintf(stderr, "invalid parameter\n");
898 return -1;
899 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000900
Tao Bao612336d2015-08-27 16:41:21 -0700901 std::vector<uint8_t> stash;
Tianjie Xu01889352016-03-22 18:08:12 -0700902 int res = LoadStash(params, stashbase, tokens[0], false, nullptr, stash, true);
Sami Tolvanen90221202014-12-09 16:39:47 +0000903
904 if (res == -1) {
905 // These source blocks will fail verification if used later, but we
906 // will let the caller decide if this is a fatal failure
Tao Baobaad2d42015-12-06 16:56:27 -0800907 fprintf(stderr, "failed to load stash %s\n", tokens[0].c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000908 continue;
909 }
910
Tao Bao612336d2015-08-27 16:41:21 -0700911 RangeSet locs;
Tao Baobaad2d42015-12-06 16:56:27 -0800912 parse_range(tokens[1], locs);
Sami Tolvanen90221202014-12-09 16:39:47 +0000913
Tao Bao612336d2015-08-27 16:41:21 -0700914 MoveRange(buffer, locs, stash);
Sami Tolvanen90221202014-12-09 16:39:47 +0000915 }
916
917 return 0;
918}
919
Sami Tolvanen90221202014-12-09 16:39:47 +0000920// Do a source/target load for move/bsdiff/imgdiff in version 3.
921//
922// Parameters are the same as for LoadSrcTgtVersion2, except for 'onehash', which
923// tells the function whether to expect separate source and targe block hashes, or
924// if they are both the same and only one hash should be expected, and
925// 'isunresumable', which receives a non-zero value if block verification fails in
926// a way that the update cannot be resumed anymore.
927//
928// If the function is unable to load the necessary blocks or their contents don't
929// match the hashes, the return value is -1 and the command should be aborted.
930//
931// If the return value is 1, the command has already been completed according to
932// the contents of the target blocks, and should not be performed again.
933//
934// If the return value is 0, source blocks have expected content and the command
935// can be performed.
936
Tao Bao34847b22015-09-08 11:05:49 -0700937static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
Tao Bao0940fe12015-08-27 16:41:21 -0700938 bool onehash, bool& overlap) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000939
Tao Baobaad2d42015-12-06 16:56:27 -0800940 if (params.cpos >= params.tokens.size()) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000941 fprintf(stderr, "missing source hash\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700942 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000943 }
944
Tao Baobaad2d42015-12-06 16:56:27 -0800945 std::string srchash = params.tokens[params.cpos++];
946 std::string tgthash;
947
Sami Tolvanen90221202014-12-09 16:39:47 +0000948 if (onehash) {
949 tgthash = srchash;
950 } else {
Tao Baobaad2d42015-12-06 16:56:27 -0800951 if (params.cpos >= params.tokens.size()) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000952 fprintf(stderr, "missing target hash\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700953 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000954 }
Tao Baobaad2d42015-12-06 16:56:27 -0800955 tgthash = params.tokens[params.cpos++];
Sami Tolvanen90221202014-12-09 16:39:47 +0000956 }
957
Tao Baobaad2d42015-12-06 16:56:27 -0800958 if (LoadSrcTgtVersion2(params, tgt, src_blocks, params.buffer, params.fd, params.stashbase,
959 &overlap) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700960 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000961 }
962
Tao Bao34847b22015-09-08 11:05:49 -0700963 std::vector<uint8_t> tgtbuffer(tgt.size * BLOCKSIZE);
Sami Tolvanen90221202014-12-09 16:39:47 +0000964
Tao Bao612336d2015-08-27 16:41:21 -0700965 if (ReadBlocks(tgt, tgtbuffer, params.fd) == -1) {
Tao Bao0940fe12015-08-27 16:41:21 -0700966 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000967 }
968
Tao Bao612336d2015-08-27 16:41:21 -0700969 if (VerifyBlocks(tgthash, tgtbuffer, tgt.size, false) == 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000970 // Target blocks already have expected content, command should be skipped
Tao Bao0940fe12015-08-27 16:41:21 -0700971 return 1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000972 }
973
Tao Bao0940fe12015-08-27 16:41:21 -0700974 if (VerifyBlocks(srchash, params.buffer, src_blocks, true) == 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000975 // If source and target blocks overlap, stash the source blocks so we can
Tianjie Xu01889352016-03-22 18:08:12 -0700976 // resume from possible write errors. In verify mode, we can skip stashing
977 // because the source blocks won't be overwritten.
978 if (overlap && params.canwrite) {
Tao Baobaad2d42015-12-06 16:56:27 -0800979 fprintf(stderr, "stashing %zu overlapping blocks to %s\n", src_blocks,
980 srchash.c_str());
Sami Tolvanen90221202014-12-09 16:39:47 +0000981
Tao Bao0940fe12015-08-27 16:41:21 -0700982 bool stash_exists = false;
Tao Bao612336d2015-08-27 16:41:21 -0700983 if (WriteStash(params.stashbase, srchash, src_blocks, params.buffer, true,
Tao Bao0940fe12015-08-27 16:41:21 -0700984 &stash_exists) != 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +0000985 fprintf(stderr, "failed to stash overlapping source blocks\n");
Tao Bao0940fe12015-08-27 16:41:21 -0700986 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +0000987 }
988
Tianjie Xudd874b12016-05-13 12:13:15 -0700989 params.stashed += src_blocks;
Sami Tolvanen90221202014-12-09 16:39:47 +0000990 // Can be deleted when the write has completed
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100991 if (!stash_exists) {
Tao Bao0940fe12015-08-27 16:41:21 -0700992 params.freestash = srchash;
Sami Tolvanen43b748f2015-04-17 12:50:31 +0100993 }
Sami Tolvanen90221202014-12-09 16:39:47 +0000994 }
995
996 // Source blocks have expected content, command can proceed
Tao Bao0940fe12015-08-27 16:41:21 -0700997 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +0000998 }
999
Tianjie Xu01889352016-03-22 18:08:12 -07001000 if (overlap && LoadStash(params, params.stashbase, srchash, true, nullptr, params.buffer,
1001 true) == 0) {
Sami Tolvanen43b748f2015-04-17 12:50:31 +01001002 // Overlapping source blocks were previously stashed, command can proceed.
1003 // We are recovering from an interrupted command, so we don't know if the
1004 // stash can safely be deleted after this command.
Tao Bao0940fe12015-08-27 16:41:21 -07001005 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001006 }
1007
1008 // Valid source data not available, update cannot be resumed
1009 fprintf(stderr, "partition has unexpected contents\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001010 params.isunresumable = true;
Sami Tolvanen90221202014-12-09 16:39:47 +00001011
Tao Bao0940fe12015-08-27 16:41:21 -07001012 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001013}
1014
Tao Bao0940fe12015-08-27 16:41:21 -07001015static int PerformCommandMove(CommandParameters& params) {
1016 size_t blocks = 0;
Tao Baoe6aa3322015-08-05 15:20:27 -07001017 bool overlap = false;
Sami Tolvanen90221202014-12-09 16:39:47 +00001018 int status = 0;
Tao Bao0940fe12015-08-27 16:41:21 -07001019 RangeSet tgt;
Sami Tolvanen90221202014-12-09 16:39:47 +00001020
Tao Bao0940fe12015-08-27 16:41:21 -07001021 if (params.version == 1) {
Tao Baobaad2d42015-12-06 16:56:27 -08001022 status = LoadSrcTgtVersion1(params, tgt, blocks, params.buffer, params.fd);
Tao Bao0940fe12015-08-27 16:41:21 -07001023 } else if (params.version == 2) {
Tao Baobaad2d42015-12-06 16:56:27 -08001024 status = LoadSrcTgtVersion2(params, tgt, blocks, params.buffer, params.fd,
Tao Bao612336d2015-08-27 16:41:21 -07001025 params.stashbase, nullptr);
Tao Bao0940fe12015-08-27 16:41:21 -07001026 } else if (params.version >= 3) {
Tao Bao34847b22015-09-08 11:05:49 -07001027 status = LoadSrcTgtVersion3(params, tgt, blocks, true, overlap);
Sami Tolvanen90221202014-12-09 16:39:47 +00001028 }
1029
1030 if (status == -1) {
1031 fprintf(stderr, "failed to read blocks for move\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001032 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001033 }
1034
1035 if (status == 0) {
Tao Bao0940fe12015-08-27 16:41:21 -07001036 params.foundwrites = true;
1037 } else if (params.foundwrites) {
1038 fprintf(stderr, "warning: commands executed out of order [%s]\n", params.cmdname);
Sami Tolvanen90221202014-12-09 16:39:47 +00001039 }
1040
Tao Bao0940fe12015-08-27 16:41:21 -07001041 if (params.canwrite) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001042 if (status == 0) {
Tao Bao0940fe12015-08-27 16:41:21 -07001043 fprintf(stderr, " moving %zu blocks\n", blocks);
Sami Tolvanen90221202014-12-09 16:39:47 +00001044
Tao Bao0940fe12015-08-27 16:41:21 -07001045 if (WriteBlocks(tgt, params.buffer, params.fd) == -1) {
1046 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001047 }
1048 } else {
Tao Bao0940fe12015-08-27 16:41:21 -07001049 fprintf(stderr, "skipping %zu already moved blocks\n", blocks);
Sami Tolvanen90221202014-12-09 16:39:47 +00001050 }
1051
1052 }
1053
Tao Baobaad2d42015-12-06 16:56:27 -08001054 if (!params.freestash.empty()) {
Tao Bao0940fe12015-08-27 16:41:21 -07001055 FreeStash(params.stashbase, params.freestash);
Tao Baobaad2d42015-12-06 16:56:27 -08001056 params.freestash.clear();
Sami Tolvanen90221202014-12-09 16:39:47 +00001057 }
1058
Tao Bao0940fe12015-08-27 16:41:21 -07001059 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001060
Tao Bao0940fe12015-08-27 16:41:21 -07001061 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001062}
1063
Tao Bao0940fe12015-08-27 16:41:21 -07001064static int PerformCommandStash(CommandParameters& params) {
Tao Baobaad2d42015-12-06 16:56:27 -08001065 return SaveStash(params, params.stashbase, params.buffer, params.fd,
Tao Bao612336d2015-08-27 16:41:21 -07001066 (params.version >= 3));
Sami Tolvanen90221202014-12-09 16:39:47 +00001067}
1068
Tao Bao0940fe12015-08-27 16:41:21 -07001069static int PerformCommandFree(CommandParameters& params) {
Tao Baobaad2d42015-12-06 16:56:27 -08001070 // <stash_id>
1071 if (params.cpos >= params.tokens.size()) {
1072 fprintf(stderr, "missing stash id in free command\n");
1073 return -1;
1074 }
1075
Tianjie Xu01889352016-03-22 18:08:12 -07001076 const std::string& id = params.tokens[params.cpos++];
1077
1078 if (!params.canwrite && stash_map.find(id) != stash_map.end()) {
1079 stash_map.erase(id);
1080 return 0;
1081 }
1082
Tao Bao0940fe12015-08-27 16:41:21 -07001083 if (params.createdstash || params.canwrite) {
Tianjie Xu01889352016-03-22 18:08:12 -07001084 return FreeStash(params.stashbase, id);
Sami Tolvanen90221202014-12-09 16:39:47 +00001085 }
1086
1087 return 0;
1088}
1089
Tao Bao0940fe12015-08-27 16:41:21 -07001090static int PerformCommandZero(CommandParameters& params) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001091
Tao Baobaad2d42015-12-06 16:56:27 -08001092 if (params.cpos >= params.tokens.size()) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001093 fprintf(stderr, "missing target blocks for zero\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001094 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001095 }
1096
Tao Bao0940fe12015-08-27 16:41:21 -07001097 RangeSet tgt;
Tao Baobaad2d42015-12-06 16:56:27 -08001098 parse_range(params.tokens[params.cpos++], tgt);
Sami Tolvanen90221202014-12-09 16:39:47 +00001099
Tao Bao0940fe12015-08-27 16:41:21 -07001100 fprintf(stderr, " zeroing %zu blocks\n", tgt.size);
Sami Tolvanen90221202014-12-09 16:39:47 +00001101
Tao Bao612336d2015-08-27 16:41:21 -07001102 allocate(BLOCKSIZE, params.buffer);
1103 memset(params.buffer.data(), 0, BLOCKSIZE);
Sami Tolvanen90221202014-12-09 16:39:47 +00001104
Tao Bao0940fe12015-08-27 16:41:21 -07001105 if (params.canwrite) {
1106 for (size_t i = 0; i < tgt.count; ++i) {
1107 if (!check_lseek(params.fd, (off64_t) tgt.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
1108 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001109 }
1110
Tao Bao0940fe12015-08-27 16:41:21 -07001111 for (size_t j = tgt.pos[i * 2]; j < tgt.pos[i * 2 + 1]; ++j) {
1112 if (write_all(params.fd, params.buffer, BLOCKSIZE) == -1) {
1113 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001114 }
1115 }
1116 }
1117 }
1118
Tao Bao0940fe12015-08-27 16:41:21 -07001119 if (params.cmdname[0] == 'z') {
Sami Tolvanene82fa182015-06-10 15:58:12 +00001120 // Update only for the zero command, as the erase command will call
1121 // this if DEBUG_ERASE is defined.
Tao Bao0940fe12015-08-27 16:41:21 -07001122 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001123 }
1124
Tao Bao0940fe12015-08-27 16:41:21 -07001125 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001126}
1127
Tao Bao0940fe12015-08-27 16:41:21 -07001128static int PerformCommandNew(CommandParameters& params) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001129
Tao Baobaad2d42015-12-06 16:56:27 -08001130 if (params.cpos >= params.tokens.size()) {
1131 fprintf(stderr, "missing target blocks for new\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001132 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001133 }
1134
Tao Bao0940fe12015-08-27 16:41:21 -07001135 RangeSet tgt;
Tao Baobaad2d42015-12-06 16:56:27 -08001136 parse_range(params.tokens[params.cpos++], tgt);
Sami Tolvanen90221202014-12-09 16:39:47 +00001137
Tao Bao0940fe12015-08-27 16:41:21 -07001138 if (params.canwrite) {
1139 fprintf(stderr, " writing %zu blocks of new data\n", tgt.size);
Sami Tolvanen90221202014-12-09 16:39:47 +00001140
Tao Bao0940fe12015-08-27 16:41:21 -07001141 RangeSinkState rss(tgt);
1142 rss.fd = params.fd;
Sami Tolvanen90221202014-12-09 16:39:47 +00001143 rss.p_block = 0;
Tao Bao0940fe12015-08-27 16:41:21 -07001144 rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001145
Tao Bao0940fe12015-08-27 16:41:21 -07001146 if (!check_lseek(params.fd, (off64_t) tgt.pos[0] * BLOCKSIZE, SEEK_SET)) {
1147 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001148 }
1149
Tao Bao0940fe12015-08-27 16:41:21 -07001150 pthread_mutex_lock(&params.nti.mu);
1151 params.nti.rss = &rss;
1152 pthread_cond_broadcast(&params.nti.cv);
Sami Tolvanen90221202014-12-09 16:39:47 +00001153
Tao Bao0940fe12015-08-27 16:41:21 -07001154 while (params.nti.rss) {
1155 pthread_cond_wait(&params.nti.cv, &params.nti.mu);
Sami Tolvanen90221202014-12-09 16:39:47 +00001156 }
1157
Tao Bao0940fe12015-08-27 16:41:21 -07001158 pthread_mutex_unlock(&params.nti.mu);
Sami Tolvanen90221202014-12-09 16:39:47 +00001159 }
1160
Tao Bao0940fe12015-08-27 16:41:21 -07001161 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001162
Tao Bao0940fe12015-08-27 16:41:21 -07001163 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001164}
1165
Tao Bao0940fe12015-08-27 16:41:21 -07001166static int PerformCommandDiff(CommandParameters& params) {
Tao Bao0940fe12015-08-27 16:41:21 -07001167
Tao Baobaad2d42015-12-06 16:56:27 -08001168 // <offset> <length>
1169 if (params.cpos + 1 >= params.tokens.size()) {
1170 fprintf(stderr, "missing patch offset or length for %s\n", params.cmdname);
Tao Bao0940fe12015-08-27 16:41:21 -07001171 return -1;
1172 }
1173
Tao Baobaad2d42015-12-06 16:56:27 -08001174 size_t offset;
1175 if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &offset)) {
1176 fprintf(stderr, "invalid patch offset\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001177 return -1;
1178 }
1179
Tao Baobaad2d42015-12-06 16:56:27 -08001180 size_t len;
1181 if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &len)) {
1182 fprintf(stderr, "invalid patch offset\n");
1183 return -1;
1184 }
Tao Bao0940fe12015-08-27 16:41:21 -07001185
Tao Bao612336d2015-08-27 16:41:21 -07001186 RangeSet tgt;
Tao Bao0940fe12015-08-27 16:41:21 -07001187 size_t blocks = 0;
Tao Bao612336d2015-08-27 16:41:21 -07001188 bool overlap = false;
Sami Tolvanen90221202014-12-09 16:39:47 +00001189 int status = 0;
Tao Bao0940fe12015-08-27 16:41:21 -07001190 if (params.version == 1) {
Tao Baobaad2d42015-12-06 16:56:27 -08001191 status = LoadSrcTgtVersion1(params, tgt, blocks, params.buffer, params.fd);
Tao Bao0940fe12015-08-27 16:41:21 -07001192 } else if (params.version == 2) {
Tao Baobaad2d42015-12-06 16:56:27 -08001193 status = LoadSrcTgtVersion2(params, tgt, blocks, params.buffer, params.fd,
Tao Bao612336d2015-08-27 16:41:21 -07001194 params.stashbase, nullptr);
Tao Bao0940fe12015-08-27 16:41:21 -07001195 } else if (params.version >= 3) {
Tao Bao34847b22015-09-08 11:05:49 -07001196 status = LoadSrcTgtVersion3(params, tgt, blocks, false, overlap);
Sami Tolvanen90221202014-12-09 16:39:47 +00001197 }
1198
1199 if (status == -1) {
1200 fprintf(stderr, "failed to read blocks for diff\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001201 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001202 }
1203
1204 if (status == 0) {
Tao Bao0940fe12015-08-27 16:41:21 -07001205 params.foundwrites = true;
1206 } else if (params.foundwrites) {
1207 fprintf(stderr, "warning: commands executed out of order [%s]\n", params.cmdname);
Sami Tolvanen90221202014-12-09 16:39:47 +00001208 }
1209
Tao Bao0940fe12015-08-27 16:41:21 -07001210 if (params.canwrite) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001211 if (status == 0) {
Tao Bao0940fe12015-08-27 16:41:21 -07001212 fprintf(stderr, "patching %zu blocks to %zu\n", blocks, tgt.size);
Sami Tolvanen90221202014-12-09 16:39:47 +00001213
Tao Bao0940fe12015-08-27 16:41:21 -07001214 Value patch_value;
Sami Tolvanen90221202014-12-09 16:39:47 +00001215 patch_value.type = VAL_BLOB;
1216 patch_value.size = len;
Tao Bao0940fe12015-08-27 16:41:21 -07001217 patch_value.data = (char*) (params.patch_start + offset);
Sami Tolvanen90221202014-12-09 16:39:47 +00001218
Tao Bao0940fe12015-08-27 16:41:21 -07001219 RangeSinkState rss(tgt);
1220 rss.fd = params.fd;
Sami Tolvanen90221202014-12-09 16:39:47 +00001221 rss.p_block = 0;
Tao Bao0940fe12015-08-27 16:41:21 -07001222 rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001223
Tao Bao0940fe12015-08-27 16:41:21 -07001224 if (!check_lseek(params.fd, (off64_t) tgt.pos[0] * BLOCKSIZE, SEEK_SET)) {
1225 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001226 }
1227
Tao Bao0940fe12015-08-27 16:41:21 -07001228 if (params.cmdname[0] == 'i') { // imgdiff
Tao Bao612336d2015-08-27 16:41:21 -07001229 ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value,
Tao Bao0940fe12015-08-27 16:41:21 -07001230 &RangeSinkWrite, &rss, nullptr, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +00001231 } else {
Tao Bao612336d2015-08-27 16:41:21 -07001232 ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, 0,
1233 &RangeSinkWrite, &rss, nullptr);
Sami Tolvanen90221202014-12-09 16:39:47 +00001234 }
1235
1236 // We expect the output of the patcher to fill the tgt ranges exactly.
Tao Bao0940fe12015-08-27 16:41:21 -07001237 if (rss.p_block != tgt.count || rss.p_remain != 0) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001238 fprintf(stderr, "range sink underrun?\n");
1239 }
1240 } else {
Tao Bao0940fe12015-08-27 16:41:21 -07001241 fprintf(stderr, "skipping %zu blocks already patched to %zu [%s]\n",
Tao Baobaad2d42015-12-06 16:56:27 -08001242 blocks, tgt.size, params.cmdline);
Sami Tolvanen90221202014-12-09 16:39:47 +00001243 }
1244 }
1245
Tao Baobaad2d42015-12-06 16:56:27 -08001246 if (!params.freestash.empty()) {
Tao Bao0940fe12015-08-27 16:41:21 -07001247 FreeStash(params.stashbase, params.freestash);
Tao Baobaad2d42015-12-06 16:56:27 -08001248 params.freestash.clear();
Sami Tolvanen90221202014-12-09 16:39:47 +00001249 }
1250
Tao Bao0940fe12015-08-27 16:41:21 -07001251 params.written += tgt.size;
Sami Tolvanen90221202014-12-09 16:39:47 +00001252
Tao Bao0940fe12015-08-27 16:41:21 -07001253 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001254}
1255
Tao Bao0940fe12015-08-27 16:41:21 -07001256static int PerformCommandErase(CommandParameters& params) {
Sami Tolvanene82fa182015-06-10 15:58:12 +00001257 if (DEBUG_ERASE) {
1258 return PerformCommandZero(params);
Sami Tolvanen90221202014-12-09 16:39:47 +00001259 }
1260
Tao Bao0940fe12015-08-27 16:41:21 -07001261 struct stat sb;
1262 if (fstat(params.fd, &sb) == -1) {
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001263 fprintf(stderr, "failed to fstat device to erase: %s\n", strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -07001264 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001265 }
1266
Tao Bao0940fe12015-08-27 16:41:21 -07001267 if (!S_ISBLK(sb.st_mode)) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001268 fprintf(stderr, "not a block device; skipping erase\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001269 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001270 }
1271
Tao Baobaad2d42015-12-06 16:56:27 -08001272 if (params.cpos >= params.tokens.size()) {
Tao Baoba9a42a2015-06-23 23:23:33 -07001273 fprintf(stderr, "missing target blocks for erase\n");
Tao Bao0940fe12015-08-27 16:41:21 -07001274 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001275 }
1276
Tao Bao0940fe12015-08-27 16:41:21 -07001277 RangeSet tgt;
Tao Baobaad2d42015-12-06 16:56:27 -08001278 parse_range(params.tokens[params.cpos++], tgt);
Sami Tolvanen90221202014-12-09 16:39:47 +00001279
Tao Bao0940fe12015-08-27 16:41:21 -07001280 if (params.canwrite) {
1281 fprintf(stderr, " erasing %zu blocks\n", tgt.size);
Sami Tolvanen90221202014-12-09 16:39:47 +00001282
Tao Bao0940fe12015-08-27 16:41:21 -07001283 for (size_t i = 0; i < tgt.count; ++i) {
1284 uint64_t blocks[2];
Sami Tolvanen90221202014-12-09 16:39:47 +00001285 // offset in bytes
Tao Bao0940fe12015-08-27 16:41:21 -07001286 blocks[0] = tgt.pos[i * 2] * (uint64_t) BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001287 // length in bytes
Tao Bao0940fe12015-08-27 16:41:21 -07001288 blocks[1] = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * (uint64_t) BLOCKSIZE;
Sami Tolvanen90221202014-12-09 16:39:47 +00001289
Tao Bao0940fe12015-08-27 16:41:21 -07001290 if (ioctl(params.fd, BLKDISCARD, &blocks) == -1) {
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001291 fprintf(stderr, "BLKDISCARD ioctl failed: %s\n", strerror(errno));
Tao Bao0940fe12015-08-27 16:41:21 -07001292 return -1;
Sami Tolvanen90221202014-12-09 16:39:47 +00001293 }
1294 }
1295 }
1296
Tao Bao0940fe12015-08-27 16:41:21 -07001297 return 0;
Sami Tolvanen90221202014-12-09 16:39:47 +00001298}
1299
1300// Definitions for transfer list command functions
Tao Bao0940fe12015-08-27 16:41:21 -07001301typedef int (*CommandFunction)(CommandParameters&);
Sami Tolvanen90221202014-12-09 16:39:47 +00001302
Tao Bao612336d2015-08-27 16:41:21 -07001303struct Command {
Sami Tolvanen90221202014-12-09 16:39:47 +00001304 const char* name;
1305 CommandFunction f;
Tao Bao612336d2015-08-27 16:41:21 -07001306};
Sami Tolvanen90221202014-12-09 16:39:47 +00001307
1308// CompareCommands and CompareCommandNames are for the hash table
1309
1310static int CompareCommands(const void* c1, const void* c2) {
1311 return strcmp(((const Command*) c1)->name, ((const Command*) c2)->name);
1312}
1313
1314static int CompareCommandNames(const void* c1, const void* c2) {
1315 return strcmp(((const Command*) c1)->name, (const char*) c2);
1316}
1317
1318// HashString is used to hash command names for the hash table
1319
1320static unsigned int HashString(const char *s) {
1321 unsigned int hash = 0;
1322 if (s) {
1323 while (*s) {
1324 hash = hash * 33 + *s++;
1325 }
1326 }
1327 return hash;
Doug Zongker52ae67d2014-09-08 12:22:09 -07001328}
1329
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001330// args:
1331// - block device (or file) to modify in-place
1332// - transfer list (blob)
1333// - new data stream (filename within package.zip)
1334// - patch stream (filename within package.zip, must be uncompressed)
1335
Tao Bao0940fe12015-08-27 16:41:21 -07001336static Value* PerformBlockImageUpdate(const char* name, State* state, int /* argc */, Expr* argv[],
1337 const Command* commands, size_t cmdcount, bool dryrun) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001338 CommandParameters params;
Sami Tolvanen90221202014-12-09 16:39:47 +00001339 memset(&params, 0, sizeof(params));
1340 params.canwrite = !dryrun;
1341
1342 fprintf(stderr, "performing %s\n", dryrun ? "verification" : "update");
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001343
Tao Bao612336d2015-08-27 16:41:21 -07001344 Value* blockdev_filename = nullptr;
1345 Value* transfer_list_value = nullptr;
1346 Value* new_data_fn = nullptr;
1347 Value* patch_data_fn = nullptr;
Doug Zongker1d5d6092014-08-21 10:47:24 -07001348 if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value,
Sami Tolvanen90221202014-12-09 16:39:47 +00001349 &new_data_fn, &patch_data_fn) < 0) {
Tao Bao612336d2015-08-27 16:41:21 -07001350 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001351 }
Tao Bao612336d2015-08-27 16:41:21 -07001352 std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename,
1353 FreeValue);
1354 std::unique_ptr<Value, decltype(&FreeValue)> transfer_list_value_holder(transfer_list_value,
1355 FreeValue);
1356 std::unique_ptr<Value, decltype(&FreeValue)> new_data_fn_holder(new_data_fn, FreeValue);
1357 std::unique_ptr<Value, decltype(&FreeValue)> patch_data_fn_holder(patch_data_fn, FreeValue);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001358
1359 if (blockdev_filename->type != VAL_STRING) {
Tianjie Xu16255832016-04-30 11:49:59 -07001360 ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string",
1361 name);
Tao Bao612336d2015-08-27 16:41:21 -07001362 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001363 }
Doug Zongker1d5d6092014-08-21 10:47:24 -07001364 if (transfer_list_value->type != VAL_BLOB) {
Tianjie Xu16255832016-04-30 11:49:59 -07001365 ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name);
Tao Bao612336d2015-08-27 16:41:21 -07001366 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001367 }
1368 if (new_data_fn->type != VAL_STRING) {
Tianjie Xu16255832016-04-30 11:49:59 -07001369 ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name);
Tao Bao612336d2015-08-27 16:41:21 -07001370 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001371 }
1372 if (patch_data_fn->type != VAL_STRING) {
Tianjie Xu16255832016-04-30 11:49:59 -07001373 ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string",
1374 name);
Tao Bao612336d2015-08-27 16:41:21 -07001375 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001376 }
1377
Tao Bao612336d2015-08-27 16:41:21 -07001378 UpdaterInfo* ui = reinterpret_cast<UpdaterInfo*>(state->cookie);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001379
Tao Bao0940fe12015-08-27 16:41:21 -07001380 if (ui == nullptr) {
Tao Bao612336d2015-08-27 16:41:21 -07001381 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001382 }
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001383
Tao Bao612336d2015-08-27 16:41:21 -07001384 FILE* cmd_pipe = ui->cmd_pipe;
1385 ZipArchive* za = ui->package_zip;
Sami Tolvanen90221202014-12-09 16:39:47 +00001386
Tao Bao0940fe12015-08-27 16:41:21 -07001387 if (cmd_pipe == nullptr || za == nullptr) {
Tao Bao612336d2015-08-27 16:41:21 -07001388 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001389 }
1390
Tao Bao612336d2015-08-27 16:41:21 -07001391 const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data);
Tao Bao0940fe12015-08-27 16:41:21 -07001392 if (patch_entry == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001393 fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data);
Tao Bao612336d2015-08-27 16:41:21 -07001394 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001395 }
1396
Sami Tolvanen90221202014-12-09 16:39:47 +00001397 params.patch_start = ui->package_zip_addr + mzGetZipEntryOffset(patch_entry);
Tao Bao612336d2015-08-27 16:41:21 -07001398 const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data);
Tao Bao0940fe12015-08-27 16:41:21 -07001399 if (new_entry == nullptr) {
Sami Tolvanen90221202014-12-09 16:39:47 +00001400 fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data);
Tao Bao612336d2015-08-27 16:41:21 -07001401 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001402 }
1403
Sami Tolvanen90221202014-12-09 16:39:47 +00001404 params.fd = TEMP_FAILURE_RETRY(open(blockdev_filename->data, O_RDWR));
Tao Bao612336d2015-08-27 16:41:21 -07001405 unique_fd fd_holder(params.fd);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001406
Sami Tolvanen90221202014-12-09 16:39:47 +00001407 if (params.fd == -1) {
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001408 fprintf(stderr, "open \"%s\" failed: %s\n", blockdev_filename->data, strerror(errno));
Tao Bao612336d2015-08-27 16:41:21 -07001409 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001410 }
1411
Sami Tolvanen90221202014-12-09 16:39:47 +00001412 if (params.canwrite) {
1413 params.nti.za = za;
1414 params.nti.entry = new_entry;
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001415
Tao Bao0940fe12015-08-27 16:41:21 -07001416 pthread_mutex_init(&params.nti.mu, nullptr);
1417 pthread_cond_init(&params.nti.cv, nullptr);
Tao Bao612336d2015-08-27 16:41:21 -07001418 pthread_attr_t attr;
Sami Tolvanen90221202014-12-09 16:39:47 +00001419 pthread_attr_init(&attr);
1420 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1421
Elliott Hughes1fdd4522015-03-23 13:33:57 -07001422 int error = pthread_create(&params.thread, &attr, unzip_new_data, &params.nti);
1423 if (error != 0) {
1424 fprintf(stderr, "pthread_create failed: %s\n", strerror(error));
Tao Bao612336d2015-08-27 16:41:21 -07001425 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001426 }
1427 }
1428
Tao Baobaad2d42015-12-06 16:56:27 -08001429 // Copy all the lines in transfer_list_value into std::string for
1430 // processing.
Tao Bao612336d2015-08-27 16:41:21 -07001431 const std::string transfer_list(transfer_list_value->data, transfer_list_value->size);
1432 std::vector<std::string> lines = android::base::Split(transfer_list, "\n");
Tao Baobaad2d42015-12-06 16:56:27 -08001433 if (lines.size() < 2) {
Tianjie Xu16255832016-04-30 11:49:59 -07001434 ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zd]\n",
1435 lines.size());
Tao Baobaad2d42015-12-06 16:56:27 -08001436 return StringValue(strdup(""));
1437 }
Doug Zongker1d5d6092014-08-21 10:47:24 -07001438
Sami Tolvanen90221202014-12-09 16:39:47 +00001439 // First line in transfer list is the version number
Tao Bao1fdec862015-10-21 14:57:44 -07001440 if (!android::base::ParseInt(lines[0].c_str(), &params.version, 1, 4)) {
Tao Bao612336d2015-08-27 16:41:21 -07001441 fprintf(stderr, "unexpected transfer list version [%s]\n", lines[0].c_str());
1442 return StringValue(strdup(""));
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001443 }
1444
Sami Tolvanen90221202014-12-09 16:39:47 +00001445 fprintf(stderr, "blockimg version is %d\n", params.version);
1446
1447 // Second line in transfer list is the total number of blocks we expect to write
Tao Baob15fd222015-09-24 11:10:51 -07001448 int total_blocks;
1449 if (!android::base::ParseInt(lines[1].c_str(), &total_blocks, 0)) {
Tianjie Xu16255832016-04-30 11:49:59 -07001450 ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str());
Tao Bao612336d2015-08-27 16:41:21 -07001451 return StringValue(strdup(""));
Tao Baob15fd222015-09-24 11:10:51 -07001452 }
1453
1454 if (total_blocks == 0) {
Tao Bao612336d2015-08-27 16:41:21 -07001455 return StringValue(strdup("t"));
Sami Tolvanen90221202014-12-09 16:39:47 +00001456 }
1457
Tao Bao612336d2015-08-27 16:41:21 -07001458 size_t start = 2;
Sami Tolvanen90221202014-12-09 16:39:47 +00001459 if (params.version >= 2) {
Tao Baobaad2d42015-12-06 16:56:27 -08001460 if (lines.size() < 4) {
Tianjie Xu16255832016-04-30 11:49:59 -07001461 ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n",
1462 lines.size());
Tao Baobaad2d42015-12-06 16:56:27 -08001463 return StringValue(strdup(""));
1464 }
1465
Sami Tolvanen90221202014-12-09 16:39:47 +00001466 // Third line is how many stash entries are needed simultaneously
Tao Bao612336d2015-08-27 16:41:21 -07001467 fprintf(stderr, "maximum stash entries %s\n", lines[2].c_str());
Doug Zongker52ae67d2014-09-08 12:22:09 -07001468
Sami Tolvanen90221202014-12-09 16:39:47 +00001469 // Fourth line is the maximum number of blocks that will be stashed simultaneously
Tao Baob15fd222015-09-24 11:10:51 -07001470 int stash_max_blocks;
1471 if (!android::base::ParseInt(lines[3].c_str(), &stash_max_blocks, 0)) {
Tianjie Xu16255832016-04-30 11:49:59 -07001472 ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n",
1473 lines[3].c_str());
Tao Bao612336d2015-08-27 16:41:21 -07001474 return StringValue(strdup(""));
Doug Zongker52ae67d2014-09-08 12:22:09 -07001475 }
1476
Tao Baob15fd222015-09-24 11:10:51 -07001477 int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase);
Tao Baob15fd222015-09-24 11:10:51 -07001478 if (res == -1) {
1479 return StringValue(strdup(""));
Sami Tolvanen90221202014-12-09 16:39:47 +00001480 }
Tao Bao612336d2015-08-27 16:41:21 -07001481
Tao Baob15fd222015-09-24 11:10:51 -07001482 params.createdstash = res;
1483
Tao Bao612336d2015-08-27 16:41:21 -07001484 start += 2;
Doug Zongker52ae67d2014-09-08 12:22:09 -07001485 }
1486
Sami Tolvanen90221202014-12-09 16:39:47 +00001487 // Build a hash table of the available commands
Tao Bao612336d2015-08-27 16:41:21 -07001488 HashTable* cmdht = mzHashTableCreate(cmdcount, nullptr);
1489 std::unique_ptr<HashTable, decltype(&mzHashTableFree)> cmdht_holder(cmdht, mzHashTableFree);
Doug Zongkerbc7ffed2014-08-15 14:31:52 -07001490
Tao Bao0940fe12015-08-27 16:41:21 -07001491 for (size_t i = 0; i < cmdcount; ++i) {
1492 unsigned int cmdhash = HashString(commands[i].name);
Sami Tolvanen90221202014-12-09 16:39:47 +00001493 mzHashTableLookup(cmdht, cmdhash, (void*) &commands[i], CompareCommands, true);
1494 }
1495
Tao Bao612336d2015-08-27 16:41:21 -07001496 int rc = -1;
Doug Zongker