Advertisement
Guest User

Untitled

a guest
Mar 4th, 2015
178
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 21.51 KB | None | 0 0
  1. /*
  2.  * Copyright (C) 2014 The Android Open Source Project
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *      http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16.  
  17. #include <ctype.h>
  18. #include <errno.h>
  19. #include <fcntl.h>
  20. #include <inttypes.h>
  21. #include <pthread.h>
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #include <sys/wait.h>
  28. #include <sys/ioctl.h>
  29. #include <time.h>
  30. #include <unistd.h>
  31.  
  32. #include "applypatch/applypatch.h"
  33. #include "edify/expr.h"
  34. #include "mincrypt/sha.h"
  35. #include "minzip/DirUtil.h"
  36. #include "updater.h"
  37.  
  38. #define BLOCKSIZE 4096
  39.  
  40. // Set this to 0 to interpret 'erase' transfers to mean do a
  41. // BLKDISCARD ioctl (the normal behavior).  Set to 1 to interpret
  42. // erase to mean fill the region with zeroes.
  43. #define DEBUG_ERASE  0
  44.  
  45. #ifndef BLKDISCARD
  46. #define BLKDISCARD _IO(0x12,119)
  47. #endif
  48.  
  49. char* PrintSha1(const uint8_t* digest);
  50.  
  51. typedef struct {
  52.     int count;
  53.     int size;
  54.     int pos[0];
  55. } RangeSet;
  56.  
  57. static RangeSet* parse_range(char* text) {
  58.     char* save;
  59.     int num;
  60.     num = strtol(strtok_r(text, ",", &save), NULL, 0);
  61.  
  62.     RangeSet* out = malloc(sizeof(RangeSet) + num * sizeof(int));
  63.     if (out == NULL) {
  64.         fprintf(stderr, "failed to allocate range of %zu bytes\n",
  65.                 sizeof(RangeSet) + num * sizeof(int));
  66.         exit(1);
  67.     }
  68.     out->count = num / 2;
  69.     out->size = 0;
  70.     int i;
  71.     for (i = 0; i < num; ++i) {
  72.         out->pos[i] = strtol(strtok_r(NULL, ",", &save), NULL, 0);
  73.         if (i%2) {
  74.             out->size += out->pos[i];
  75.         } else {
  76.             out->size -= out->pos[i];
  77.         }
  78.     }
  79.  
  80.     return out;
  81. }
  82.  
  83. static void readblock(int fd, uint8_t* data, size_t size) {
  84.     size_t so_far = 0;
  85.     while (so_far < size) {
  86.         ssize_t r = read(fd, data+so_far, size-so_far);
  87.         if (r < 0 && errno != EINTR) {
  88.             fprintf(stderr, "read failed: %s\n", strerror(errno));
  89.             return;
  90.         } else {
  91.             so_far += r;
  92.         }
  93.     }
  94. }
  95.  
  96. static void writeblock(int fd, const uint8_t* data, size_t size) {
  97.     size_t written = 0;
  98.     while (written < size) {
  99.         ssize_t w = write(fd, data+written, size-written);
  100.         if (w < 0 && errno != EINTR) {
  101.             fprintf(stderr, "write failed: %s\n", strerror(errno));
  102.             return;
  103.         } else {
  104.             written += w;
  105.         }
  106.     }
  107. }
  108.  
  109. static void check_lseek(int fd, off64_t offset, int whence) {
  110.     while (true) {
  111.         off64_t ret = lseek64(fd, offset, whence);
  112.         if (ret < 0) {
  113.             if (errno != EINTR) {
  114.                 fprintf(stderr, "lseek64 failed: %s\n", strerror(errno));
  115.                 exit(1);
  116.             }
  117.         } else {
  118.             break;
  119.         }
  120.     }
  121. }
  122.  
  123. static void allocate(size_t size, uint8_t** buffer, size_t* buffer_alloc) {
  124.     // if the buffer's big enough, reuse it.
  125.     if (size <= *buffer_alloc) return;
  126.  
  127.     free(*buffer);
  128.  
  129.     *buffer = (uint8_t*) malloc(size);
  130.     if (*buffer == NULL) {
  131.         fprintf(stderr, "failed to allocate %zu bytes\n", size);
  132.         exit(1);
  133.     }
  134.     *buffer_alloc = size;
  135. }
  136.  
  137. typedef struct {
  138.     int fd;
  139.     RangeSet* tgt;
  140.     int p_block;
  141.     size_t p_remain;
  142. } RangeSinkState;
  143.  
  144. static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
  145.     RangeSinkState* rss = (RangeSinkState*) token;
  146.  
  147.     if (rss->p_remain <= 0) {
  148.         fprintf(stderr, "range sink write overrun");
  149.         exit(1);
  150.     }
  151.  
  152.     ssize_t written = 0;
  153.     while (size > 0) {
  154.         size_t write_now = size;
  155.         if (rss->p_remain < write_now) write_now = rss->p_remain;
  156.         writeblock(rss->fd, data, write_now);
  157.         data += write_now;
  158.         size -= write_now;
  159.  
  160.         rss->p_remain -= write_now;
  161.         written += write_now;
  162.  
  163.         if (rss->p_remain == 0) {
  164.             // move to the next block
  165.             ++rss->p_block;
  166.             if (rss->p_block < rss->tgt->count) {
  167.                 rss->p_remain = (rss->tgt->pos[rss->p_block*2+1] - rss->tgt->pos[rss->p_block*2]) * BLOCKSIZE;
  168.                 check_lseek(rss->fd, (off64_t)rss->tgt->pos[rss->p_block*2] * BLOCKSIZE, SEEK_SET);
  169.             } else {
  170.                 // we can't write any more; return how many bytes have
  171.                 // been written so far.
  172.                 return written;
  173.             }
  174.         }
  175.     }
  176.  
  177.     return written;
  178. }
  179.  
  180. // All of the data for all the 'new' transfers is contained in one
  181. // file in the update package, concatenated together in the order in
  182. // which transfers.list will need it.  We want to stream it out of the
  183. // archive (it's compressed) without writing it to a temp file, but we
  184. // can't write each section until it's that transfer's turn to go.
  185. //
  186. // To achieve this, we expand the new data from the archive in a
  187. // background thread, and block that threads 'receive uncompressed
  188. // data' function until the main thread has reached a point where we
  189. // want some new data to be written.  We signal the background thread
  190. // with the destination for the data and block the main thread,
  191. // waiting for the background thread to complete writing that section.
  192. // Then it signals the main thread to wake up and goes back to
  193. // blocking waiting for a transfer.
  194. //
  195. // NewThreadInfo is the struct used to pass information back and forth
  196. // between the two threads.  When the main thread wants some data
  197. // written, it sets rss to the destination location and signals the
  198. // condition.  When the background thread is done writing, it clears
  199. // rss and signals the condition again.
  200.  
  201. typedef struct {
  202.     ZipArchive* za;
  203.     const ZipEntry* entry;
  204.  
  205.     RangeSinkState* rss;
  206.  
  207.     pthread_mutex_t mu;
  208.     pthread_cond_t cv;
  209. } NewThreadInfo;
  210.  
  211. static bool receive_new_data(const unsigned char* data, int size, void* cookie) {
  212.     NewThreadInfo* nti = (NewThreadInfo*) cookie;
  213.  
  214.     while (size > 0) {
  215.         // Wait for nti->rss to be non-NULL, indicating some of this
  216.         // data is wanted.
  217.         pthread_mutex_lock(&nti->mu);
  218.         while (nti->rss == NULL) {
  219.             pthread_cond_wait(&nti->cv, &nti->mu);
  220.         }
  221.         pthread_mutex_unlock(&nti->mu);
  222.  
  223.         // At this point nti->rss is set, and we own it.  The main
  224.         // thread is waiting for it to disappear from nti.
  225.         ssize_t written = RangeSinkWrite(data, size, nti->rss);
  226.         data += written;
  227.         size -= written;
  228.  
  229.         if (nti->rss->p_block == nti->rss->tgt->count) {
  230.             // we have written all the bytes desired by this rss.
  231.  
  232.             pthread_mutex_lock(&nti->mu);
  233.             nti->rss = NULL;
  234.             pthread_cond_broadcast(&nti->cv);
  235.             pthread_mutex_unlock(&nti->mu);
  236.         }
  237.     }
  238.  
  239.     return true;
  240. }
  241.  
  242. static void* unzip_new_data(void* cookie) {
  243.     NewThreadInfo* nti = (NewThreadInfo*) cookie;
  244.     mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti);
  245.     return NULL;
  246. }
  247.  
  248. // args:
  249. //    - block device (or file) to modify in-place
  250. //    - transfer list (blob)
  251. //    - new data stream (filename within package.zip)
  252. //    - patch stream (filename within package.zip, must be uncompressed)
  253.  
  254. Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]) {
  255.     Value* blockdev_filename;
  256.     Value* transfer_list_value;
  257.     char* transfer_list = NULL;
  258.     Value* new_data_fn;
  259.     Value* patch_data_fn;
  260.     bool success = false;
  261.  
  262.     if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value,
  263.                       &new_data_fn, &patch_data_fn) < 0) {
  264.         return NULL;
  265.     }
  266.  
  267.     if (blockdev_filename->type != VAL_STRING) {
  268.         ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
  269.         goto done;
  270.     }
  271.     if (transfer_list_value->type != VAL_BLOB) {
  272.         ErrorAbort(state, "transfer_list argument to %s must be blob", name);
  273.         goto done;
  274.     }
  275.     if (new_data_fn->type != VAL_STRING) {
  276.         ErrorAbort(state, "new_data_fn argument to %s must be string", name);
  277.         goto done;
  278.     }
  279.     if (patch_data_fn->type != VAL_STRING) {
  280.         ErrorAbort(state, "patch_data_fn argument to %s must be string", name);
  281.         goto done;
  282.     }
  283.  
  284.     UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
  285.     FILE* cmd_pipe = ui->cmd_pipe;
  286.  
  287.     ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip;
  288.  
  289.     const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data);
  290.     if (patch_entry == NULL) {
  291.         ErrorAbort(state, "%s(): no file \"%s\" in package", name, patch_data_fn->data);
  292.         goto done;
  293.     }
  294.  
  295.     uint8_t* patch_start = ((UpdaterInfo*)(state->cookie))->package_zip_addr +
  296.         mzGetZipEntryOffset(patch_entry);
  297.  
  298.     const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data);
  299.     if (new_entry == NULL) {
  300.         ErrorAbort(state, "%s(): no file \"%s\" in package", name, new_data_fn->data);
  301.         goto done;
  302.     }
  303.  
  304.     // The transfer list is a text file containing commands to
  305.     // transfer data from one place to another on the target
  306.     // partition.  We parse it and execute the commands in order:
  307.     //
  308.     //    zero [rangeset]
  309.     //      - fill the indicated blocks with zeros
  310.     //
  311.     //    new [rangeset]
  312.     //      - fill the blocks with data read from the new_data file
  313.     //
  314.     //    bsdiff patchstart patchlen [src rangeset] [tgt rangeset]
  315.     //    imgdiff patchstart patchlen [src rangeset] [tgt rangeset]
  316.     //      - read the source blocks, apply a patch, write result to
  317.     //        target blocks.  bsdiff or imgdiff specifies the type of
  318.     //        patch.
  319.     //
  320.     //    move [src rangeset] [tgt rangeset]
  321.     //      - copy data from source blocks to target blocks (no patch
  322.     //        needed; rangesets are the same size)
  323.     //
  324.     //    erase [rangeset]
  325.     //      - mark the given blocks as empty
  326.     //
  327.     // The creator of the transfer list will guarantee that no block
  328.     // is read (ie, used as the source for a patch or move) after it
  329.     // has been written.
  330.     //
  331.     // Within one command the source and target ranges may overlap so
  332.     // in general we need to read the entire source into memory before
  333.     // writing anything to the target blocks.
  334.     //
  335.     // All the patch data is concatenated into one patch_data file in
  336.     // the update package.  It must be stored uncompressed because we
  337.     // memory-map it in directly from the archive.  (Since patches are
  338.     // already compressed, we lose very little by not compressing
  339.     // their concatenation.)
  340.  
  341.     pthread_t new_data_thread;
  342.     NewThreadInfo nti;
  343.     nti.za = za;
  344.     nti.entry = new_entry;
  345.     nti.rss = NULL;
  346.     pthread_mutex_init(&nti.mu, NULL);
  347.     pthread_cond_init(&nti.cv, NULL);
  348.  
  349.     pthread_attr_t attr;
  350.     pthread_attr_init(&attr);
  351.     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  352.     pthread_create(&new_data_thread, &attr, unzip_new_data, &nti);
  353.  
  354.     int i, j;
  355.  
  356.     char* linesave;
  357.     char* wordsave;
  358.  
  359.     int fd = open(blockdev_filename->data, O_RDWR);
  360.     if (fd < 0) {
  361.         ErrorAbort(state, "failed to open %s: %s", blockdev_filename->data, strerror(errno));
  362.         goto done;
  363.     }
  364.  
  365.     char* line;
  366.     char* word;
  367.  
  368.     // The data in transfer_list_value is not necessarily
  369.     // null-terminated, so we need to copy it to a new buffer and add
  370.     // the null that strtok_r will need.
  371.     transfer_list = malloc(transfer_list_value->size+1);
  372.     if (transfer_list == NULL) {
  373.         fprintf(stderr, "failed to allocate %zd bytes for transfer list\n",
  374.                 transfer_list_value->size+1);
  375.         exit(1);
  376.     }
  377.     memcpy(transfer_list, transfer_list_value->data, transfer_list_value->size);
  378.     transfer_list[transfer_list_value->size] = '\0';
  379.  
  380.     line = strtok_r(transfer_list, "\n", &linesave);
  381.  
  382.     // first line in transfer list is the version number; currently
  383.     // there's only version 1.
  384.     if (strcmp(line, "1") != 0) {
  385.         ErrorAbort(state, "unexpected transfer list version [%s]\n", line);
  386.         goto done;
  387.     }
  388.  
  389.     // second line in transfer list is the total number of blocks we
  390.     // expect to write.
  391.     line = strtok_r(NULL, "\n", &linesave);
  392.     int total_blocks = strtol(line, NULL, 0);
  393.     // shouldn't happen, but avoid divide by zero.
  394.     if (total_blocks == 0) ++total_blocks;
  395.     int blocks_so_far = 0;
  396.  
  397.     uint8_t* buffer = NULL;
  398.     size_t buffer_alloc = 0;
  399.  
  400.     // third and subsequent lines are all individual transfer commands.
  401.     for (line = strtok_r(NULL, "\n", &linesave); line;
  402.          line = strtok_r(NULL, "\n", &linesave)) {
  403.         char* style;
  404.         style = strtok_r(line, " ", &wordsave);
  405.  
  406.         if (strcmp("move", style) == 0) {
  407.             word = strtok_r(NULL, " ", &wordsave);
  408.             RangeSet* src = parse_range(word);
  409.             word = strtok_r(NULL, " ", &wordsave);
  410.             RangeSet* tgt = parse_range(word);
  411.  
  412.             printf("  moving %d blocks\n", src->size);
  413.  
  414.             allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc);
  415.             size_t p = 0;
  416.             for (i = 0; i < src->count; ++i) {
  417.                 check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
  418.                 size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
  419.                 readblock(fd, buffer+p, sz);
  420.                 p += sz;
  421.             }
  422.  
  423.             p = 0;
  424.             for (i = 0; i < tgt->count; ++i) {
  425.                 check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
  426.                 size_t sz = (tgt->pos[i*2+1] - tgt->pos[i*2]) * BLOCKSIZE;
  427.                 writeblock(fd, buffer+p, sz);
  428.                 p += sz;
  429.             }
  430.  
  431.             blocks_so_far += tgt->size;
  432.             fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
  433.             fflush(cmd_pipe);
  434.  
  435.             free(src);
  436.             free(tgt);
  437.  
  438.         } else if (strcmp("zero", style) == 0 ||
  439.                    (DEBUG_ERASE && strcmp("erase", style) == 0)) {
  440.             word = strtok_r(NULL, " ", &wordsave);
  441.             RangeSet* tgt = parse_range(word);
  442.  
  443.             printf("  zeroing %d blocks\n", tgt->size);
  444.  
  445.             allocate(BLOCKSIZE, &buffer, &buffer_alloc);
  446.             memset(buffer, 0, BLOCKSIZE);
  447.             for (i = 0; i < tgt->count; ++i) {
  448.                 check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
  449.                 for (j = tgt->pos[i*2]; j < tgt->pos[i*2+1]; ++j) {
  450.                     writeblock(fd, buffer, BLOCKSIZE);
  451.                 }
  452.             }
  453.  
  454.             if (style[0] == 'z') {   // "zero" but not "erase"
  455.                 blocks_so_far += tgt->size;
  456.                 fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
  457.                 fflush(cmd_pipe);
  458.             }
  459.  
  460.             free(tgt);
  461.         } else if (strcmp("new", style) == 0) {
  462.  
  463.             word = strtok_r(NULL, " ", &wordsave);
  464.             RangeSet* tgt = parse_range(word);
  465.  
  466.             printf("  writing %d blocks of new data\n", tgt->size);
  467.  
  468.             RangeSinkState rss;
  469.             rss.fd = fd;
  470.             rss.tgt = tgt;
  471.             rss.p_block = 0;
  472.             rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE;
  473.             check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
  474.  
  475.             pthread_mutex_lock(&nti.mu);
  476.             nti.rss = &rss;
  477.             pthread_cond_broadcast(&nti.cv);
  478.             while (nti.rss) {
  479.                 pthread_cond_wait(&nti.cv, &nti.mu);
  480.             }
  481.             pthread_mutex_unlock(&nti.mu);
  482.  
  483.             blocks_so_far += tgt->size;
  484.             fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
  485.             fflush(cmd_pipe);
  486.  
  487.             free(tgt);
  488.  
  489.         } else if (strcmp("bsdiff", style) == 0 ||
  490.                    strcmp("imgdiff", style) == 0) {
  491.             word = strtok_r(NULL, " ", &wordsave);
  492.             size_t patch_offset = strtoul(word, NULL, 0);
  493.             word = strtok_r(NULL, " ", &wordsave);
  494.             size_t patch_len = strtoul(word, NULL, 0);
  495.  
  496.             word = strtok_r(NULL, " ", &wordsave);
  497.             RangeSet* src = parse_range(word);
  498.             word = strtok_r(NULL, " ", &wordsave);
  499.             RangeSet* tgt = parse_range(word);
  500.  
  501.             printf("  patching %d blocks to %d\n", src->size, tgt->size);
  502.  
  503.             // Read the source into memory.
  504.             allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc);
  505.             size_t p = 0;
  506.             for (i = 0; i < src->count; ++i) {
  507.                 check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
  508.                 size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
  509.                 readblock(fd, buffer+p, sz);
  510.                 p += sz;
  511.             }
  512.  
  513.             Value patch_value;
  514.             patch_value.type = VAL_BLOB;
  515.             patch_value.size = patch_len;
  516.             patch_value.data = (char*)(patch_start + patch_offset);
  517.  
  518.             RangeSinkState rss;
  519.             rss.fd = fd;
  520.             rss.tgt = tgt;
  521.             rss.p_block = 0;
  522.             rss.p_remain = (tgt->pos[1] - tgt->pos[0]) * BLOCKSIZE;
  523.             check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
  524.  
  525.             if (style[0] == 'i') {      // imgdiff
  526.                 ApplyImagePatch(buffer, src->size * BLOCKSIZE,
  527.                                 &patch_value,
  528.                                 &RangeSinkWrite, &rss, NULL, NULL);
  529.             } else {
  530.                 ApplyBSDiffPatch(buffer, src->size * BLOCKSIZE,
  531.                                  &patch_value, 0,
  532.                                  &RangeSinkWrite, &rss, NULL);
  533.             }
  534.  
  535.             // We expect the output of the patcher to fill the tgt ranges exactly.
  536.             if (rss.p_block != tgt->count || rss.p_remain != 0) {
  537.                 fprintf(stderr, "range sink underrun?\n");
  538.             }
  539.  
  540.             blocks_so_far += tgt->size;
  541.             fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
  542.             fflush(cmd_pipe);
  543.  
  544.             free(src);
  545.             free(tgt);
  546.         } else if (!DEBUG_ERASE && strcmp("erase", style) == 0) {
  547.             struct stat st;
  548.             if (fstat(fd, &st) == 0 && S_ISBLK(st.st_mode)) {
  549.                 word = strtok_r(NULL, " ", &wordsave);
  550.                 RangeSet* tgt = parse_range(word);
  551.  
  552.                 printf("  erasing %d blocks\n", tgt->size);
  553.  
  554.                 for (i = 0; i < tgt->count; ++i) {
  555.                     uint64_t range[2];
  556.                     // offset in bytes
  557.                     range[0] = tgt->pos[i*2] * (uint64_t)BLOCKSIZE;
  558.                     // len in bytes
  559.                     range[1] = (tgt->pos[i*2+1] - tgt->pos[i*2]) * (uint64_t)BLOCKSIZE;
  560.  
  561.                     if (ioctl(fd, BLKDISCARD, &range) < 0) {
  562.                         printf("    blkdiscard failed: %s\n", strerror(errno));
  563.                     }
  564.                 }
  565.  
  566.                 free(tgt);
  567.             } else {
  568.                 printf("  ignoring erase (not block device)\n");
  569.             }
  570.         } else {
  571.             fprintf(stderr, "unknown transfer style \"%s\"\n", style);
  572.             exit(1);
  573.         }
  574.     }
  575.  
  576.     pthread_join(new_data_thread, NULL);
  577.     success = true;
  578.  
  579.     free(buffer);
  580.     printf("wrote %d blocks; expected %d\n", blocks_so_far, total_blocks);
  581.     printf("max alloc needed was %zu\n", buffer_alloc);
  582.  
  583.   done:
  584.     free(transfer_list);
  585.     FreeValue(blockdev_filename);
  586.     FreeValue(transfer_list_value);
  587.     FreeValue(new_data_fn);
  588.     FreeValue(patch_data_fn);
  589.     return StringValue(success ? strdup("t") : strdup(""));
  590. }
  591.  
  592. Value* RangeSha1Fn(const char* name, State* state, int argc, Expr* argv[]) {
  593.     Value* blockdev_filename;
  594.     Value* ranges;
  595.     const uint8_t* digest = NULL;
  596.     if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) {
  597.         return NULL;
  598.     }
  599.  
  600.     if (blockdev_filename->type != VAL_STRING) {
  601.         ErrorAbort(state, "blockdev_filename argument to %s must be string", name);
  602.         goto done;
  603.     }
  604.     if (ranges->type != VAL_STRING) {
  605.         ErrorAbort(state, "ranges argument to %s must be string", name);
  606.         goto done;
  607.     }
  608.  
  609.     int fd = open(blockdev_filename->data, O_RDWR);
  610.     if (fd < 0) {
  611.         ErrorAbort(state, "failed to open %s: %s", blockdev_filename->data, strerror(errno));
  612.         goto done;
  613.     }
  614.  
  615.     RangeSet* rs = parse_range(ranges->data);
  616.     uint8_t buffer[BLOCKSIZE];
  617.  
  618.     SHA_CTX ctx;
  619.     SHA_init(&ctx);
  620.  
  621.     int i, j;
  622.     for (i = 0; i < rs->count; ++i) {
  623.         check_lseek(fd, (off64_t)rs->pos[i*2] * BLOCKSIZE, SEEK_SET);
  624.         for (j = rs->pos[i*2]; j < rs->pos[i*2+1]; ++j) {
  625.             readblock(fd, buffer, BLOCKSIZE);
  626.             SHA_update(&ctx, buffer, BLOCKSIZE);
  627.         }
  628.     }
  629.     digest = SHA_final(&ctx);
  630.     close(fd);
  631.  
  632.   done:
  633.     FreeValue(blockdev_filename);
  634.     FreeValue(ranges);
  635.     if (digest == NULL) {
  636.         return StringValue(strdup(""));
  637.     } else {
  638.         return StringValue(PrintSha1(digest));
  639.     }
  640. }
  641.  
  642. void RegisterBlockImageFunctions() {
  643.     RegisterFunction("block_image_update", BlockImageUpdateFn);
  644.     RegisterFunction("range_sha1", RangeSha1Fn);
  645. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement