1bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker/*
2bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * Copyright (C) 2014 The Android Open Source Project
3bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker *
4bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * Licensed under the Apache License, Version 2.0 (the "License");
5bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * you may not use this file except in compliance with the License.
6bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * You may obtain a copy of the License at
7bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker *
8bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker *      http://www.apache.org/licenses/LICENSE-2.0
9bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker *
10bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * Unless required by applicable law or agreed to in writing, software
11bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * distributed under the License is distributed on an "AS IS" BASIS,
12bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * See the License for the specific language governing permissions and
14bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker * limitations under the License.
15bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker */
16bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
17bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <ctype.h>
18bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <errno.h>
19bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <fcntl.h>
20bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <inttypes.h>
21bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <pthread.h>
22bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <stdarg.h>
23bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <stdio.h>
24bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <stdlib.h>
25bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <string.h>
26bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <sys/types.h>
27bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <sys/wait.h>
28bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <sys/ioctl.h>
29bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <time.h>
30bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include <unistd.h>
31bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
32bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include "applypatch/applypatch.h"
33bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include "edify/expr.h"
34bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include "mincrypt/sha.h"
35bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include "minzip/DirUtil.h"
36bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#include "updater.h"
37bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
38bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#define BLOCKSIZE 4096
39bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
40f7bb09dae8d7c89130648ef2aca7025860b6d801Doug Zongker// Set this to 0 to interpret 'erase' transfers to mean do a
41f7bb09dae8d7c89130648ef2aca7025860b6d801Doug Zongker// BLKDISCARD ioctl (the normal behavior).  Set to 1 to interpret
42f7bb09dae8d7c89130648ef2aca7025860b6d801Doug Zongker// erase to mean fill the region with zeroes.
43bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#define DEBUG_ERASE  0
44bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
45bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#ifndef BLKDISCARD
46bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#define BLKDISCARD _IO(0x12,119)
47bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker#endif
48bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
49bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerchar* PrintSha1(const uint8_t* digest);
50bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
51bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkertypedef struct {
52bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int count;
53bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int size;
54bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int pos[0];
55bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker} RangeSet;
56bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
57bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerstatic RangeSet* parse_range(char* text) {
58bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    char* save;
59bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int num;
60bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    num = strtol(strtok_r(text, ",", &save), NULL, 0);
61bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
62bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    RangeSet* out = malloc(sizeof(RangeSet) + num * sizeof(int));
63bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (out == NULL) {
64d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        fprintf(stderr, "failed to allocate range of %zu bytes\n",
65bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                sizeof(RangeSet) + num * sizeof(int));
66bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        exit(1);
67bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
68bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    out->count = num / 2;
69bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    out->size = 0;
70bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int i;
71bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    for (i = 0; i < num; ++i) {
72bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        out->pos[i] = strtol(strtok_r(NULL, ",", &save), NULL, 0);
73bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        if (i%2) {
74bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            out->size += out->pos[i];
75bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else {
76bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            out->size -= out->pos[i];
77bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
78bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
79bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
80bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    return out;
81bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
82bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
83bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerstatic void readblock(int fd, uint8_t* data, size_t size) {
84bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    size_t so_far = 0;
85bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    while (so_far < size) {
86bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ssize_t r = read(fd, data+so_far, size-so_far);
87bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        if (r < 0 && errno != EINTR) {
88bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            fprintf(stderr, "read failed: %s\n", strerror(errno));
89bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            return;
90bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else {
91bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            so_far += r;
92bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
93bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
94bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
95bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
96bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerstatic void writeblock(int fd, const uint8_t* data, size_t size) {
97bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    size_t written = 0;
98bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    while (written < size) {
99bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ssize_t w = write(fd, data+written, size-written);
100bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        if (w < 0 && errno != EINTR) {
101bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            fprintf(stderr, "write failed: %s\n", strerror(errno));
102bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            return;
103bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else {
104bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            written += w;
105bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
106bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
107bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
108bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
1098328922ff040280007da0aaaf8b567581231d5edAndrew Boiestatic void check_lseek(int fd, off64_t offset, int whence) {
110bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    while (true) {
1118328922ff040280007da0aaaf8b567581231d5edAndrew Boie        off64_t ret = lseek64(fd, offset, whence);
112bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        if (ret < 0) {
113bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            if (errno != EINTR) {
1148328922ff040280007da0aaaf8b567581231d5edAndrew Boie                fprintf(stderr, "lseek64 failed: %s\n", strerror(errno));
115bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                exit(1);
116bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
117bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else {
118bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            break;
119bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
120bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
121bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
122bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
123bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerstatic void allocate(size_t size, uint8_t** buffer, size_t* buffer_alloc) {
124bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // if the buffer's big enough, reuse it.
125bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (size <= *buffer_alloc) return;
126bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
127bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    free(*buffer);
128bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
129bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    *buffer = (uint8_t*) malloc(size);
130bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (*buffer == NULL) {
1311d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker        fprintf(stderr, "failed to allocate %zu bytes\n", size);
132bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        exit(1);
133bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
134bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    *buffer_alloc = size;
135bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
136bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
137bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkertypedef struct {
138bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int fd;
139bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    RangeSet* tgt;
140bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int p_block;
141bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    size_t p_remain;
142bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker} RangeSinkState;
143bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
144bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerstatic ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
145bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    RangeSinkState* rss = (RangeSinkState*) token;
146bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
147bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (rss->p_remain <= 0) {
148bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        fprintf(stderr, "range sink write overrun");
149bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        exit(1);
150bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
151bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
152bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    ssize_t written = 0;
153bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    while (size > 0) {
154bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        size_t write_now = size;
155bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        if (rss->p_remain < write_now) write_now = rss->p_remain;
156bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        writeblock(rss->fd, data, write_now);
157bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        data += write_now;
158bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        size -= write_now;
159bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
160bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        rss->p_remain -= write_now;
161bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        written += write_now;
162bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
163bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        if (rss->p_remain == 0) {
164bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            // move to the next block
165bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            ++rss->p_block;
166bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            if (rss->p_block < rss->tgt->count) {
167bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                rss->p_remain = (rss->tgt->pos[rss->p_block*2+1] - rss->tgt->pos[rss->p_block*2]) * BLOCKSIZE;
1688328922ff040280007da0aaaf8b567581231d5edAndrew Boie                check_lseek(rss->fd, (off64_t)rss->tgt->pos[rss->p_block*2] * BLOCKSIZE, SEEK_SET);
169bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            } else {
170bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                // we can't write any more; return how many bytes have
171bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                // been written so far.
172bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                return written;
173bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
174bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
175bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
176bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
177bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    return written;
178bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
179bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
180bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// All of the data for all the 'new' transfers is contained in one
181bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// file in the update package, concatenated together in the order in
182bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// which transfers.list will need it.  We want to stream it out of the
183bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// archive (it's compressed) without writing it to a temp file, but we
184bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// can't write each section until it's that transfer's turn to go.
185bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker//
186bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// To achieve this, we expand the new data from the archive in a
187bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// background thread, and block that threads 'receive uncompressed
188bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// data' function until the main thread has reached a point where we
189bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// want some new data to be written.  We signal the background thread
190bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// with the destination for the data and block the main thread,
191bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// waiting for the background thread to complete writing that section.
192bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// Then it signals the main thread to wake up and goes back to
193bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// blocking waiting for a transfer.
194bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker//
195bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// NewThreadInfo is the struct used to pass information back and forth
196bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// between the two threads.  When the main thread wants some data
197bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// written, it sets rss to the destination location and signals the
198bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// condition.  When the background thread is done writing, it clears
199bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// rss and signals the condition again.
200bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
201bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkertypedef struct {
202bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    ZipArchive* za;
203bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    const ZipEntry* entry;
204bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
205bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    RangeSinkState* rss;
206bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
207bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_mutex_t mu;
208bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_cond_t cv;
209bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker} NewThreadInfo;
210bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
211bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerstatic bool receive_new_data(const unsigned char* data, int size, void* cookie) {
212bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    NewThreadInfo* nti = (NewThreadInfo*) cookie;
213bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
214bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    while (size > 0) {
215bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        // Wait for nti->rss to be non-NULL, indicating some of this
216bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        // data is wanted.
217bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        pthread_mutex_lock(&nti->mu);
218bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        while (nti->rss == NULL) {
219bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            pthread_cond_wait(&nti->cv, &nti->mu);
220bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
221bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        pthread_mutex_unlock(&nti->mu);
222bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
223bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        // At this point nti->rss is set, and we own it.  The main
224bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        // thread is waiting for it to disappear from nti.
225bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ssize_t written = RangeSinkWrite(data, size, nti->rss);
226bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        data += written;
227bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        size -= written;
228bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
229bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        if (nti->rss->p_block == nti->rss->tgt->count) {
230bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            // we have written all the bytes desired by this rss.
231bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
232bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            pthread_mutex_lock(&nti->mu);
233bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            nti->rss = NULL;
234bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            pthread_cond_broadcast(&nti->cv);
235bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            pthread_mutex_unlock(&nti->mu);
236bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
237bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
238bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
239bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    return true;
240bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
241bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
242bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerstatic void* unzip_new_data(void* cookie) {
243bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    NewThreadInfo* nti = (NewThreadInfo*) cookie;
244bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti);
245bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    return NULL;
246bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
247bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
248d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// Do a source/target load for move/bsdiff/imgdiff in version 1.
249d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// 'wordsave' is the save_ptr of a strtok_r()-in-progress.  We expect
250d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// to parse the remainder of the string as:
251d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//
252d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//    <src_range> <tgt_range>
253d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//
254d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// The source range is loaded into the provided buffer, reallocating
255d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// it to make it larger if necessary.  The target ranges are returned
256d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// in *tgt, if tgt is non-NULL.
257d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
258d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongkerstatic void LoadSrcTgtVersion1(char* wordsave, RangeSet** tgt, int* src_blocks,
259d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                               uint8_t** buffer, size_t* buffer_alloc, int fd) {
260d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    char* word;
261d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
262d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    word = strtok_r(NULL, " ", &wordsave);
263d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    RangeSet* src = parse_range(word);
264d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
265d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    if (tgt != NULL) {
266d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        word = strtok_r(NULL, " ", &wordsave);
267d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        *tgt = parse_range(word);
268d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    }
269d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
270d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    allocate(src->size * BLOCKSIZE, buffer, buffer_alloc);
271d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    size_t p = 0;
272d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    int i;
273d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    for (i = 0; i < src->count; ++i) {
274d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
275d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
276d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        readblock(fd, *buffer+p, sz);
277d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        p += sz;
278d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    }
279d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
280d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    *src_blocks = src->size;
281d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    free(src);
282d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker}
283d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
284d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongkerstatic void MoveRange(uint8_t* dest, RangeSet* locs, const uint8_t* source) {
285d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    // source contains packed data, which we want to move to the
286d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    // locations given in *locs in the dest buffer.  source and dest
287d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    // may be the same buffer.
288d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
289d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    int start = locs->size;
290d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    int i;
291d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    for (i = locs->count-1; i >= 0; --i) {
292d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        int blocks = locs->pos[i*2+1] - locs->pos[i*2];
293d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        start -= blocks;
294d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        memmove(dest + (locs->pos[i*2] * BLOCKSIZE), source + (start * BLOCKSIZE),
295d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                blocks * BLOCKSIZE);
296d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    }
297d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker}
298d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
299d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// Do a source/target load for move/bsdiff/imgdiff in version 2.
300d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// 'wordsave' is the save_ptr of a strtok_r()-in-progress.  We expect
301d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// to parse the remainder of the string as one of:
302d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//
303d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//    <tgt_range> <src_block_count> <src_range>
304d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//        (loads data from source image only)
305d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//
306d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//    <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
307d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//        (loads data from stashes only)
308d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//
309d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//    <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
310d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//        (loads data from both source image and stashes)
311d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker//
312d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// On return, buffer is filled with the loaded source data (rearranged
313d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// and combined with stashed data as necessary).  buffer may be
314d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// reallocated if needed to accommodate the source data.  *tgt is the
315d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// target RangeSet.  Any stashes required are taken from stash_table
316d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker// and free()'d after being used.
317d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
318d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongkerstatic void LoadSrcTgtVersion2(char* wordsave, RangeSet** tgt, int* src_blocks,
319d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                               uint8_t** buffer, size_t* buffer_alloc, int fd,
320d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                               uint8_t** stash_table) {
321d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    char* word;
322d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
323d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    if (tgt != NULL) {
324d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        word = strtok_r(NULL, " ", &wordsave);
325d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        *tgt = parse_range(word);
326d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    }
327d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
328d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    word = strtok_r(NULL, " ", &wordsave);
329d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    *src_blocks = strtol(word, NULL, 0);
330d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
331d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    allocate(*src_blocks * BLOCKSIZE, buffer, buffer_alloc);
332d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
333d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    word = strtok_r(NULL, " ", &wordsave);
334d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    if (word[0] == '-' && word[1] == '\0') {
335d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        // no source ranges, only stashes
336d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    } else {
337d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        RangeSet* src = parse_range(word);
338d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
339d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        size_t p = 0;
340d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        int i;
341d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        for (i = 0; i < src->count; ++i) {
342d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
343d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
344d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            readblock(fd, *buffer+p, sz);
345d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            p += sz;
346d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        }
347d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        free(src);
348d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
349d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        word = strtok_r(NULL, " ", &wordsave);
350d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        if (word == NULL) {
351d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            // no stashes, only source range
352d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            return;
353d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        }
354d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
355d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        RangeSet* locs = parse_range(word);
356d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        MoveRange(*buffer, locs, *buffer);
357d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    }
358d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
359d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    while ((word = strtok_r(NULL, " ", &wordsave)) != NULL) {
360d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        // Each word is a an index into the stash table, a colon, and
361d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        // then a rangeset describing where in the source block that
362d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        // stashed data should go.
363d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        char* colonsave = NULL;
364d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        char* colon = strtok_r(word, ":", &colonsave);
365d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        int stash_id = strtol(colon, NULL, 0);
366d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        colon = strtok_r(NULL, ":", &colonsave);
367d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        RangeSet* locs = parse_range(colon);
368d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        MoveRange(*buffer, locs, stash_table[stash_id]);
369d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        free(stash_table[stash_id]);
370d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        stash_table[stash_id] = NULL;
371d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        free(locs);
372d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    }
373d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker}
374d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
375bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// args:
376bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker//    - block device (or file) to modify in-place
377bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker//    - transfer list (blob)
378bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker//    - new data stream (filename within package.zip)
379bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker//    - patch stream (filename within package.zip, must be uncompressed)
380bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
381bc7ffeda98a861e346c30c771d3258030f7fcf21Doug ZongkerValue* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]) {
382bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    Value* blockdev_filename;
3831d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    Value* transfer_list_value;
3841d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    char* transfer_list = NULL;
385bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    Value* new_data_fn;
386bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    Value* patch_data_fn;
387bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    bool success = false;
388bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
3891d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value,
390bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                      &new_data_fn, &patch_data_fn) < 0) {
391bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        return NULL;
392bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
393bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
394bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (blockdev_filename->type != VAL_STRING) {
395bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
396bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
397bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
3981d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    if (transfer_list_value->type != VAL_BLOB) {
399bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "transfer_list argument to %s must be blob", name);
400bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
401bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
402bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (new_data_fn->type != VAL_STRING) {
403bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "new_data_fn argument to %s must be string", name);
404bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
405bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
406bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (patch_data_fn->type != VAL_STRING) {
407bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "patch_data_fn argument to %s must be string", name);
408bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
409bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
410bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
411bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
412bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    FILE* cmd_pipe = ui->cmd_pipe;
413bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
414bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
415bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
416bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data);
417bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (patch_entry == NULL) {
418bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "%s(): no file \"%s\" in package", name, patch_data_fn->data);
419bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
420bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
421bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
422bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    uint8_t* patch_start = ((UpdaterInfo*)(state->cookie))->package_zip_addr +
423bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        mzGetZipEntryOffset(patch_entry);
424bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
425bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data);
426bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (new_entry == NULL) {
427bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "%s(): no file \"%s\" in package", name, new_data_fn->data);
428bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
429bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
430bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
431bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // The transfer list is a text file containing commands to
432bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // transfer data from one place to another on the target
433bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // partition.  We parse it and execute the commands in order:
434bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //
435bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //    zero [rangeset]
436bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //      - fill the indicated blocks with zeros
437bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //
438bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //    new [rangeset]
439bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //      - fill the blocks with data read from the new_data file
440bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //
441bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //    erase [rangeset]
442bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //      - mark the given blocks as empty
443bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //
444d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //    move <...>
445d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //    bsdiff <patchstart> <patchlen> <...>
446d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //    imgdiff <patchstart> <patchlen> <...>
447d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //      - read the source blocks, apply a patch (or not in the
448d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //        case of move), write result to target blocks.  bsdiff or
449d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //        imgdiff specifies the type of patch; move means no patch
450d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //        at all.
451d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //
452d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //        The format of <...> differs between versions 1 and 2;
453d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //        see the LoadSrcTgtVersion{1,2}() functions for a
454d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //        description of what's expected.
455d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //
456d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //    stash <stash_id> <src_range>
457d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //      - (version 2 only) load the given source range and stash
458d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //        the data in the given slot of the stash table.
459d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //
460bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // The creator of the transfer list will guarantee that no block
461bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // is read (ie, used as the source for a patch or move) after it
462bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // has been written.
463bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //
464d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    // In version 2, the creator will guarantee that a given stash is
465d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    // loaded (with a stash command) before it's used in a
466d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    // move/bsdiff/imgdiff command.
467d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    //
468bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // Within one command the source and target ranges may overlap so
469bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // in general we need to read the entire source into memory before
470bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // writing anything to the target blocks.
471bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    //
472bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // All the patch data is concatenated into one patch_data file in
473bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // the update package.  It must be stored uncompressed because we
474bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // memory-map it in directly from the archive.  (Since patches are
475bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // already compressed, we lose very little by not compressing
476bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // their concatenation.)
477bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
478bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_t new_data_thread;
479bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    NewThreadInfo nti;
480bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    nti.za = za;
481bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    nti.entry = new_entry;
482bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    nti.rss = NULL;
483bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_mutex_init(&nti.mu, NULL);
484bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_cond_init(&nti.cv, NULL);
485bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
486bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_attr_t attr;
487bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_attr_init(&attr);
488bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
489bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_create(&new_data_thread, &attr, unzip_new_data, &nti);
490bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
491bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int i, j;
492bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
493bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    char* linesave;
494bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    char* wordsave;
495bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
496bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int fd = open(blockdev_filename->data, O_RDWR);
497bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (fd < 0) {
498bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "failed to open %s: %s", blockdev_filename->data, strerror(errno));
499bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
500bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
501bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
502bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    char* line;
503bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    char* word;
504bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
5051d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    // The data in transfer_list_value is not necessarily
5061d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    // null-terminated, so we need to copy it to a new buffer and add
5071d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    // the null that strtok_r will need.
5081d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    transfer_list = malloc(transfer_list_value->size+1);
5091d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    if (transfer_list == NULL) {
5101d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker        fprintf(stderr, "failed to allocate %zd bytes for transfer list\n",
5111d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker                transfer_list_value->size+1);
5121d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker        exit(1);
5131d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    }
5141d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    memcpy(transfer_list, transfer_list_value->data, transfer_list_value->size);
5151d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    transfer_list[transfer_list_value->size] = '\0';
5161d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker
5171d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    line = strtok_r(transfer_list, "\n", &linesave);
518bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
519d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    int version;
520bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // first line in transfer list is the version number; currently
521bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // there's only version 1.
522d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    if (strcmp(line, "1") == 0) {
523d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        version = 1;
524d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    } else if (strcmp(line, "2") == 0) {
525d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        version = 2;
526d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    } else {
527bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "unexpected transfer list version [%s]\n", line);
528bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
529bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
530d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    printf("blockimg version is %d\n", version);
531bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
532bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // second line in transfer list is the total number of blocks we
533bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // expect to write.
534bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    line = strtok_r(NULL, "\n", &linesave);
535bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int total_blocks = strtol(line, NULL, 0);
536bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // shouldn't happen, but avoid divide by zero.
537bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (total_blocks == 0) ++total_blocks;
538bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int blocks_so_far = 0;
539bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
540d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    uint8_t** stash_table = NULL;
541d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    if (version >= 2) {
542d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        // Next line is how many stash entries are needed simultaneously.
543d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        line = strtok_r(NULL, "\n", &linesave);
544d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        int stash_entries = strtol(line, NULL, 0);
545d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
546d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        stash_table = (uint8_t**) calloc(stash_entries, sizeof(uint8_t*));
547d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        if (stash_table == NULL) {
548d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            fprintf(stderr, "failed to allocate %d-entry stash table\n", stash_entries);
549d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            exit(1);
550d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        }
551d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
552d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        // Next line is the maximum number of blocks that will be
553d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        // stashed simultaneously.  This could be used to verify that
554d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        // enough memory or scratch disk space is available.
555d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        line = strtok_r(NULL, "\n", &linesave);
556d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        int stash_max_blocks = strtol(line, NULL, 0);
557d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker    }
558d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
559bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    uint8_t* buffer = NULL;
560bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    size_t buffer_alloc = 0;
561bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
562bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    // third and subsequent lines are all individual transfer commands.
563bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    for (line = strtok_r(NULL, "\n", &linesave); line;
564bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker         line = strtok_r(NULL, "\n", &linesave)) {
565d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
566bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        char* style;
567bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        style = strtok_r(line, " ", &wordsave);
568bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
569bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        if (strcmp("move", style) == 0) {
570d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            RangeSet* tgt;
571d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            int src_blocks;
572d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            if (version == 1) {
573d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                LoadSrcTgtVersion1(wordsave, &tgt, &src_blocks,
574d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                                   &buffer, &buffer_alloc, fd);
575d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            } else if (version == 2) {
576d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                LoadSrcTgtVersion2(wordsave, &tgt, &src_blocks,
577d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                                   &buffer, &buffer_alloc, fd, stash_table);
578d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            }
579bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
580d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            printf("  moving %d blocks\n", src_blocks);
581bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
582bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            size_t p = 0;
583bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            for (i = 0; i < tgt->count; ++i) {
5848328922ff040280007da0aaaf8b567581231d5edAndrew Boie                check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
585bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                size_t sz = (tgt->pos[i*2+1] - tgt->pos[i*2]) * BLOCKSIZE;
586bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                writeblock(fd, buffer+p, sz);
587bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                p += sz;
588bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
589bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
590bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            blocks_so_far += tgt->size;
591bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
592bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            fflush(cmd_pipe);
593bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
594bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            free(tgt);
595bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
596d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker        } else if (strcmp("stash", style) == 0) {
597d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            word = strtok_r(NULL, " ", &wordsave);
598d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            int stash_id = strtol(word, NULL, 0);
599d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            int src_blocks;
600d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            size_t stash_alloc = 0;
601d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
602d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            // Even though the "stash" style only appears in version
603d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            // 2, the version 1 source loader happens to do exactly
604d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            // what we want to read data into the stash_table.
605d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            LoadSrcTgtVersion1(wordsave, NULL, &src_blocks,
606d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                               stash_table + stash_id, &stash_alloc, fd);
607d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
608bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else if (strcmp("zero", style) == 0 ||
609bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                   (DEBUG_ERASE && strcmp("erase", style) == 0)) {
610bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            word = strtok_r(NULL, " ", &wordsave);
611bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            RangeSet* tgt = parse_range(word);
612bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
613bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            printf("  zeroing %d blocks\n", tgt->size);
614bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
615bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            allocate(BLOCKSIZE, &buffer, &buffer_alloc);
616bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            memset(buffer, 0, BLOCKSIZE);
617bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            for (i = 0; i < tgt->count; ++i) {
6188328922ff040280007da0aaaf8b567581231d5edAndrew Boie                check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
619bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                for (j = tgt->pos[i*2]; j < tgt->pos[i*2+1]; ++j) {
620bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                    writeblock(fd, buffer, BLOCKSIZE);
621bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                }
622bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
623bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
624bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            if (style[0] == 'z') {   // "zero" but not "erase"
625bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                blocks_so_far += tgt->size;
626bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
627bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                fflush(cmd_pipe);
628bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
629bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
630bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            free(tgt);
631bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else if (strcmp("new", style) == 0) {
632bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
633bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            word = strtok_r(NULL, " ", &wordsave);
634bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            RangeSet* tgt = parse_range(word);
635bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
636bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            printf("  writing %d blocks of new data\n", tgt->size);
637bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
638bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            RangeSinkState rss;
639bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            rss.fd = fd;
640bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            rss.tgt = tgt;
641bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            rss.p_block = 0;
642bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE;
6438328922ff040280007da0aaaf8b567581231d5edAndrew Boie            check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
644bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
645bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            pthread_mutex_lock(&nti.mu);
646bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            nti.rss = &rss;
647bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            pthread_cond_broadcast(&nti.cv);
648bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            while (nti.rss) {
649bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                pthread_cond_wait(&nti.cv, &nti.mu);
650bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
651bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            pthread_mutex_unlock(&nti.mu);
652bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
653bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            blocks_so_far += tgt->size;
654bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
655bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            fflush(cmd_pipe);
656bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
657bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            free(tgt);
658bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
659bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else if (strcmp("bsdiff", style) == 0 ||
660bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                   strcmp("imgdiff", style) == 0) {
661bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            word = strtok_r(NULL, " ", &wordsave);
662bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            size_t patch_offset = strtoul(word, NULL, 0);
663bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            word = strtok_r(NULL, " ", &wordsave);
664bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            size_t patch_len = strtoul(word, NULL, 0);
665bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
666d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            RangeSet* tgt;
667d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            int src_blocks;
668d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            if (version == 1) {
669d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                LoadSrcTgtVersion1(wordsave, &tgt, &src_blocks,
670d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                                   &buffer, &buffer_alloc, fd);
671d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            } else if (version == 2) {
672d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                LoadSrcTgtVersion2(wordsave, &tgt, &src_blocks,
673d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker                                   &buffer, &buffer_alloc, fd, stash_table);
674bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
675bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
676d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker            printf("  patching %d blocks to %d\n", src_blocks, tgt->size);
677d83e4f15890ac6ebe0d61924bd224eb1ae8565adDoug Zongker
678bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            Value patch_value;
679bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            patch_value.type = VAL_BLOB;
680bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            patch_value.size = patch_len;
681bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            patch_value.data = (char*)(patch_start + patch_offset);
682bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
683bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            RangeSinkState rss;
684bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            rss.fd = fd;
685bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            rss.tgt = tgt;
686bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            rss.p_block = 0;
687bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE;
6888328922ff040280007da0aaaf8b567581231d5edAndrew Boie            check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
689bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
6905b9defe848933503de062cd3925c9e4ad4e1933fTao Bao            int ret;
691bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            if (style[0] == 'i') {      // imgdiff
6925b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                ret = ApplyImagePatch(buffer, src_blocks * BLOCKSIZE,
6935b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                                      &patch_value,
6945b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                                      &RangeSinkWrite, &rss, NULL, NULL);
695bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            } else {
6965b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                ret = ApplyBSDiffPatch(buffer, src_blocks * BLOCKSIZE,
6975b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                                       &patch_value, 0,
6985b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                                       &RangeSinkWrite, &rss, NULL);
6995b9defe848933503de062cd3925c9e4ad4e1933fTao Bao            }
7005b9defe848933503de062cd3925c9e4ad4e1933fTao Bao
7015b9defe848933503de062cd3925c9e4ad4e1933fTao Bao            if (ret != 0) {
7025b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                ErrorAbort(state, "patch failed\n");
7035b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                goto done;
704bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
705bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
706bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            // We expect the output of the patcher to fill the tgt ranges exactly.
707bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            if (rss.p_block != tgt->count || rss.p_remain != 0) {
7085b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                ErrorAbort(state, "range sink underrun?\n");
7095b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                goto done;
710bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
711bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
712bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            blocks_so_far += tgt->size;
713bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
714bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            fflush(cmd_pipe);
715bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
716bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            free(tgt);
717bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else if (!DEBUG_ERASE && strcmp("erase", style) == 0) {
718bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            struct stat st;
719bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) {
720bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                word = strtok_r(NULL, " ", &wordsave);
721bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                RangeSet* tgt = parse_range(word);
722bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
723bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                printf("  erasing %d blocks\n", tgt->size);
724bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
725bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                for (i = 0; i < tgt->count; ++i) {
726bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                    uint64_t range[2];
727bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                    // offset in bytes
7281d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker                    range[0] = tgt->pos[i*2] * (uint64_t)BLOCKSIZE;
729bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                    // len in bytes
7301d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker                    range[1] = (tgt->pos[i*2+1] - tgt->pos[i*2]) * (uint64_t)BLOCKSIZE;
731bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
732bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                    if (ioctl(fd, BLKDISCARD, &range) < 0) {
7335b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                        ErrorAbort(state, "    blkdiscard failed: %s\n", strerror(errno));
7345b9defe848933503de062cd3925c9e4ad4e1933fTao Bao                        goto done;
735bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                    }
736bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                }
737bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
738bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                free(tgt);
739bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            } else {
740bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker                printf("  ignoring erase (not block device)\n");
741bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            }
742bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        } else {
7435b9defe848933503de062cd3925c9e4ad4e1933fTao Bao            ErrorAbort(state, "unknown transfer style \"%s\"\n", style);
7445b9defe848933503de062cd3925c9e4ad4e1933fTao Bao            goto done;
745bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
746bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
747bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
748bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    pthread_join(new_data_thread, NULL);
749bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    success = true;
750bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
751bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    free(buffer);
752bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    printf("wrote %d blocks; expected %d\n", blocks_so_far, total_blocks);
753bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    printf("max alloc needed was %zu\n", buffer_alloc);
754bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
7555b9defe848933503de062cd3925c9e4ad4e1933fTao Baodone:
7561d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    free(transfer_list);
757bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    FreeValue(blockdev_filename);
7581d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker    FreeValue(transfer_list_value);
759bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    FreeValue(new_data_fn);
760bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    FreeValue(patch_data_fn);
7615b9defe848933503de062cd3925c9e4ad4e1933fTao Bao    if (success) {
7625b9defe848933503de062cd3925c9e4ad4e1933fTao Bao        return StringValue(strdup("t"));
7635b9defe848933503de062cd3925c9e4ad4e1933fTao Bao    } else {
7645b9defe848933503de062cd3925c9e4ad4e1933fTao Bao        // NULL will be passed to its caller at Evaluate() and abort the OTA
7655b9defe848933503de062cd3925c9e4ad4e1933fTao Bao        // process.
7665b9defe848933503de062cd3925c9e4ad4e1933fTao Bao        return NULL;
7675b9defe848933503de062cd3925c9e4ad4e1933fTao Bao    }
768bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
769bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
770bc7ffeda98a861e346c30c771d3258030f7fcf21Doug ZongkerValue* RangeSha1Fn(const char* name, State* state, int argc, Expr* argv[]) {
771bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    Value* blockdev_filename;
772bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    Value* ranges;
773bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    const uint8_t* digest = NULL;
774bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) {
775bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        return NULL;
776bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
777bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
778bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (blockdev_filename->type != VAL_STRING) {
779bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
780bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
781bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
782bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (ranges->type != VAL_STRING) {
783bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "ranges argument to %s must be string", name);
784bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
785bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
786bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
787bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int fd = open(blockdev_filename->data, O_RDWR);
788bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (fd < 0) {
789bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        ErrorAbort(state, "failed to open %s: %s", blockdev_filename->data, strerror(errno));
790bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        goto done;
791bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
792bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
793bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    RangeSet* rs = parse_range(ranges->data);
794bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    uint8_t buffer[BLOCKSIZE];
795bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
796bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    SHA_CTX ctx;
797bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    SHA_init(&ctx);
798bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
799bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    int i, j;
800bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    for (i = 0; i < rs->count; ++i) {
8018328922ff040280007da0aaaf8b567581231d5edAndrew Boie        check_lseek(fd, (off64_t)rs->pos[i*2] * BLOCKSIZE, SEEK_SET);
802bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        for (j = rs->pos[i*2]; j < rs->pos[i*2+1]; ++j) {
803bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            readblock(fd, buffer, BLOCKSIZE);
804bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker            SHA_update(&ctx, buffer, BLOCKSIZE);
805bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        }
806bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
807bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    digest = SHA_final(&ctx);
808bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    close(fd);
809bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
8105b9defe848933503de062cd3925c9e4ad4e1933fTao Baodone:
811bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    FreeValue(blockdev_filename);
812bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    FreeValue(ranges);
813bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    if (digest == NULL) {
8145b9defe848933503de062cd3925c9e4ad4e1933fTao Bao        return NULL;
815bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    } else {
816bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker        return StringValue(PrintSha1(digest));
817bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    }
818bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
819bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker
820bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkervoid RegisterBlockImageFunctions() {
821bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    RegisterFunction("block_image_update", BlockImageUpdateFn);
822bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker    RegisterFunction("range_sha1", RangeSha1Fn);
823bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker}
824