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