blockimg.c revision f7bb09dae8d7c89130648ef2aca7025860b6d801
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) { 641d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker fprintf(stderr, "failed to allocate range of %lu 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 109bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkerstatic void check_lseek(int fd, off_t offset, int whence) { 110bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker while (true) { 1111d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker off_t ret = lseek(fd, offset, whence); 112bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (ret < 0) { 113bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (errno != EINTR) { 114bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fprintf(stderr, "lseek 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; 1681d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker check_lseek(rss->fd, rss->tgt->pos[rss->p_block*2] * (off_t)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 248bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// args: 249bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// - block device (or file) to modify in-place 250bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// - transfer list (blob) 251bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// - new data stream (filename within package.zip) 252bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker// - patch stream (filename within package.zip, must be uncompressed) 253bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 254bc7ffeda98a861e346c30c771d3258030f7fcf21Doug ZongkerValue* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]) { 255bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker Value* blockdev_filename; 2561d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker Value* transfer_list_value; 2571d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker char* transfer_list = NULL; 258bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker Value* new_data_fn; 259bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker Value* patch_data_fn; 260bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker bool success = false; 261bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 2621d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value, 263bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker &new_data_fn, &patch_data_fn) < 0) { 264bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker return NULL; 265bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 266bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 267bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (blockdev_filename->type != VAL_STRING) { 268bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "blockdev_filename argument to %s must be string", name); 269bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 270bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 2711d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker if (transfer_list_value->type != VAL_BLOB) { 272bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "transfer_list argument to %s must be blob", name); 273bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 274bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 275bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (new_data_fn->type != VAL_STRING) { 276bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "new_data_fn argument to %s must be string", name); 277bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 278bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 279bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (patch_data_fn->type != VAL_STRING) { 280bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "patch_data_fn argument to %s must be string", name); 281bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 282bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 283bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 284bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); 285bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker FILE* cmd_pipe = ui->cmd_pipe; 286bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 287bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; 288bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 289bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data); 290bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (patch_entry == NULL) { 291bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "%s(): no file \"%s\" in package", name, patch_data_fn->data); 292bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 293bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 294bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 295bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker uint8_t* patch_start = ((UpdaterInfo*)(state->cookie))->package_zip_addr + 296bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker mzGetZipEntryOffset(patch_entry); 297bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 298bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data); 299bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (new_entry == NULL) { 300bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "%s(): no file \"%s\" in package", name, new_data_fn->data); 301bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 302bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 303bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 304bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // The transfer list is a text file containing commands to 305bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // transfer data from one place to another on the target 306bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // partition. We parse it and execute the commands in order: 307bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // 308bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // zero [rangeset] 309bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // - fill the indicated blocks with zeros 310bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // 311bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // new [rangeset] 312bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // - fill the blocks with data read from the new_data file 313bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // 314bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // bsdiff patchstart patchlen [src rangeset] [tgt rangeset] 315bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // imgdiff patchstart patchlen [src rangeset] [tgt rangeset] 316bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // - read the source blocks, apply a patch, write result to 317bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // target blocks. bsdiff or imgdiff specifies the type of 318bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // patch. 319bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // 320bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // move [src rangeset] [tgt rangeset] 321bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // - copy data from source blocks to target blocks (no patch 322bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // needed; rangesets are the same size) 323bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // 324bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // erase [rangeset] 325bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // - mark the given blocks as empty 326bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // 327bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // The creator of the transfer list will guarantee that no block 328bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // is read (ie, used as the source for a patch or move) after it 329bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // has been written. 330bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // 331bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // Within one command the source and target ranges may overlap so 332bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // in general we need to read the entire source into memory before 333bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // writing anything to the target blocks. 334bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // 335bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // All the patch data is concatenated into one patch_data file in 336bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // the update package. It must be stored uncompressed because we 337bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // memory-map it in directly from the archive. (Since patches are 338bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // already compressed, we lose very little by not compressing 339bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // their concatenation.) 340bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 341bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_t new_data_thread; 342bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker NewThreadInfo nti; 343bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker nti.za = za; 344bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker nti.entry = new_entry; 345bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker nti.rss = NULL; 346bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_mutex_init(&nti.mu, NULL); 347bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_cond_init(&nti.cv, NULL); 348bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 349bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_attr_t attr; 350bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_attr_init(&attr); 351bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 352bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_create(&new_data_thread, &attr, unzip_new_data, &nti); 353bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 354bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker int i, j; 355bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 356bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker char* linesave; 357bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker char* wordsave; 358bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 359bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker int fd = open(blockdev_filename->data, O_RDWR); 360bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (fd < 0) { 361bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "failed to open %s: %s", blockdev_filename->data, strerror(errno)); 362bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 363bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 364bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 365bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker char* line; 366bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker char* word; 367bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 3681d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker // The data in transfer_list_value is not necessarily 3691d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker // null-terminated, so we need to copy it to a new buffer and add 3701d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker // the null that strtok_r will need. 3711d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker transfer_list = malloc(transfer_list_value->size+1); 3721d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker if (transfer_list == NULL) { 3731d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker fprintf(stderr, "failed to allocate %zd bytes for transfer list\n", 3741d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker transfer_list_value->size+1); 3751d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker exit(1); 3761d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker } 3771d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker memcpy(transfer_list, transfer_list_value->data, transfer_list_value->size); 3781d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker transfer_list[transfer_list_value->size] = '\0'; 3791d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker 3801d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker line = strtok_r(transfer_list, "\n", &linesave); 381bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 382bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // first line in transfer list is the version number; currently 383bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // there's only version 1. 384bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (strcmp(line, "1") != 0) { 385bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "unexpected transfer list version [%s]\n", line); 386bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 387bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 388bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 389bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // second line in transfer list is the total number of blocks we 390bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // expect to write. 391bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker line = strtok_r(NULL, "\n", &linesave); 392bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker int total_blocks = strtol(line, NULL, 0); 393bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // shouldn't happen, but avoid divide by zero. 394bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (total_blocks == 0) ++total_blocks; 395bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker int blocks_so_far = 0; 396bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 397bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker uint8_t* buffer = NULL; 398bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker size_t buffer_alloc = 0; 399bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 400bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // third and subsequent lines are all individual transfer commands. 401bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (line = strtok_r(NULL, "\n", &linesave); line; 402bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker line = strtok_r(NULL, "\n", &linesave)) { 403bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker char* style; 404bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker style = strtok_r(line, " ", &wordsave); 405bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 406bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (strcmp("move", style) == 0) { 407bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 408bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSet* src = parse_range(word); 409bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 410bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSet* tgt = parse_range(word); 411bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 412bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf(" moving %d blocks\n", src->size); 413bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 414bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc); 415bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker size_t p = 0; 416bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (i = 0; i < src->count; ++i) { 4171d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker check_lseek(fd, src->pos[i*2] * (off_t)BLOCKSIZE, SEEK_SET); 418bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE; 419bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker readblock(fd, buffer+p, sz); 420bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker p += sz; 421bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 422bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 423bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker p = 0; 424bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (i = 0; i < tgt->count; ++i) { 4251d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker check_lseek(fd, tgt->pos[i*2] * (off_t)BLOCKSIZE, SEEK_SET); 426bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker size_t sz = (tgt->pos[i*2+1] - tgt->pos[i*2]) * BLOCKSIZE; 427bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker writeblock(fd, buffer+p, sz); 428bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker p += sz; 429bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 430bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 431bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker blocks_so_far += tgt->size; 432bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks); 433bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fflush(cmd_pipe); 434bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 435bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker free(src); 436bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker free(tgt); 437bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 438bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } else if (strcmp("zero", style) == 0 || 439bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker (DEBUG_ERASE && strcmp("erase", style) == 0)) { 440bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 441bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSet* tgt = parse_range(word); 442bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 443bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf(" zeroing %d blocks\n", tgt->size); 444bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 445bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker allocate(BLOCKSIZE, &buffer, &buffer_alloc); 446bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker memset(buffer, 0, BLOCKSIZE); 447bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (i = 0; i < tgt->count; ++i) { 4481d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker check_lseek(fd, tgt->pos[i*2] * (off_t)BLOCKSIZE, SEEK_SET); 449bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (j = tgt->pos[i*2]; j < tgt->pos[i*2+1]; ++j) { 450bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker writeblock(fd, buffer, BLOCKSIZE); 451bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 452bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 453bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 454bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (style[0] == 'z') { // "zero" but not "erase" 455bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker blocks_so_far += tgt->size; 456bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks); 457bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fflush(cmd_pipe); 458bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 459bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 460bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker free(tgt); 461bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } else if (strcmp("new", style) == 0) { 462bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 463bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 464bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSet* tgt = parse_range(word); 465bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 466bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf(" writing %d blocks of new data\n", tgt->size); 467bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 468bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSinkState rss; 469bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker rss.fd = fd; 470bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker rss.tgt = tgt; 471bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker rss.p_block = 0; 472bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE; 4731d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker check_lseek(fd, tgt->pos[0] * (off_t)BLOCKSIZE, SEEK_SET); 474bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 475bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_mutex_lock(&nti.mu); 476bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker nti.rss = &rss; 477bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_cond_broadcast(&nti.cv); 478bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker while (nti.rss) { 479bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_cond_wait(&nti.cv, &nti.mu); 480bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 481bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_mutex_unlock(&nti.mu); 482bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 483bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker blocks_so_far += tgt->size; 484bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks); 485bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fflush(cmd_pipe); 486bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 487bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker free(tgt); 488bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 489bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } else if (strcmp("bsdiff", style) == 0 || 490bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker strcmp("imgdiff", style) == 0) { 491bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 492bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker size_t patch_offset = strtoul(word, NULL, 0); 493bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 494bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker size_t patch_len = strtoul(word, NULL, 0); 495bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 496bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 497bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSet* src = parse_range(word); 498bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 499bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSet* tgt = parse_range(word); 500bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 501bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf(" patching %d blocks to %d\n", src->size, tgt->size); 502bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 503bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // Read the source into memory. 504bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc); 505bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker size_t p = 0; 506bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (i = 0; i < src->count; ++i) { 5071d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker check_lseek(fd, src->pos[i*2] * (off_t)BLOCKSIZE, SEEK_SET); 508bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE; 509bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker readblock(fd, buffer+p, sz); 510bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker p += sz; 511bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 512bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 513bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker Value patch_value; 514bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker patch_value.type = VAL_BLOB; 515bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker patch_value.size = patch_len; 516bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker patch_value.data = (char*)(patch_start + patch_offset); 517bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 518bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSinkState rss; 519bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker rss.fd = fd; 520bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker rss.tgt = tgt; 521bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker rss.p_block = 0; 522bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE; 5231d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker check_lseek(fd, tgt->pos[0] * (off_t)BLOCKSIZE, SEEK_SET); 524bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 525bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (style[0] == 'i') { // imgdiff 526bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ApplyImagePatch(buffer, src->size * BLOCKSIZE, 527bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker &patch_value, 528bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker &RangeSinkWrite, &rss, NULL, NULL); 529bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } else { 530bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ApplyBSDiffPatch(buffer, src->size * BLOCKSIZE, 531bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker &patch_value, 0, 532bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker &RangeSinkWrite, &rss, NULL); 533bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 534bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 535bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // We expect the output of the patcher to fill the tgt ranges exactly. 536bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (rss.p_block != tgt->count || rss.p_remain != 0) { 537bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fprintf(stderr, "range sink underrun?\n"); 538bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 539bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 540bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker blocks_so_far += tgt->size; 541bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks); 542bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fflush(cmd_pipe); 543bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 544bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker free(src); 545bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker free(tgt); 546bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } else if (!DEBUG_ERASE && strcmp("erase", style) == 0) { 547bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker struct stat st; 548bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) { 549bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker word = strtok_r(NULL, " ", &wordsave); 550bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSet* tgt = parse_range(word); 551bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 552bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf(" erasing %d blocks\n", tgt->size); 553bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 554bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (i = 0; i < tgt->count; ++i) { 555bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker uint64_t range[2]; 556bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // offset in bytes 5571d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker range[0] = tgt->pos[i*2] * (uint64_t)BLOCKSIZE; 558bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker // len in bytes 5591d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker range[1] = (tgt->pos[i*2+1] - tgt->pos[i*2]) * (uint64_t)BLOCKSIZE; 560bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 561bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (ioctl(fd, BLKDISCARD, &range) < 0) { 562bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf(" blkdiscard failed: %s\n", strerror(errno)); 563bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 564bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 565bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 566bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker free(tgt); 567bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } else { 568bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf(" ignoring erase (not block device)\n"); 569bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 570bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } else { 571bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker fprintf(stderr, "unknown transfer style \"%s\"\n", style); 572bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker exit(1); 573bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 574bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 575bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 576bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker pthread_join(new_data_thread, NULL); 577bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker success = true; 578bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 579bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker free(buffer); 580bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf("wrote %d blocks; expected %d\n", blocks_so_far, total_blocks); 581bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker printf("max alloc needed was %zu\n", buffer_alloc); 582bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 583bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker done: 5841d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker free(transfer_list); 585bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker FreeValue(blockdev_filename); 5861d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker FreeValue(transfer_list_value); 587bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker FreeValue(new_data_fn); 588bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker FreeValue(patch_data_fn); 589bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker return StringValue(success ? strdup("t") : strdup("")); 590bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker} 591bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 592bc7ffeda98a861e346c30c771d3258030f7fcf21Doug ZongkerValue* RangeSha1Fn(const char* name, State* state, int argc, Expr* argv[]) { 593bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker Value* blockdev_filename; 594bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker Value* ranges; 595bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker const uint8_t* digest = NULL; 596bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) { 597bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker return NULL; 598bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 599bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 600bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (blockdev_filename->type != VAL_STRING) { 601bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "blockdev_filename argument to %s must be string", name); 602bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 603bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 604bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (ranges->type != VAL_STRING) { 605bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "ranges argument to %s must be string", name); 606bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 607bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 608bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 609bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker int fd = open(blockdev_filename->data, O_RDWR); 610bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (fd < 0) { 611bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker ErrorAbort(state, "failed to open %s: %s", blockdev_filename->data, strerror(errno)); 612bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker goto done; 613bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 614bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 615bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RangeSet* rs = parse_range(ranges->data); 616bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker uint8_t buffer[BLOCKSIZE]; 617bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 618bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker SHA_CTX ctx; 619bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker SHA_init(&ctx); 620bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 621bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker int i, j; 622bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (i = 0; i < rs->count; ++i) { 6231d5d6098f4a470bc8e56ae8914180041815e6e22Doug Zongker check_lseek(fd, rs->pos[i*2] * (off_t)BLOCKSIZE, SEEK_SET); 624bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker for (j = rs->pos[i*2]; j < rs->pos[i*2+1]; ++j) { 625bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker readblock(fd, buffer, BLOCKSIZE); 626bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker SHA_update(&ctx, buffer, BLOCKSIZE); 627bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 628bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 629bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker digest = SHA_final(&ctx); 630bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker close(fd); 631bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 632bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker done: 633bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker FreeValue(blockdev_filename); 634bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker FreeValue(ranges); 635bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker if (digest == NULL) { 636bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker return StringValue(strdup("")); 637bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } else { 638bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker return StringValue(PrintSha1(digest)); 639bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker } 640bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker} 641bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker 642bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongkervoid RegisterBlockImageFunctions() { 643bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RegisterFunction("block_image_update", BlockImageUpdateFn); 644bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker RegisterFunction("range_sha1", RangeSha1Fn); 645bc7ffeda98a861e346c30c771d3258030f7fcf21Doug Zongker} 646