• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <linux/fs.h>
23 #include <pthread.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <sys/ioctl.h>
32 #include <time.h>
33 #include <unistd.h>
34 #include <fec/io.h>
35 
36 #include <map>
37 #include <memory>
38 #include <string>
39 #include <vector>
40 
41 #include <android-base/parseint.h>
42 #include <android-base/strings.h>
43 
44 #include "applypatch/applypatch.h"
45 #include "edify/expr.h"
46 #include "error_code.h"
47 #include "install.h"
48 #include "openssl/sha.h"
49 #include "minzip/Hash.h"
50 #include "ota_io.h"
51 #include "print_sha1.h"
52 #include "unique_fd.h"
53 #include "updater.h"
54 
55 #define BLOCKSIZE 4096
56 
57 // 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 
62 #define STASH_DIRECTORY_BASE "/cache/recovery"
63 #define STASH_DIRECTORY_MODE 0700
64 #define STASH_FILE_MODE 0600
65 
66 struct RangeSet {
67     size_t count;             // Limit is INT_MAX.
68     size_t size;
69     std::vector<size_t> pos;  // Actual limit is INT_MAX.
70 };
71 
72 static CauseCode failure_type = kNoCause;
73 static bool is_retry = false;
74 static std::map<std::string, RangeSet> stash_map;
75 
parse_range(const std::string & range_text,RangeSet & rs)76 static void parse_range(const std::string& range_text, RangeSet& rs) {
77 
78     std::vector<std::string> pieces = android::base::Split(range_text, ",");
79     if (pieces.size() < 3) {
80         goto err;
81     }
82 
83     size_t num;
84     if (!android::base::ParseUint(pieces[0].c_str(), &num, static_cast<size_t>(INT_MAX))) {
85         goto err;
86     }
87 
88     if (num == 0 || num % 2) {
89         goto err; // must be even
90     } else if (num != pieces.size() - 1) {
91         goto err;
92     }
93 
94     rs.pos.resize(num);
95     rs.count = num / 2;
96     rs.size = 0;
97 
98     for (size_t i = 0; i < num; i += 2) {
99         if (!android::base::ParseUint(pieces[i+1].c_str(), &rs.pos[i],
100                                       static_cast<size_t>(INT_MAX))) {
101             goto err;
102         }
103 
104         if (!android::base::ParseUint(pieces[i+2].c_str(), &rs.pos[i+1],
105                                       static_cast<size_t>(INT_MAX))) {
106             goto err;
107         }
108 
109         if (rs.pos[i] >= rs.pos[i+1]) {
110             goto err; // empty or negative range
111         }
112 
113         size_t sz = rs.pos[i+1] - rs.pos[i];
114         if (rs.size > SIZE_MAX - sz) {
115             goto err; // overflow
116         }
117 
118         rs.size += sz;
119     }
120 
121     return;
122 
123 err:
124     fprintf(stderr, "failed to parse range '%s'\n", range_text.c_str());
125     exit(1);
126 }
127 
range_overlaps(const RangeSet & r1,const RangeSet & r2)128 static bool range_overlaps(const RangeSet& r1, const RangeSet& r2) {
129     for (size_t i = 0; i < r1.count; ++i) {
130         size_t r1_0 = r1.pos[i * 2];
131         size_t r1_1 = r1.pos[i * 2 + 1];
132 
133         for (size_t j = 0; j < r2.count; ++j) {
134             size_t r2_0 = r2.pos[j * 2];
135             size_t r2_1 = r2.pos[j * 2 + 1];
136 
137             if (!(r2_0 >= r1_1 || r1_0 >= r2_1)) {
138                 return true;
139             }
140         }
141     }
142 
143     return false;
144 }
145 
read_all(int fd,uint8_t * data,size_t size)146 static int read_all(int fd, uint8_t* data, size_t size) {
147     size_t so_far = 0;
148     while (so_far < size) {
149         ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far));
150         if (r == -1) {
151             failure_type = kFreadFailure;
152             fprintf(stderr, "read failed: %s\n", strerror(errno));
153             return -1;
154         }
155         so_far += r;
156     }
157     return 0;
158 }
159 
read_all(int fd,std::vector<uint8_t> & buffer,size_t size)160 static int read_all(int fd, std::vector<uint8_t>& buffer, size_t size) {
161     return read_all(fd, buffer.data(), size);
162 }
163 
write_all(int fd,const uint8_t * data,size_t size)164 static int write_all(int fd, const uint8_t* data, size_t size) {
165     size_t written = 0;
166     while (written < size) {
167         ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written));
168         if (w == -1) {
169             failure_type = kFwriteFailure;
170             fprintf(stderr, "write failed: %s\n", strerror(errno));
171             return -1;
172         }
173         written += w;
174     }
175 
176     return 0;
177 }
178 
write_all(int fd,const std::vector<uint8_t> & buffer,size_t size)179 static int write_all(int fd, const std::vector<uint8_t>& buffer, size_t size) {
180     return write_all(fd, buffer.data(), size);
181 }
182 
discard_blocks(int fd,off64_t offset,uint64_t size)183 static bool discard_blocks(int fd, off64_t offset, uint64_t size) {
184     // Don't discard blocks unless the update is a retry run.
185     if (!is_retry) {
186         return true;
187     }
188 
189     uint64_t args[2] = {static_cast<uint64_t>(offset), size};
190     int status = ioctl(fd, BLKDISCARD, &args);
191     if (status == -1) {
192         fprintf(stderr, "BLKDISCARD ioctl failed: %s\n", strerror(errno));
193         return false;
194     }
195     return true;
196 }
197 
check_lseek(int fd,off64_t offset,int whence)198 static bool check_lseek(int fd, off64_t offset, int whence) {
199     off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence));
200     if (rc == -1) {
201         failure_type = kLseekFailure;
202         fprintf(stderr, "lseek64 failed: %s\n", strerror(errno));
203         return false;
204     }
205     return true;
206 }
207 
allocate(size_t size,std::vector<uint8_t> & buffer)208 static void allocate(size_t size, std::vector<uint8_t>& buffer) {
209     // if the buffer's big enough, reuse it.
210     if (size <= buffer.size()) return;
211 
212     buffer.resize(size);
213 }
214 
215 struct RangeSinkState {
RangeSinkStateRangeSinkState216     RangeSinkState(RangeSet& rs) : tgt(rs) { };
217 
218     int fd;
219     const RangeSet& tgt;
220     size_t p_block;
221     size_t p_remain;
222 };
223 
RangeSinkWrite(const uint8_t * data,ssize_t size,void * token)224 static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
225     RangeSinkState* rss = reinterpret_cast<RangeSinkState*>(token);
226 
227     if (rss->p_remain == 0) {
228         fprintf(stderr, "range sink write overrun");
229         return 0;
230     }
231 
232     ssize_t written = 0;
233     while (size > 0) {
234         size_t write_now = size;
235 
236         if (rss->p_remain < write_now) {
237             write_now = rss->p_remain;
238         }
239 
240         if (write_all(rss->fd, data, write_now) == -1) {
241             break;
242         }
243 
244         data += write_now;
245         size -= write_now;
246 
247         rss->p_remain -= write_now;
248         written += write_now;
249 
250         if (rss->p_remain == 0) {
251             // move to the next block
252             ++rss->p_block;
253             if (rss->p_block < rss->tgt.count) {
254                 rss->p_remain = (rss->tgt.pos[rss->p_block * 2 + 1] -
255                                  rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE;
256 
257                 off64_t offset = static_cast<off64_t>(rss->tgt.pos[rss->p_block*2]) * BLOCKSIZE;
258                 if (!discard_blocks(rss->fd, offset, rss->p_remain)) {
259                     break;
260                 }
261 
262                 if (!check_lseek(rss->fd, offset, SEEK_SET)) {
263                     break;
264                 }
265 
266             } else {
267                 // we can't write any more; return how many bytes have
268                 // been written so far.
269                 break;
270             }
271         }
272     }
273 
274     return written;
275 }
276 
277 // All of the data for all the 'new' transfers is contained in one
278 // file in the update package, concatenated together in the order in
279 // which transfers.list will need it.  We want to stream it out of the
280 // archive (it's compressed) without writing it to a temp file, but we
281 // can't write each section until it's that transfer's turn to go.
282 //
283 // To achieve this, we expand the new data from the archive in a
284 // background thread, and block that threads 'receive uncompressed
285 // data' function until the main thread has reached a point where we
286 // want some new data to be written.  We signal the background thread
287 // with the destination for the data and block the main thread,
288 // waiting for the background thread to complete writing that section.
289 // Then it signals the main thread to wake up and goes back to
290 // blocking waiting for a transfer.
291 //
292 // NewThreadInfo is the struct used to pass information back and forth
293 // between the two threads.  When the main thread wants some data
294 // written, it sets rss to the destination location and signals the
295 // condition.  When the background thread is done writing, it clears
296 // rss and signals the condition again.
297 
298 struct NewThreadInfo {
299     ZipArchive* za;
300     const ZipEntry* entry;
301 
302     RangeSinkState* rss;
303 
304     pthread_mutex_t mu;
305     pthread_cond_t cv;
306 };
307 
receive_new_data(const unsigned char * data,int size,void * cookie)308 static bool receive_new_data(const unsigned char* data, int size, void* cookie) {
309     NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie);
310 
311     while (size > 0) {
312         // Wait for nti->rss to be non-null, indicating some of this
313         // data is wanted.
314         pthread_mutex_lock(&nti->mu);
315         while (nti->rss == nullptr) {
316             pthread_cond_wait(&nti->cv, &nti->mu);
317         }
318         pthread_mutex_unlock(&nti->mu);
319 
320         // At this point nti->rss is set, and we own it.  The main
321         // thread is waiting for it to disappear from nti.
322         ssize_t written = RangeSinkWrite(data, size, nti->rss);
323         data += written;
324         size -= written;
325 
326         if (nti->rss->p_block == nti->rss->tgt.count) {
327             // we have written all the bytes desired by this rss.
328 
329             pthread_mutex_lock(&nti->mu);
330             nti->rss = nullptr;
331             pthread_cond_broadcast(&nti->cv);
332             pthread_mutex_unlock(&nti->mu);
333         }
334     }
335 
336     return true;
337 }
338 
unzip_new_data(void * cookie)339 static void* unzip_new_data(void* cookie) {
340     NewThreadInfo* nti = (NewThreadInfo*) cookie;
341     mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti);
342     return nullptr;
343 }
344 
ReadBlocks(const RangeSet & src,std::vector<uint8_t> & buffer,int fd)345 static int ReadBlocks(const RangeSet& src, std::vector<uint8_t>& buffer, int fd) {
346     size_t p = 0;
347     uint8_t* data = buffer.data();
348 
349     for (size_t i = 0; i < src.count; ++i) {
350         if (!check_lseek(fd, (off64_t) src.pos[i * 2] * BLOCKSIZE, SEEK_SET)) {
351             return -1;
352         }
353 
354         size_t size = (src.pos[i * 2 + 1] - src.pos[i * 2]) * BLOCKSIZE;
355 
356         if (read_all(fd, data + p, size) == -1) {
357             return -1;
358         }
359 
360         p += size;
361     }
362 
363     return 0;
364 }
365 
WriteBlocks(const RangeSet & tgt,const std::vector<uint8_t> & buffer,int fd)366 static int WriteBlocks(const RangeSet& tgt, const std::vector<uint8_t>& buffer, int fd) {
367     const uint8_t* data = buffer.data();
368 
369     size_t p = 0;
370     for (size_t i = 0; i < tgt.count; ++i) {
371         off64_t offset = static_cast<off64_t>(tgt.pos[i * 2]) * BLOCKSIZE;
372         size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
373         if (!discard_blocks(fd, offset, size)) {
374             return -1;
375         }
376 
377         if (!check_lseek(fd, offset, SEEK_SET)) {
378             return -1;
379         }
380 
381         if (write_all(fd, data + p, size) == -1) {
382             return -1;
383         }
384 
385         p += size;
386     }
387 
388     return 0;
389 }
390 
391 // Parameters for transfer list command functions
392 struct CommandParameters {
393     std::vector<std::string> tokens;
394     size_t cpos;
395     const char* cmdname;
396     const char* cmdline;
397     std::string freestash;
398     std::string stashbase;
399     bool canwrite;
400     int createdstash;
401     int fd;
402     bool foundwrites;
403     bool isunresumable;
404     int version;
405     size_t written;
406     size_t stashed;
407     NewThreadInfo nti;
408     pthread_t thread;
409     std::vector<uint8_t> buffer;
410     uint8_t* patch_start;
411 };
412 
413 // Do a source/target load for move/bsdiff/imgdiff in version 1.
414 // We expect to parse the remainder of the parameter tokens as:
415 //
416 //    <src_range> <tgt_range>
417 //
418 // The source range is loaded into the provided buffer, reallocating
419 // it to make it larger if necessary.
420 
LoadSrcTgtVersion1(CommandParameters & params,RangeSet & tgt,size_t & src_blocks,std::vector<uint8_t> & buffer,int fd)421 static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
422         std::vector<uint8_t>& buffer, int fd) {
423 
424     if (params.cpos + 1 >= params.tokens.size()) {
425         fprintf(stderr, "invalid parameters\n");
426         return -1;
427     }
428 
429     // <src_range>
430     RangeSet src;
431     parse_range(params.tokens[params.cpos++], src);
432 
433     // <tgt_range>
434     parse_range(params.tokens[params.cpos++], tgt);
435 
436     allocate(src.size * BLOCKSIZE, buffer);
437     int rc = ReadBlocks(src, buffer, fd);
438     src_blocks = src.size;
439 
440     return rc;
441 }
442 
VerifyBlocks(const std::string & expected,const std::vector<uint8_t> & buffer,const size_t blocks,bool printerror)443 static int VerifyBlocks(const std::string& expected, const std::vector<uint8_t>& buffer,
444         const size_t blocks, bool printerror) {
445     uint8_t digest[SHA_DIGEST_LENGTH];
446     const uint8_t* data = buffer.data();
447 
448     SHA1(data, blocks * BLOCKSIZE, digest);
449 
450     std::string hexdigest = print_sha1(digest);
451 
452     if (hexdigest != expected) {
453         if (printerror) {
454             fprintf(stderr, "failed to verify blocks (expected %s, read %s)\n",
455                     expected.c_str(), hexdigest.c_str());
456         }
457         return -1;
458     }
459 
460     return 0;
461 }
462 
GetStashFileName(const std::string & base,const std::string & id,const std::string & postfix)463 static std::string GetStashFileName(const std::string& base, const std::string& id,
464         const std::string& postfix) {
465     if (base.empty()) {
466         return "";
467     }
468 
469     std::string fn(STASH_DIRECTORY_BASE);
470     fn += "/" + base + "/" + id + postfix;
471 
472     return fn;
473 }
474 
475 typedef void (*StashCallback)(const std::string&, void*);
476 
477 // Does a best effort enumeration of stash files. Ignores possible non-file
478 // items in the stash directory and continues despite of errors. Calls the
479 // 'callback' function for each file and passes 'data' to the function as a
480 // parameter.
481 
EnumerateStash(const std::string & dirname,StashCallback callback,void * data)482 static void EnumerateStash(const std::string& dirname, StashCallback callback, void* data) {
483     if (dirname.empty() || callback == nullptr) {
484         return;
485     }
486 
487     std::unique_ptr<DIR, int(*)(DIR*)> directory(opendir(dirname.c_str()), closedir);
488 
489     if (directory == nullptr) {
490         if (errno != ENOENT) {
491             fprintf(stderr, "opendir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
492         }
493         return;
494     }
495 
496     struct dirent* item;
497     while ((item = readdir(directory.get())) != nullptr) {
498         if (item->d_type != DT_REG) {
499             continue;
500         }
501 
502         std::string fn = dirname + "/" + std::string(item->d_name);
503         callback(fn, data);
504     }
505 }
506 
UpdateFileSize(const std::string & fn,void * data)507 static void UpdateFileSize(const std::string& fn, void* data) {
508     if (fn.empty() || !data) {
509         return;
510     }
511 
512     struct stat sb;
513     if (stat(fn.c_str(), &sb) == -1) {
514         fprintf(stderr, "stat \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
515         return;
516     }
517 
518     int* size = reinterpret_cast<int*>(data);
519     *size += sb.st_size;
520 }
521 
522 // Deletes the stash directory and all files in it. Assumes that it only
523 // contains files. There is nothing we can do about unlikely, but possible
524 // errors, so they are merely logged.
525 
DeleteFile(const std::string & fn,void *)526 static void DeleteFile(const std::string& fn, void* /* data */) {
527     if (!fn.empty()) {
528         fprintf(stderr, "deleting %s\n", fn.c_str());
529 
530         if (unlink(fn.c_str()) == -1 && errno != ENOENT) {
531             fprintf(stderr, "unlink \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
532         }
533     }
534 }
535 
DeletePartial(const std::string & fn,void * data)536 static void DeletePartial(const std::string& fn, void* data) {
537     if (android::base::EndsWith(fn, ".partial")) {
538         DeleteFile(fn, data);
539     }
540 }
541 
DeleteStash(const std::string & base)542 static void DeleteStash(const std::string& base) {
543     if (base.empty()) {
544         return;
545     }
546 
547     fprintf(stderr, "deleting stash %s\n", base.c_str());
548 
549     std::string dirname = GetStashFileName(base, "", "");
550     EnumerateStash(dirname, DeleteFile, nullptr);
551 
552     if (rmdir(dirname.c_str()) == -1) {
553         if (errno != ENOENT && errno != ENOTDIR) {
554             fprintf(stderr, "rmdir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno));
555         }
556     }
557 }
558 
LoadStash(CommandParameters & params,const std::string & base,const std::string & id,bool verify,size_t * blocks,std::vector<uint8_t> & buffer,bool printnoent)559 static int LoadStash(CommandParameters& params, const std::string& base, const std::string& id,
560         bool verify, size_t* blocks, std::vector<uint8_t>& buffer, bool printnoent) {
561     // In verify mode, if source range_set was saved for the given hash,
562     // check contents in the source blocks first. If the check fails,
563     // search for the stashed files on /cache as usual.
564     if (!params.canwrite) {
565         if (stash_map.find(id) != stash_map.end()) {
566             const RangeSet& src = stash_map[id];
567             allocate(src.size * BLOCKSIZE, buffer);
568 
569             if (ReadBlocks(src, buffer, params.fd) == -1) {
570                 fprintf(stderr, "failed to read source blocks in stash map.\n");
571                 return -1;
572             }
573             if (VerifyBlocks(id, buffer, src.size, true) != 0) {
574                 fprintf(stderr, "failed to verify loaded source blocks in stash map.\n");
575                 return -1;
576             }
577             return 0;
578         }
579     }
580 
581     if (base.empty()) {
582         return -1;
583     }
584 
585     size_t blockcount = 0;
586 
587     if (!blocks) {
588         blocks = &blockcount;
589     }
590 
591     std::string fn = GetStashFileName(base, id, "");
592 
593     struct stat sb;
594     int res = stat(fn.c_str(), &sb);
595 
596     if (res == -1) {
597         if (errno != ENOENT || printnoent) {
598             fprintf(stderr, "stat \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
599         }
600         return -1;
601     }
602 
603     fprintf(stderr, " loading %s\n", fn.c_str());
604 
605     if ((sb.st_size % BLOCKSIZE) != 0) {
606         fprintf(stderr, "%s size %" PRId64 " not multiple of block size %d",
607                 fn.c_str(), static_cast<int64_t>(sb.st_size), BLOCKSIZE);
608         return -1;
609     }
610 
611     int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY));
612     unique_fd fd_holder(fd);
613 
614     if (fd == -1) {
615         fprintf(stderr, "open \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
616         return -1;
617     }
618 
619     allocate(sb.st_size, buffer);
620 
621     if (read_all(fd, buffer, sb.st_size) == -1) {
622         return -1;
623     }
624 
625     *blocks = sb.st_size / BLOCKSIZE;
626 
627     if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) {
628         fprintf(stderr, "unexpected contents in %s\n", fn.c_str());
629         DeleteFile(fn, nullptr);
630         return -1;
631     }
632 
633     return 0;
634 }
635 
WriteStash(const std::string & base,const std::string & id,int blocks,std::vector<uint8_t> & buffer,bool checkspace,bool * exists)636 static int WriteStash(const std::string& base, const std::string& id, int blocks,
637         std::vector<uint8_t>& buffer, bool checkspace, bool *exists) {
638     if (base.empty()) {
639         return -1;
640     }
641 
642     if (checkspace && CacheSizeCheck(blocks * BLOCKSIZE) != 0) {
643         fprintf(stderr, "not enough space to write stash\n");
644         return -1;
645     }
646 
647     std::string fn = GetStashFileName(base, id, ".partial");
648     std::string cn = GetStashFileName(base, id, "");
649 
650     if (exists) {
651         struct stat sb;
652         int res = stat(cn.c_str(), &sb);
653 
654         if (res == 0) {
655             // The file already exists and since the name is the hash of the contents,
656             // it's safe to assume the contents are identical (accidental hash collisions
657             // are unlikely)
658             fprintf(stderr, " skipping %d existing blocks in %s\n", blocks, cn.c_str());
659             *exists = true;
660             return 0;
661         }
662 
663         *exists = false;
664     }
665 
666     fprintf(stderr, " writing %d blocks to %s\n", blocks, cn.c_str());
667 
668     int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE));
669     unique_fd fd_holder(fd);
670 
671     if (fd == -1) {
672         fprintf(stderr, "failed to create \"%s\": %s\n", fn.c_str(), strerror(errno));
673         return -1;
674     }
675 
676     if (write_all(fd, buffer, blocks * BLOCKSIZE) == -1) {
677         return -1;
678     }
679 
680     if (ota_fsync(fd) == -1) {
681         failure_type = kFsyncFailure;
682         fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno));
683         return -1;
684     }
685 
686     if (rename(fn.c_str(), cn.c_str()) == -1) {
687         fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", fn.c_str(), cn.c_str(),
688                 strerror(errno));
689         return -1;
690     }
691 
692     std::string dname = GetStashFileName(base, "", "");
693     int dfd = TEMP_FAILURE_RETRY(open(dname.c_str(), O_RDONLY | O_DIRECTORY));
694     unique_fd dfd_holder(dfd);
695 
696     if (dfd == -1) {
697         failure_type = kFileOpenFailure;
698         fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
699         return -1;
700     }
701 
702     if (ota_fsync(dfd) == -1) {
703         failure_type = kFsyncFailure;
704         fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno));
705         return -1;
706     }
707 
708     return 0;
709 }
710 
711 // Creates a directory for storing stash files and checks if the /cache partition
712 // hash enough space for the expected amount of blocks we need to store. Returns
713 // >0 if we created the directory, zero if it existed already, and <0 of failure.
714 
CreateStash(State * state,int maxblocks,const char * blockdev,std::string & base)715 static int CreateStash(State* state, int maxblocks, const char* blockdev, std::string& base) {
716     if (blockdev == nullptr) {
717         return -1;
718     }
719 
720     // Stash directory should be different for each partition to avoid conflicts
721     // when updating multiple partitions at the same time, so we use the hash of
722     // the block device name as the base directory
723     uint8_t digest[SHA_DIGEST_LENGTH];
724     SHA1(reinterpret_cast<const uint8_t*>(blockdev), strlen(blockdev), digest);
725     base = print_sha1(digest);
726 
727     std::string dirname = GetStashFileName(base, "", "");
728     struct stat sb;
729     int res = stat(dirname.c_str(), &sb);
730 
731     if (res == -1 && errno != ENOENT) {
732         ErrorAbort(state, kStashCreationFailure, "stat \"%s\" failed: %s\n",
733                    dirname.c_str(), strerror(errno));
734         return -1;
735     } else if (res != 0) {
736         fprintf(stderr, "creating stash %s\n", dirname.c_str());
737         res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE);
738 
739         if (res != 0) {
740             ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s\n",
741                        dirname.c_str(), strerror(errno));
742             return -1;
743         }
744 
745         if (CacheSizeCheck(maxblocks * BLOCKSIZE) != 0) {
746             ErrorAbort(state, kStashCreationFailure, "not enough space for stash\n");
747             return -1;
748         }
749 
750         return 1;  // Created directory
751     }
752 
753     fprintf(stderr, "using existing stash %s\n", dirname.c_str());
754 
755     // If the directory already exists, calculate the space already allocated to
756     // stash files and check if there's enough for all required blocks. Delete any
757     // partially completed stash files first.
758 
759     EnumerateStash(dirname, DeletePartial, nullptr);
760     int size = 0;
761     EnumerateStash(dirname, UpdateFileSize, &size);
762 
763     size = maxblocks * BLOCKSIZE - size;
764 
765     if (size > 0 && CacheSizeCheck(size) != 0) {
766         ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%d more needed)\n",
767                    size);
768         return -1;
769     }
770 
771     return 0; // Using existing directory
772 }
773 
SaveStash(CommandParameters & params,const std::string & base,std::vector<uint8_t> & buffer,int fd,bool usehash)774 static int SaveStash(CommandParameters& params, const std::string& base,
775         std::vector<uint8_t>& buffer, int fd, bool usehash) {
776 
777     // <stash_id> <src_range>
778     if (params.cpos + 1 >= params.tokens.size()) {
779         fprintf(stderr, "missing id and/or src range fields in stash command\n");
780         return -1;
781     }
782     const std::string& id = params.tokens[params.cpos++];
783 
784     size_t blocks = 0;
785     if (usehash && LoadStash(params, base, id, true, &blocks, buffer, false) == 0) {
786         // Stash file already exists and has expected contents. Do not
787         // read from source again, as the source may have been already
788         // overwritten during a previous attempt.
789         return 0;
790     }
791 
792     RangeSet src;
793     parse_range(params.tokens[params.cpos++], src);
794 
795     allocate(src.size * BLOCKSIZE, buffer);
796     if (ReadBlocks(src, buffer, fd) == -1) {
797         return -1;
798     }
799     blocks = src.size;
800 
801     if (usehash && VerifyBlocks(id, buffer, blocks, true) != 0) {
802         // Source blocks have unexpected contents. If we actually need this
803         // data later, this is an unrecoverable error. However, the command
804         // that uses the data may have already completed previously, so the
805         // possible failure will occur during source block verification.
806         fprintf(stderr, "failed to load source blocks for stash %s\n", id.c_str());
807         return 0;
808     }
809 
810     // In verify mode, save source range_set instead of stashing blocks.
811     if (!params.canwrite && usehash) {
812         stash_map[id] = src;
813         return 0;
814     }
815 
816     fprintf(stderr, "stashing %zu blocks to %s\n", blocks, id.c_str());
817     params.stashed += blocks;
818     return WriteStash(base, id, blocks, buffer, false, nullptr);
819 }
820 
FreeStash(const std::string & base,const std::string & id)821 static int FreeStash(const std::string& base, const std::string& id) {
822     if (base.empty() || id.empty()) {
823         return -1;
824     }
825 
826     std::string fn = GetStashFileName(base, id, "");
827     DeleteFile(fn, nullptr);
828 
829     return 0;
830 }
831 
MoveRange(std::vector<uint8_t> & dest,const RangeSet & locs,const std::vector<uint8_t> & source)832 static void MoveRange(std::vector<uint8_t>& dest, const RangeSet& locs,
833         const std::vector<uint8_t>& source) {
834     // source contains packed data, which we want to move to the
835     // locations given in locs in the dest buffer.  source and dest
836     // may be the same buffer.
837 
838     const uint8_t* from = source.data();
839     uint8_t* to = dest.data();
840     size_t start = locs.size;
841     for (int i = locs.count-1; i >= 0; --i) {
842         size_t blocks = locs.pos[i*2+1] - locs.pos[i*2];
843         start -= blocks;
844         memmove(to + (locs.pos[i*2] * BLOCKSIZE), from + (start * BLOCKSIZE),
845                 blocks * BLOCKSIZE);
846     }
847 }
848 
849 // Do a source/target load for move/bsdiff/imgdiff in version 2.
850 // We expect to parse the remainder of the parameter tokens as one of:
851 //
852 //    <tgt_range> <src_block_count> <src_range>
853 //        (loads data from source image only)
854 //
855 //    <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
856 //        (loads data from stashes only)
857 //
858 //    <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
859 //        (loads data from both source image and stashes)
860 //
861 // On return, buffer is filled with the loaded source data (rearranged
862 // and combined with stashed data as necessary).  buffer may be
863 // reallocated if needed to accommodate the source data.  *tgt is the
864 // target RangeSet.  Any stashes required are loaded using LoadStash.
865 
LoadSrcTgtVersion2(CommandParameters & params,RangeSet & tgt,size_t & src_blocks,std::vector<uint8_t> & buffer,int fd,const std::string & stashbase,bool * overlap)866 static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
867         std::vector<uint8_t>& buffer, int fd, const std::string& stashbase, bool* overlap) {
868 
869     // At least it needs to provide three parameters: <tgt_range>,
870     // <src_block_count> and "-"/<src_range>.
871     if (params.cpos + 2 >= params.tokens.size()) {
872         fprintf(stderr, "invalid parameters\n");
873         return -1;
874     }
875 
876     // <tgt_range>
877     parse_range(params.tokens[params.cpos++], tgt);
878 
879     // <src_block_count>
880     const std::string& token = params.tokens[params.cpos++];
881     if (!android::base::ParseUint(token.c_str(), &src_blocks)) {
882         fprintf(stderr, "invalid src_block_count \"%s\"\n", token.c_str());
883         return -1;
884     }
885 
886     allocate(src_blocks * BLOCKSIZE, buffer);
887 
888     // "-" or <src_range> [<src_loc>]
889     if (params.tokens[params.cpos] == "-") {
890         // no source ranges, only stashes
891         params.cpos++;
892     } else {
893         RangeSet src;
894         parse_range(params.tokens[params.cpos++], src);
895         int res = ReadBlocks(src, buffer, fd);
896 
897         if (overlap) {
898             *overlap = range_overlaps(src, tgt);
899         }
900 
901         if (res == -1) {
902             return -1;
903         }
904 
905         if (params.cpos >= params.tokens.size()) {
906             // no stashes, only source range
907             return 0;
908         }
909 
910         RangeSet locs;
911         parse_range(params.tokens[params.cpos++], locs);
912         MoveRange(buffer, locs, buffer);
913     }
914 
915     // <[stash_id:stash_range]>
916     while (params.cpos < params.tokens.size()) {
917         // Each word is a an index into the stash table, a colon, and
918         // then a rangeset describing where in the source block that
919         // stashed data should go.
920         std::vector<std::string> tokens = android::base::Split(params.tokens[params.cpos++], ":");
921         if (tokens.size() != 2) {
922             fprintf(stderr, "invalid parameter\n");
923             return -1;
924         }
925 
926         std::vector<uint8_t> stash;
927         int res = LoadStash(params, stashbase, tokens[0], false, nullptr, stash, true);
928 
929         if (res == -1) {
930             // These source blocks will fail verification if used later, but we
931             // will let the caller decide if this is a fatal failure
932             fprintf(stderr, "failed to load stash %s\n", tokens[0].c_str());
933             continue;
934         }
935 
936         RangeSet locs;
937         parse_range(tokens[1], locs);
938 
939         MoveRange(buffer, locs, stash);
940     }
941 
942     return 0;
943 }
944 
945 // Do a source/target load for move/bsdiff/imgdiff in version 3.
946 //
947 // Parameters are the same as for LoadSrcTgtVersion2, except for 'onehash', which
948 // tells the function whether to expect separate source and targe block hashes, or
949 // if they are both the same and only one hash should be expected, and
950 // 'isunresumable', which receives a non-zero value if block verification fails in
951 // a way that the update cannot be resumed anymore.
952 //
953 // If the function is unable to load the necessary blocks or their contents don't
954 // match the hashes, the return value is -1 and the command should be aborted.
955 //
956 // If the return value is 1, the command has already been completed according to
957 // the contents of the target blocks, and should not be performed again.
958 //
959 // If the return value is 0, source blocks have expected content and the command
960 // can be performed.
961 
LoadSrcTgtVersion3(CommandParameters & params,RangeSet & tgt,size_t & src_blocks,bool onehash,bool & overlap)962 static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
963         bool onehash, bool& overlap) {
964 
965     if (params.cpos >= params.tokens.size()) {
966         fprintf(stderr, "missing source hash\n");
967         return -1;
968     }
969 
970     std::string srchash = params.tokens[params.cpos++];
971     std::string tgthash;
972 
973     if (onehash) {
974         tgthash = srchash;
975     } else {
976         if (params.cpos >= params.tokens.size()) {
977             fprintf(stderr, "missing target hash\n");
978             return -1;
979         }
980         tgthash = params.tokens[params.cpos++];
981     }
982 
983     if (LoadSrcTgtVersion2(params, tgt, src_blocks, params.buffer, params.fd, params.stashbase,
984             &overlap) == -1) {
985         return -1;
986     }
987 
988     std::vector<uint8_t> tgtbuffer(tgt.size * BLOCKSIZE);
989 
990     if (ReadBlocks(tgt, tgtbuffer, params.fd) == -1) {
991         return -1;
992     }
993 
994     if (VerifyBlocks(tgthash, tgtbuffer, tgt.size, false) == 0) {
995         // Target blocks already have expected content, command should be skipped
996         return 1;
997     }
998 
999     if (VerifyBlocks(srchash, params.buffer, src_blocks, true) == 0) {
1000         // If source and target blocks overlap, stash the source blocks so we can
1001         // resume from possible write errors. In verify mode, we can skip stashing
1002         // because the source blocks won't be overwritten.
1003         if (overlap && params.canwrite) {
1004             fprintf(stderr, "stashing %zu overlapping blocks to %s\n", src_blocks,
1005                     srchash.c_str());
1006 
1007             bool stash_exists = false;
1008             if (WriteStash(params.stashbase, srchash, src_blocks, params.buffer, true,
1009                            &stash_exists) != 0) {
1010                 fprintf(stderr, "failed to stash overlapping source blocks\n");
1011                 return -1;
1012             }
1013 
1014             params.stashed += src_blocks;
1015             // Can be deleted when the write has completed
1016             if (!stash_exists) {
1017                 params.freestash = srchash;
1018             }
1019         }
1020 
1021         // Source blocks have expected content, command can proceed
1022         return 0;
1023     }
1024 
1025     if (overlap && LoadStash(params, params.stashbase, srchash, true, nullptr, params.buffer,
1026                              true) == 0) {
1027         // Overlapping source blocks were previously stashed, command can proceed.
1028         // We are recovering from an interrupted command, so we don't know if the
1029         // stash can safely be deleted after this command.
1030         return 0;
1031     }
1032 
1033     // Valid source data not available, update cannot be resumed
1034     fprintf(stderr, "partition has unexpected contents\n");
1035     params.isunresumable = true;
1036 
1037     return -1;
1038 }
1039 
PerformCommandMove(CommandParameters & params)1040 static int PerformCommandMove(CommandParameters& params) {
1041     size_t blocks = 0;
1042     bool overlap = false;
1043     int status = 0;
1044     RangeSet tgt;
1045 
1046     if (params.version == 1) {
1047         status = LoadSrcTgtVersion1(params, tgt, blocks, params.buffer, params.fd);
1048     } else if (params.version == 2) {
1049         status = LoadSrcTgtVersion2(params, tgt, blocks, params.buffer, params.fd,
1050                 params.stashbase, nullptr);
1051     } else if (params.version >= 3) {
1052         status = LoadSrcTgtVersion3(params, tgt, blocks, true, overlap);
1053     }
1054 
1055     if (status == -1) {
1056         fprintf(stderr, "failed to read blocks for move\n");
1057         return -1;
1058     }
1059 
1060     if (status == 0) {
1061         params.foundwrites = true;
1062     } else if (params.foundwrites) {
1063         fprintf(stderr, "warning: commands executed out of order [%s]\n", params.cmdname);
1064     }
1065 
1066     if (params.canwrite) {
1067         if (status == 0) {
1068             fprintf(stderr, "  moving %zu blocks\n", blocks);
1069 
1070             if (WriteBlocks(tgt, params.buffer, params.fd) == -1) {
1071                 return -1;
1072             }
1073         } else {
1074             fprintf(stderr, "skipping %zu already moved blocks\n", blocks);
1075         }
1076 
1077     }
1078 
1079     if (!params.freestash.empty()) {
1080         FreeStash(params.stashbase, params.freestash);
1081         params.freestash.clear();
1082     }
1083 
1084     params.written += tgt.size;
1085 
1086     return 0;
1087 }
1088 
PerformCommandStash(CommandParameters & params)1089 static int PerformCommandStash(CommandParameters& params) {
1090     return SaveStash(params, params.stashbase, params.buffer, params.fd,
1091             (params.version >= 3));
1092 }
1093 
PerformCommandFree(CommandParameters & params)1094 static int PerformCommandFree(CommandParameters& params) {
1095     // <stash_id>
1096     if (params.cpos >= params.tokens.size()) {
1097         fprintf(stderr, "missing stash id in free command\n");
1098         return -1;
1099     }
1100 
1101     const std::string& id = params.tokens[params.cpos++];
1102 
1103     if (!params.canwrite && stash_map.find(id) != stash_map.end()) {
1104         stash_map.erase(id);
1105         return 0;
1106     }
1107 
1108     if (params.createdstash || params.canwrite) {
1109         return FreeStash(params.stashbase, id);
1110     }
1111 
1112     return 0;
1113 }
1114 
PerformCommandZero(CommandParameters & params)1115 static int PerformCommandZero(CommandParameters& params) {
1116 
1117     if (params.cpos >= params.tokens.size()) {
1118         fprintf(stderr, "missing target blocks for zero\n");
1119         return -1;
1120     }
1121 
1122     RangeSet tgt;
1123     parse_range(params.tokens[params.cpos++], tgt);
1124 
1125     fprintf(stderr, "  zeroing %zu blocks\n", tgt.size);
1126 
1127     allocate(BLOCKSIZE, params.buffer);
1128     memset(params.buffer.data(), 0, BLOCKSIZE);
1129 
1130     if (params.canwrite) {
1131         for (size_t i = 0; i < tgt.count; ++i) {
1132             off64_t offset = static_cast<off64_t>(tgt.pos[i * 2]) * BLOCKSIZE;
1133             size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE;
1134             if (!discard_blocks(params.fd, offset, size)) {
1135                 return -1;
1136             }
1137 
1138             if (!check_lseek(params.fd, offset, SEEK_SET)) {
1139                 return -1;
1140             }
1141 
1142             for (size_t j = tgt.pos[i * 2]; j < tgt.pos[i * 2 + 1]; ++j) {
1143                 if (write_all(params.fd, params.buffer, BLOCKSIZE) == -1) {
1144                     return -1;
1145                 }
1146             }
1147         }
1148     }
1149 
1150     if (params.cmdname[0] == 'z') {
1151         // Update only for the zero command, as the erase command will call
1152         // this if DEBUG_ERASE is defined.
1153         params.written += tgt.size;
1154     }
1155 
1156     return 0;
1157 }
1158 
PerformCommandNew(CommandParameters & params)1159 static int PerformCommandNew(CommandParameters& params) {
1160 
1161     if (params.cpos >= params.tokens.size()) {
1162         fprintf(stderr, "missing target blocks for new\n");
1163         return -1;
1164     }
1165 
1166     RangeSet tgt;
1167     parse_range(params.tokens[params.cpos++], tgt);
1168 
1169     if (params.canwrite) {
1170         fprintf(stderr, " writing %zu blocks of new data\n", tgt.size);
1171 
1172         RangeSinkState rss(tgt);
1173         rss.fd = params.fd;
1174         rss.p_block = 0;
1175         rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
1176 
1177         off64_t offset = static_cast<off64_t>(tgt.pos[0]) * BLOCKSIZE;
1178         if (!discard_blocks(params.fd, offset, tgt.size * BLOCKSIZE)) {
1179             return -1;
1180         }
1181 
1182         if (!check_lseek(params.fd, offset, SEEK_SET)) {
1183             return -1;
1184         }
1185 
1186         pthread_mutex_lock(&params.nti.mu);
1187         params.nti.rss = &rss;
1188         pthread_cond_broadcast(&params.nti.cv);
1189 
1190         while (params.nti.rss) {
1191             pthread_cond_wait(&params.nti.cv, &params.nti.mu);
1192         }
1193 
1194         pthread_mutex_unlock(&params.nti.mu);
1195     }
1196 
1197     params.written += tgt.size;
1198 
1199     return 0;
1200 }
1201 
PerformCommandDiff(CommandParameters & params)1202 static int PerformCommandDiff(CommandParameters& params) {
1203 
1204     // <offset> <length>
1205     if (params.cpos + 1 >= params.tokens.size()) {
1206         fprintf(stderr, "missing patch offset or length for %s\n", params.cmdname);
1207         return -1;
1208     }
1209 
1210     size_t offset;
1211     if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &offset)) {
1212         fprintf(stderr, "invalid patch offset\n");
1213         return -1;
1214     }
1215 
1216     size_t len;
1217     if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &len)) {
1218         fprintf(stderr, "invalid patch offset\n");
1219         return -1;
1220     }
1221 
1222     RangeSet tgt;
1223     size_t blocks = 0;
1224     bool overlap = false;
1225     int status = 0;
1226     if (params.version == 1) {
1227         status = LoadSrcTgtVersion1(params, tgt, blocks, params.buffer, params.fd);
1228     } else if (params.version == 2) {
1229         status = LoadSrcTgtVersion2(params, tgt, blocks, params.buffer, params.fd,
1230                 params.stashbase, nullptr);
1231     } else if (params.version >= 3) {
1232         status = LoadSrcTgtVersion3(params, tgt, blocks, false, overlap);
1233     }
1234 
1235     if (status == -1) {
1236         fprintf(stderr, "failed to read blocks for diff\n");
1237         return -1;
1238     }
1239 
1240     if (status == 0) {
1241         params.foundwrites = true;
1242     } else if (params.foundwrites) {
1243         fprintf(stderr, "warning: commands executed out of order [%s]\n", params.cmdname);
1244     }
1245 
1246     if (params.canwrite) {
1247         if (status == 0) {
1248             fprintf(stderr, "patching %zu blocks to %zu\n", blocks, tgt.size);
1249 
1250             Value patch_value;
1251             patch_value.type = VAL_BLOB;
1252             patch_value.size = len;
1253             patch_value.data = (char*) (params.patch_start + offset);
1254 
1255             RangeSinkState rss(tgt);
1256             rss.fd = params.fd;
1257             rss.p_block = 0;
1258             rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE;
1259 
1260             off64_t offset = static_cast<off64_t>(tgt.pos[0]) * BLOCKSIZE;
1261             if (!discard_blocks(params.fd, offset, rss.p_remain)) {
1262                 return -1;
1263             }
1264 
1265             if (!check_lseek(params.fd, offset, SEEK_SET)) {
1266                 return -1;
1267             }
1268 
1269             if (params.cmdname[0] == 'i') {      // imgdiff
1270                 if (ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value,
1271                         &RangeSinkWrite, &rss, nullptr, nullptr) != 0) {
1272                     fprintf(stderr, "Failed to apply image patch.\n");
1273                     return -1;
1274                 }
1275             } else {
1276                 if (ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value,
1277                         0, &RangeSinkWrite, &rss, nullptr) != 0) {
1278                     fprintf(stderr, "Failed to apply bsdiff patch.\n");
1279                     return -1;
1280                 }
1281             }
1282 
1283             // We expect the output of the patcher to fill the tgt ranges exactly.
1284             if (rss.p_block != tgt.count || rss.p_remain != 0) {
1285                 fprintf(stderr, "range sink underrun?\n");
1286             }
1287         } else {
1288             fprintf(stderr, "skipping %zu blocks already patched to %zu [%s]\n",
1289                 blocks, tgt.size, params.cmdline);
1290         }
1291     }
1292 
1293     if (!params.freestash.empty()) {
1294         FreeStash(params.stashbase, params.freestash);
1295         params.freestash.clear();
1296     }
1297 
1298     params.written += tgt.size;
1299 
1300     return 0;
1301 }
1302 
PerformCommandErase(CommandParameters & params)1303 static int PerformCommandErase(CommandParameters& params) {
1304     if (DEBUG_ERASE) {
1305         return PerformCommandZero(params);
1306     }
1307 
1308     struct stat sb;
1309     if (fstat(params.fd, &sb) == -1) {
1310         fprintf(stderr, "failed to fstat device to erase: %s\n", strerror(errno));
1311         return -1;
1312     }
1313 
1314     if (!S_ISBLK(sb.st_mode)) {
1315         fprintf(stderr, "not a block device; skipping erase\n");
1316         return -1;
1317     }
1318 
1319     if (params.cpos >= params.tokens.size()) {
1320         fprintf(stderr, "missing target blocks for erase\n");
1321         return -1;
1322     }
1323 
1324     RangeSet tgt;
1325     parse_range(params.tokens[params.cpos++], tgt);
1326 
1327     if (params.canwrite) {
1328         fprintf(stderr, " erasing %zu blocks\n", tgt.size);
1329 
1330         for (size_t i = 0; i < tgt.count; ++i) {
1331             uint64_t blocks[2];
1332             // offset in bytes
1333             blocks[0] = tgt.pos[i * 2] * (uint64_t) BLOCKSIZE;
1334             // length in bytes
1335             blocks[1] = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * (uint64_t) BLOCKSIZE;
1336 
1337             if (ioctl(params.fd, BLKDISCARD, &blocks) == -1) {
1338                 fprintf(stderr, "BLKDISCARD ioctl failed: %s\n", strerror(errno));
1339                 return -1;
1340             }
1341         }
1342     }
1343 
1344     return 0;
1345 }
1346 
1347 // Definitions for transfer list command functions
1348 typedef int (*CommandFunction)(CommandParameters&);
1349 
1350 struct Command {
1351     const char* name;
1352     CommandFunction f;
1353 };
1354 
1355 // CompareCommands and CompareCommandNames are for the hash table
1356 
CompareCommands(const void * c1,const void * c2)1357 static int CompareCommands(const void* c1, const void* c2) {
1358     return strcmp(((const Command*) c1)->name, ((const Command*) c2)->name);
1359 }
1360 
CompareCommandNames(const void * c1,const void * c2)1361 static int CompareCommandNames(const void* c1, const void* c2) {
1362     return strcmp(((const Command*) c1)->name, (const char*) c2);
1363 }
1364 
1365 // HashString is used to hash command names for the hash table
1366 
HashString(const char * s)1367 static unsigned int HashString(const char *s) {
1368     unsigned int hash = 0;
1369     if (s) {
1370         while (*s) {
1371             hash = hash * 33 + *s++;
1372         }
1373     }
1374     return hash;
1375 }
1376 
1377 // args:
1378 //    - block device (or file) to modify in-place
1379 //    - transfer list (blob)
1380 //    - new data stream (filename within package.zip)
1381 //    - patch stream (filename within package.zip, must be uncompressed)
1382 
PerformBlockImageUpdate(const char * name,State * state,int,Expr * argv[],const Command * commands,size_t cmdcount,bool dryrun)1383 static Value* PerformBlockImageUpdate(const char* name, State* state, int /* argc */, Expr* argv[],
1384         const Command* commands, size_t cmdcount, bool dryrun) {
1385     CommandParameters params;
1386     memset(&params, 0, sizeof(params));
1387     params.canwrite = !dryrun;
1388 
1389     fprintf(stderr, "performing %s\n", dryrun ? "verification" : "update");
1390     if (state->is_retry) {
1391         is_retry = true;
1392         fprintf(stderr, "This update is a retry.\n");
1393     }
1394 
1395     Value* blockdev_filename = nullptr;
1396     Value* transfer_list_value = nullptr;
1397     Value* new_data_fn = nullptr;
1398     Value* patch_data_fn = nullptr;
1399     if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value,
1400             &new_data_fn, &patch_data_fn) < 0) {
1401         return StringValue(strdup(""));
1402     }
1403     std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename,
1404             FreeValue);
1405     std::unique_ptr<Value, decltype(&FreeValue)> transfer_list_value_holder(transfer_list_value,
1406             FreeValue);
1407     std::unique_ptr<Value, decltype(&FreeValue)> new_data_fn_holder(new_data_fn, FreeValue);
1408     std::unique_ptr<Value, decltype(&FreeValue)> patch_data_fn_holder(patch_data_fn, FreeValue);
1409 
1410     if (blockdev_filename->type != VAL_STRING) {
1411         ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string",
1412                    name);
1413         return StringValue(strdup(""));
1414     }
1415     if (transfer_list_value->type != VAL_BLOB) {
1416         ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name);
1417         return StringValue(strdup(""));
1418     }
1419     if (new_data_fn->type != VAL_STRING) {
1420         ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name);
1421         return StringValue(strdup(""));
1422     }
1423     if (patch_data_fn->type != VAL_STRING) {
1424         ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string",
1425                    name);
1426         return StringValue(strdup(""));
1427     }
1428 
1429     UpdaterInfo* ui = reinterpret_cast<UpdaterInfo*>(state->cookie);
1430 
1431     if (ui == nullptr) {
1432         return StringValue(strdup(""));
1433     }
1434 
1435     FILE* cmd_pipe = ui->cmd_pipe;
1436     ZipArchive* za = ui->package_zip;
1437 
1438     if (cmd_pipe == nullptr || za == nullptr) {
1439         return StringValue(strdup(""));
1440     }
1441 
1442     const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data);
1443     if (patch_entry == nullptr) {
1444         fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data);
1445         return StringValue(strdup(""));
1446     }
1447 
1448     params.patch_start = ui->package_zip_addr + mzGetZipEntryOffset(patch_entry);
1449     const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data);
1450     if (new_entry == nullptr) {
1451         fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data);
1452         return StringValue(strdup(""));
1453     }
1454 
1455     params.fd = TEMP_FAILURE_RETRY(open(blockdev_filename->data, O_RDWR));
1456     unique_fd fd_holder(params.fd);
1457 
1458     if (params.fd == -1) {
1459         fprintf(stderr, "open \"%s\" failed: %s\n", blockdev_filename->data, strerror(errno));
1460         return StringValue(strdup(""));
1461     }
1462 
1463     if (params.canwrite) {
1464         params.nti.za = za;
1465         params.nti.entry = new_entry;
1466 
1467         pthread_mutex_init(&params.nti.mu, nullptr);
1468         pthread_cond_init(&params.nti.cv, nullptr);
1469         pthread_attr_t attr;
1470         pthread_attr_init(&attr);
1471         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1472 
1473         int error = pthread_create(&params.thread, &attr, unzip_new_data, &params.nti);
1474         if (error != 0) {
1475             fprintf(stderr, "pthread_create failed: %s\n", strerror(error));
1476             return StringValue(strdup(""));
1477         }
1478     }
1479 
1480     // Copy all the lines in transfer_list_value into std::string for
1481     // processing.
1482     const std::string transfer_list(transfer_list_value->data, transfer_list_value->size);
1483     std::vector<std::string> lines = android::base::Split(transfer_list, "\n");
1484     if (lines.size() < 2) {
1485         ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zd]\n",
1486                    lines.size());
1487         return StringValue(strdup(""));
1488     }
1489 
1490     // First line in transfer list is the version number
1491     if (!android::base::ParseInt(lines[0].c_str(), &params.version, 1, 4)) {
1492         fprintf(stderr, "unexpected transfer list version [%s]\n", lines[0].c_str());
1493         return StringValue(strdup(""));
1494     }
1495 
1496     fprintf(stderr, "blockimg version is %d\n", params.version);
1497 
1498     // Second line in transfer list is the total number of blocks we expect to write
1499     int total_blocks;
1500     if (!android::base::ParseInt(lines[1].c_str(), &total_blocks, 0)) {
1501         ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str());
1502         return StringValue(strdup(""));
1503     }
1504 
1505     if (total_blocks == 0) {
1506         return StringValue(strdup("t"));
1507     }
1508 
1509     size_t start = 2;
1510     if (params.version >= 2) {
1511         if (lines.size() < 4) {
1512             ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n",
1513                        lines.size());
1514             return StringValue(strdup(""));
1515         }
1516 
1517         // Third line is how many stash entries are needed simultaneously
1518         fprintf(stderr, "maximum stash entries %s\n", lines[2].c_str());
1519 
1520         // Fourth line is the maximum number of blocks that will be stashed simultaneously
1521         int stash_max_blocks;
1522         if (!android::base::ParseInt(lines[3].c_str(), &stash_max_blocks, 0)) {
1523             ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n",
1524                        lines[3].c_str());
1525             return StringValue(strdup(""));
1526         }
1527 
1528         int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase);
1529         if (res == -1) {
1530             return StringValue(strdup(""));
1531         }
1532 
1533         params.createdstash = res;
1534 
1535         start += 2;
1536     }
1537 
1538     // Build a hash table of the available commands
1539     HashTable* cmdht = mzHashTableCreate(cmdcount, nullptr);
1540     std::unique_ptr<HashTable, decltype(&mzHashTableFree)> cmdht_holder(cmdht, mzHashTableFree);
1541 
1542     for (size_t i = 0; i < cmdcount; ++i) {
1543         unsigned int cmdhash = HashString(commands[i].name);
1544         mzHashTableLookup(cmdht, cmdhash, (void*) &commands[i], CompareCommands, true);
1545     }
1546 
1547     int rc = -1;
1548 
1549     // Subsequent lines are all individual transfer commands
1550     for (auto it = lines.cbegin() + start; it != lines.cend(); it++) {
1551         const std::string& line_str(*it);
1552         if (line_str.empty()) {
1553             continue;
1554         }
1555 
1556         params.tokens = android::base::Split(line_str, " ");
1557         params.cpos = 0;
1558         params.cmdname = params.tokens[params.cpos++].c_str();
1559         params.cmdline = line_str.c_str();
1560 
1561         unsigned int cmdhash = HashString(params.cmdname);
1562         const Command* cmd = reinterpret_cast<const Command*>(mzHashTableLookup(cmdht, cmdhash,
1563                 const_cast<char*>(params.cmdname), CompareCommandNames,
1564                 false));
1565 
1566         if (cmd == nullptr) {
1567             fprintf(stderr, "unexpected command [%s]\n", params.cmdname);
1568             goto pbiudone;
1569         }
1570 
1571         if (cmd->f != nullptr && cmd->f(params) == -1) {
1572             fprintf(stderr, "failed to execute command [%s]\n", line_str.c_str());
1573             goto pbiudone;
1574         }
1575 
1576         if (params.canwrite) {
1577             if (ota_fsync(params.fd) == -1) {
1578                 failure_type = kFsyncFailure;
1579                 fprintf(stderr, "fsync failed: %s\n", strerror(errno));
1580                 goto pbiudone;
1581             }
1582             fprintf(cmd_pipe, "set_progress %.4f\n", (double) params.written / total_blocks);
1583             fflush(cmd_pipe);
1584         }
1585     }
1586 
1587     if (params.canwrite) {
1588         pthread_join(params.thread, nullptr);
1589 
1590         fprintf(stderr, "wrote %zu blocks; expected %d\n", params.written, total_blocks);
1591         fprintf(stderr, "stashed %zu blocks\n", params.stashed);
1592         fprintf(stderr, "max alloc needed was %zu\n", params.buffer.size());
1593 
1594         const char* partition = strrchr(blockdev_filename->data, '/');
1595         if (partition != nullptr && *(partition+1) != 0) {
1596             fprintf(cmd_pipe, "log bytes_written_%s: %zu\n", partition + 1,
1597                     params.written * BLOCKSIZE);
1598             fprintf(cmd_pipe, "log bytes_stashed_%s: %zu\n", partition + 1,
1599                     params.stashed * BLOCKSIZE);
1600             fflush(cmd_pipe);
1601         }
1602         // Delete stash only after successfully completing the update, as it
1603         // may contain blocks needed to complete the update later.
1604         DeleteStash(params.stashbase);
1605     } else {
1606         fprintf(stderr, "verified partition contents; update may be resumed\n");
1607     }
1608 
1609     rc = 0;
1610 
1611 pbiudone:
1612     if (ota_fsync(params.fd) == -1) {
1613         failure_type = kFsyncFailure;
1614         fprintf(stderr, "fsync failed: %s\n", strerror(errno));
1615     }
1616     // params.fd will be automatically closed because of the fd_holder above.
1617 
1618     // Only delete the stash if the update cannot be resumed, or it's
1619     // a verification run and we created the stash.
1620     if (params.isunresumable || (!params.canwrite && params.createdstash)) {
1621         DeleteStash(params.stashbase);
1622     }
1623 
1624     if (failure_type != kNoCause && state->cause_code == kNoCause) {
1625         state->cause_code = failure_type;
1626     }
1627 
1628     return StringValue(rc == 0 ? strdup("t") : strdup(""));
1629 }
1630 
1631 // The transfer list is a text file containing commands to
1632 // transfer data from one place to another on the target
1633 // partition.  We parse it and execute the commands in order:
1634 //
1635 //    zero [rangeset]
1636 //      - fill the indicated blocks with zeros
1637 //
1638 //    new [rangeset]
1639 //      - fill the blocks with data read from the new_data file
1640 //
1641 //    erase [rangeset]
1642 //      - mark the given blocks as empty
1643 //
1644 //    move <...>
1645 //    bsdiff <patchstart> <patchlen> <...>
1646 //    imgdiff <patchstart> <patchlen> <...>
1647 //      - read the source blocks, apply a patch (or not in the
1648 //        case of move), write result to target blocks.  bsdiff or
1649 //        imgdiff specifies the type of patch; move means no patch
1650 //        at all.
1651 //
1652 //        The format of <...> differs between versions 1 and 2;
1653 //        see the LoadSrcTgtVersion{1,2}() functions for a
1654 //        description of what's expected.
1655 //
1656 //    stash <stash_id> <src_range>
1657 //      - (version 2+ only) load the given source range and stash
1658 //        the data in the given slot of the stash table.
1659 //
1660 //    free <stash_id>
1661 //      - (version 3+ only) free the given stash data.
1662 //
1663 // The creator of the transfer list will guarantee that no block
1664 // is read (ie, used as the source for a patch or move) after it
1665 // has been written.
1666 //
1667 // In version 2, the creator will guarantee that a given stash is
1668 // loaded (with a stash command) before it's used in a
1669 // move/bsdiff/imgdiff command.
1670 //
1671 // Within one command the source and target ranges may overlap so
1672 // in general we need to read the entire source into memory before
1673 // writing anything to the target blocks.
1674 //
1675 // All the patch data is concatenated into one patch_data file in
1676 // the update package.  It must be stored uncompressed because we
1677 // memory-map it in directly from the archive.  (Since patches are
1678 // already compressed, we lose very little by not compressing
1679 // their concatenation.)
1680 //
1681 // In version 3, commands that read data from the partition (i.e.
1682 // move/bsdiff/imgdiff/stash) have one or more additional hashes
1683 // before the range parameters, which are used to check if the
1684 // command has already been completed and verify the integrity of
1685 // the source data.
1686 
BlockImageVerifyFn(const char * name,State * state,int argc,Expr * argv[])1687 Value* BlockImageVerifyFn(const char* name, State* state, int argc, Expr* argv[]) {
1688     // Commands which are not tested are set to nullptr to skip them completely
1689     const Command commands[] = {
1690         { "bsdiff",     PerformCommandDiff  },
1691         { "erase",      nullptr             },
1692         { "free",       PerformCommandFree  },
1693         { "imgdiff",    PerformCommandDiff  },
1694         { "move",       PerformCommandMove  },
1695         { "new",        nullptr             },
1696         { "stash",      PerformCommandStash },
1697         { "zero",       nullptr             }
1698     };
1699 
1700     // Perform a dry run without writing to test if an update can proceed
1701     return PerformBlockImageUpdate(name, state, argc, argv, commands,
1702                 sizeof(commands) / sizeof(commands[0]), true);
1703 }
1704 
BlockImageUpdateFn(const char * name,State * state,int argc,Expr * argv[])1705 Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]) {
1706     const Command commands[] = {
1707         { "bsdiff",     PerformCommandDiff  },
1708         { "erase",      PerformCommandErase },
1709         { "free",       PerformCommandFree  },
1710         { "imgdiff",    PerformCommandDiff  },
1711         { "move",       PerformCommandMove  },
1712         { "new",        PerformCommandNew   },
1713         { "stash",      PerformCommandStash },
1714         { "zero",       PerformCommandZero  }
1715     };
1716 
1717     return PerformBlockImageUpdate(name, state, argc, argv, commands,
1718                 sizeof(commands) / sizeof(commands[0]), false);
1719 }
1720 
RangeSha1Fn(const char * name,State * state,int,Expr * argv[])1721 Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) {
1722     Value* blockdev_filename;
1723     Value* ranges;
1724 
1725     if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) {
1726         return StringValue(strdup(""));
1727     }
1728     std::unique_ptr<Value, decltype(&FreeValue)> ranges_holder(ranges, FreeValue);
1729     std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename,
1730             FreeValue);
1731 
1732     if (blockdev_filename->type != VAL_STRING) {
1733         ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string",
1734                    name);
1735         return StringValue(strdup(""));
1736     }
1737     if (ranges->type != VAL_STRING) {
1738         ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
1739         return StringValue(strdup(""));
1740     }
1741 
1742     int fd = open(blockdev_filename->data, O_RDWR);
1743     unique_fd fd_holder(fd);
1744     if (fd < 0) {
1745         ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", blockdev_filename->data,
1746                    strerror(errno));
1747         return StringValue(strdup(""));
1748     }
1749 
1750     RangeSet rs;
1751     parse_range(ranges->data, rs);
1752 
1753     SHA_CTX ctx;
1754     SHA1_Init(&ctx);
1755 
1756     std::vector<uint8_t> buffer(BLOCKSIZE);
1757     for (size_t i = 0; i < rs.count; ++i) {
1758         if (!check_lseek(fd, (off64_t)rs.pos[i*2] * BLOCKSIZE, SEEK_SET)) {
1759             ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", blockdev_filename->data,
1760                        strerror(errno));
1761             return StringValue(strdup(""));
1762         }
1763 
1764         for (size_t j = rs.pos[i*2]; j < rs.pos[i*2+1]; ++j) {
1765             if (read_all(fd, buffer, BLOCKSIZE) == -1) {
1766                 ErrorAbort(state, kFreadFailure, "failed to read %s: %s", blockdev_filename->data,
1767                         strerror(errno));
1768                 return StringValue(strdup(""));
1769             }
1770 
1771             SHA1_Update(&ctx, buffer.data(), BLOCKSIZE);
1772         }
1773     }
1774     uint8_t digest[SHA_DIGEST_LENGTH];
1775     SHA1_Final(digest, &ctx);
1776 
1777     return StringValue(strdup(print_sha1(digest).c_str()));
1778 }
1779 
1780 // This function checks if a device has been remounted R/W prior to an incremental
1781 // OTA update. This is an common cause of update abortion. The function reads the
1782 // 1st block of each partition and check for mounting time/count. It return string "t"
1783 // if executes successfully and an empty string otherwise.
1784 
CheckFirstBlockFn(const char * name,State * state,int argc,Expr * argv[])1785 Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) {
1786     Value* arg_filename;
1787 
1788     if (ReadValueArgs(state, argv, 1, &arg_filename) < 0) {
1789         return nullptr;
1790     }
1791     std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue);
1792 
1793     if (filename->type != VAL_STRING) {
1794         ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
1795         return StringValue(strdup(""));
1796     }
1797 
1798     int fd = open(arg_filename->data, O_RDONLY);
1799     unique_fd fd_holder(fd);
1800     if (fd == -1) {
1801         ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data,
1802                    strerror(errno));
1803         return StringValue(strdup(""));
1804     }
1805 
1806     RangeSet blk0 {1 /*count*/, 1/*size*/, std::vector<size_t> {0, 1}/*position*/};
1807     std::vector<uint8_t> block0_buffer(BLOCKSIZE);
1808 
1809     if (ReadBlocks(blk0, block0_buffer, fd) == -1) {
1810         ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data,
1811                 strerror(errno));
1812         return StringValue(strdup(""));
1813     }
1814 
1815     // https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout
1816     // Super block starts from block 0, offset 0x400
1817     //   0x2C: len32 Mount time
1818     //   0x30: len32 Write time
1819     //   0x34: len16 Number of mounts since the last fsck
1820     //   0x38: len16 Magic signature 0xEF53
1821 
1822     time_t mount_time = *reinterpret_cast<uint32_t*>(&block0_buffer[0x400+0x2C]);
1823     uint16_t mount_count = *reinterpret_cast<uint16_t*>(&block0_buffer[0x400+0x34]);
1824 
1825     if (mount_count > 0) {
1826         uiPrintf(state, "Device was remounted R/W %d times\n", mount_count);
1827         uiPrintf(state, "Last remount happened on %s", ctime(&mount_time));
1828     }
1829 
1830     return StringValue(strdup("t"));
1831 }
1832 
1833 
BlockImageRecoverFn(const char * name,State * state,int argc,Expr * argv[])1834 Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[]) {
1835     Value* arg_filename;
1836     Value* arg_ranges;
1837 
1838     if (ReadValueArgs(state, argv, 2, &arg_filename, &arg_ranges) < 0) {
1839         return NULL;
1840     }
1841 
1842     std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue);
1843     std::unique_ptr<Value, decltype(&FreeValue)> ranges(arg_ranges, FreeValue);
1844 
1845     if (filename->type != VAL_STRING) {
1846         ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name);
1847         return StringValue(strdup(""));
1848     }
1849     if (ranges->type != VAL_STRING) {
1850         ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name);
1851         return StringValue(strdup(""));
1852     }
1853 
1854     // Output notice to log when recover is attempted
1855     fprintf(stderr, "%s image corrupted, attempting to recover...\n", filename->data);
1856 
1857     // When opened with O_RDWR, libfec rewrites corrupted blocks when they are read
1858     fec::io fh(filename->data, O_RDWR);
1859 
1860     if (!fh) {
1861         ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data,
1862                    strerror(errno));
1863         return StringValue(strdup(""));
1864     }
1865 
1866     if (!fh.has_ecc() || !fh.has_verity()) {
1867         ErrorAbort(state, kLibfecFailure, "unable to use metadata to correct errors");
1868         return StringValue(strdup(""));
1869     }
1870 
1871     fec_status status;
1872 
1873     if (!fh.get_status(status)) {
1874         ErrorAbort(state, kLibfecFailure, "failed to read FEC status");
1875         return StringValue(strdup(""));
1876     }
1877 
1878     RangeSet rs;
1879     parse_range(ranges->data, rs);
1880 
1881     uint8_t buffer[BLOCKSIZE];
1882 
1883     for (size_t i = 0; i < rs.count; ++i) {
1884         for (size_t j = rs.pos[i * 2]; j < rs.pos[i * 2 + 1]; ++j) {
1885             // Stay within the data area, libfec validates and corrects metadata
1886             if (status.data_size <= (uint64_t)j * BLOCKSIZE) {
1887                 continue;
1888             }
1889 
1890             if (fh.pread(buffer, BLOCKSIZE, (off64_t)j * BLOCKSIZE) != BLOCKSIZE) {
1891                 ErrorAbort(state, kLibfecFailure, "failed to recover %s (block %zu): %s",
1892                            filename->data, j, strerror(errno));
1893                 return StringValue(strdup(""));
1894             }
1895 
1896             // If we want to be able to recover from a situation where rewriting a corrected
1897             // block doesn't guarantee the same data will be returned when re-read later, we
1898             // can save a copy of corrected blocks to /cache. Note:
1899             //
1900             //  1. Maximum space required from /cache is the same as the maximum number of
1901             //     corrupted blocks we can correct. For RS(255, 253) and a 2 GiB partition,
1902             //     this would be ~16 MiB, for example.
1903             //
1904             //  2. To find out if this block was corrupted, call fec_get_status after each
1905             //     read and check if the errors field value has increased.
1906         }
1907     }
1908     fprintf(stderr, "...%s image recovered successfully.\n", filename->data);
1909     return StringValue(strdup("t"));
1910 }
1911 
RegisterBlockImageFunctions()1912 void RegisterBlockImageFunctions() {
1913     RegisterFunction("block_image_verify", BlockImageVerifyFn);
1914     RegisterFunction("block_image_update", BlockImageUpdateFn);
1915     RegisterFunction("block_image_recover", BlockImageRecoverFn);
1916     RegisterFunction("check_first_block", CheckFirstBlockFn);
1917     RegisterFunction("range_sha1", RangeSha1Fn);
1918 }
1919