uncrypt.cpp revision f449db2f30235a0c2fef4bc7bc41776e271a60a0
176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker/*
276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * Copyright (C) 2014 The Android Open Source Project
376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker *
476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * Licensed under the Apache License, Version 2.0 (the "License");
576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * you may not use this file except in compliance with the License.
676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * You may obtain a copy of the License at
776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker *
876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker *      http://www.apache.org/licenses/LICENSE-2.0
976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker *
1076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * Unless required by applicable law or agreed to in writing, software
1176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * distributed under the License is distributed on an "AS IS" BASIS,
1276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * See the License for the specific language governing permissions and
1476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker * limitations under the License.
1576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker */
1676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
1776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// This program takes a file on an ext4 filesystem and produces a list
1876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// of the blocks that file occupies, which enables the file contents
1976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// to be read directly from the block device without mounting the
2076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// filesystem.
2176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//
2276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// If the filesystem is using an encrypted block device, it will also
2376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// read the file and rewrite it to the same blocks of the underlying
2476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// (unencrypted) block device, so the file contents can be read
2576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// without the need for the decryption key.
2676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//
2776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// The output of this program is a "block map" which looks like this:
2876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//
2976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//     /dev/block/platform/msm_sdcc.1/by-name/userdata     # block device
3076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//     49652 4096                        # file size in bytes, block size
3176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//     3                                 # count of block ranges
3276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//     1000 1008                         # block range 0
3376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//     2100 2102                         # ... block range 1
3476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//     30 33                             # ... block range 2
3576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//
3676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// Each block range represents a half-open interval; the line "30 33"
3776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// reprents the blocks [30, 31, 32].
3876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker//
3976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// Recovery can take this block map file and retrieve the underlying
4076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker// file data to use as an update package.
4176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
4276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <stdio.h>
4376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <stdlib.h>
4476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <stdarg.h>
4576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <sys/types.h>
4676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <sys/stat.h>
4776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <fcntl.h>
4876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <linux/fs.h>
4976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <sys/mman.h>
5076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
51f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker#define LOG_TAG "uncrypt"
52f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker#include <log/log.h>
5376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <cutils/properties.h>
5476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#include <fs_mgr.h>
5576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
5676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#define WINDOW_SIZE 5
5776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#define RECOVERY_COMMAND_FILE "/cache/recovery/command"
5876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#define RECOVERY_COMMAND_FILE_TMP "/cache/recovery/command.tmp"
5976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker#define CACHE_BLOCK_MAP "/cache/recovery/block.map"
6076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
612efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongkerstatic struct fstab* fstab = NULL;
622efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker
6376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongkerstatic int write_at_offset(unsigned char* buffer, size_t size,
6476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                           int wfd, off64_t offset)
6576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker{
6676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    lseek64(wfd, offset, SEEK_SET);
6776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    size_t written = 0;
6876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    while (written < size) {
6976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        ssize_t wrote = write(wfd, buffer + written, size - written);
7076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (wrote < 0) {
71f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker            ALOGE("error writing offset %lld: %s\n", offset, strerror(errno));
7276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            return -1;
7376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
7476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        written += wrote;
7576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
7676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    return 0;
7776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker}
7876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
7976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongkervoid add_block_to_ranges(int** ranges, int* range_alloc, int* range_used, int new_block)
8076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker{
8176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // If the current block start is < 0, set the start to the new
8276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // block.  (This only happens for the very first block of the very
8376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // first range.)
8476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if ((*ranges)[*range_used*2-2] < 0) {
8576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        (*ranges)[*range_used*2-2] = new_block;
8676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        (*ranges)[*range_used*2-1] = new_block;
8776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
8876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
8976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (new_block == (*ranges)[*range_used*2-1]) {
9076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // If the new block comes immediately after the current range,
9176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // all we have to do is extend the current range.
9276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        ++(*ranges)[*range_used*2-1];
9376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    } else {
9476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // We need to start a new range.
9576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
9676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // If there isn't enough room in the array, we need to expand it.
9776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (*range_used >= *range_alloc) {
9876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            *range_alloc *= 2;
9976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            *ranges = realloc(*ranges, *range_alloc * 2 * sizeof(int));
10076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
10176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
10276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        ++*range_used;
10376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        (*ranges)[*range_used*2-2] = new_block;
10476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        (*ranges)[*range_used*2-1] = new_block+1;
10576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
10676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker}
10776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
1082efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongkerstatic struct fstab* read_fstab()
10976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker{
1102efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    fstab = NULL;
1112efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker
11276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // The fstab path is always "/fstab.${ro.hardware}".
11376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    char fstab_path[PATH_MAX+1] = "/fstab.";
11476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (!property_get("ro.hardware", fstab_path+strlen(fstab_path), "")) {
115f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker        ALOGE("failed to get ro.hardware\n");
11676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        return NULL;
11776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
11876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
1192efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    fstab = fs_mgr_read_fstab(fstab_path);
12076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (!fstab) {
121f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker        ALOGE("failed to read %s\n", fstab_path);
12276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        return NULL;
12376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
12476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
1252efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    return fstab;
1262efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker}
1272efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker
1282efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongkerconst char* find_block_device(const char* path, int* encryptable, int* encrypted)
1292efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker{
13076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // Look for a volume whose mount point is the prefix of path and
13176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // return its block device.  Set encrypted if it's currently
13276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // encrypted.
13376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int i;
13476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    for (i = 0; i < fstab->num_entries; ++i) {
13576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        struct fstab_rec* v = &fstab->recs[i];
13676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (!v->mount_point) continue;
13776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        int len = strlen(v->mount_point);
13876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (strncmp(path, v->mount_point, len) == 0 &&
13976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            (path[len] == '/' || path[len] == 0)) {
14076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            *encrypted = 0;
14176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            *encryptable = 0;
14276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            if (fs_mgr_is_encryptable(v)) {
14376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                *encryptable = 1;
14476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                char buffer[PROPERTY_VALUE_MAX+1];
14576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                if (property_get("ro.crypto.state", buffer, "") &&
14676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                    strcmp(buffer, "encrypted") == 0) {
14776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                    *encrypted = 1;
14876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                }
14976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            }
15076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            return v->blk_device;
15176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
15276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
15376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
15476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    return NULL;
15576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker}
15676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
15776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongkerchar* parse_recovery_command_file()
15876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker{
15976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    char* fn = NULL;
16076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int count = 0;
16176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    char temp[1024];
16276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
163e7b288824589b2828d83e1d47f6f12b0bd0fb353Maxim Siniavine
16476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
16576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    FILE* f = fopen(RECOVERY_COMMAND_FILE, "r");
166e7b288824589b2828d83e1d47f6f12b0bd0fb353Maxim Siniavine    if (f == NULL) {
167e7b288824589b2828d83e1d47f6f12b0bd0fb353Maxim Siniavine        return NULL;
168e7b288824589b2828d83e1d47f6f12b0bd0fb353Maxim Siniavine    }
169e7b288824589b2828d83e1d47f6f12b0bd0fb353Maxim Siniavine    FILE* fo = fopen(RECOVERY_COMMAND_FILE_TMP, "w");
170e7b288824589b2828d83e1d47f6f12b0bd0fb353Maxim Siniavine
17176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    while (fgets(temp, sizeof(temp), f)) {
17276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        printf("read: %s", temp);
173eaf33654c1817bd665831a13c5bd0c04daabee02Doug Zongker        if (strncmp(temp, "--update_package=/data/", strlen("--update_package=/data/")) == 0) {
17476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            fn = strdup(temp + strlen("--update_package="));
17576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            strcpy(temp, "--update_package=@" CACHE_BLOCK_MAP "\n");
17676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
17776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        fputs(temp, fo);
17876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
17976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    fclose(f);
18076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    fclose(fo);
18176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
18276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (fn) {
18376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        char* newline = strchr(fn, '\n');
18476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (newline) *newline = 0;
18576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
18676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    return fn;
18776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker}
18876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
18976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongkerint produce_block_map(const char* path, const char* map_file, const char* blk_dev,
19076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                      int encrypted)
19176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker{
19276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    struct stat sb;
19376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int ret;
19476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
19576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    FILE* mapf = fopen(map_file, "w");
19676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
19776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    ret = stat(path, &sb);
19876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (ret != 0) {
199f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker        ALOGE("failed to stat %s\n", path);
20076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        return -1;
20176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
20276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
203f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker    ALOGI(" block size: %ld bytes\n", (long)sb.st_blksize);
20476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
20576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int blocks = ((sb.st_size-1) / sb.st_blksize) + 1;
206f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker    ALOGI("  file size: %lld bytes, %d blocks\n", (long long)sb.st_size, blocks);
20776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
20876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int* ranges;
20976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int range_alloc = 1;
21076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int range_used = 1;
21176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    ranges = malloc(range_alloc * 2 * sizeof(int));
21276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    ranges[0] = -1;
21376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    ranges[1] = -1;
21476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
2152605dec597f7ebabf31b7e9430f19ab888b2919aMark Salyzyn    fprintf(mapf, "%s\n%lld %lu\n", blk_dev, (long long)sb.st_size, (unsigned long)sb.st_blksize);
21676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
21776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    unsigned char* buffers[WINDOW_SIZE];
21876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int i;
21976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (encrypted) {
22076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        for (i = 0; i < WINDOW_SIZE; ++i) {
22176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            buffers[i] = malloc(sb.st_blksize);
22276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
22376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
22476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int head_block = 0;
22576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int head = 0, tail = 0;
22676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    size_t pos = 0;
22776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
22876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int fd = open(path, O_RDONLY);
22976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (fd < 0) {
230f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker        ALOGE("failed to open fd for reading: %s\n", strerror(errno));
23176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        return -1;
23276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
23376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    fsync(fd);
23476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
23576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int wfd = -1;
23676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (encrypted) {
23776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        wfd = open(blk_dev, O_WRONLY);
23876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (wfd < 0) {
239f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker            ALOGE("failed to open fd for writing: %s\n", strerror(errno));
24076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            return -1;
24176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
24276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
24376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
24476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    while (pos < sb.st_size) {
24576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if ((tail+1) % WINDOW_SIZE == head) {
24676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            // write out head buffer
24776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            int block = head_block;
24876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            ret = ioctl(fd, FIBMAP, &block);
24976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            if (ret != 0) {
250f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker                ALOGE("failed to find block %d\n", head_block);
25176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                return -1;
25276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            }
25376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            add_block_to_ranges(&ranges, &range_alloc, &range_used, block);
25476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            if (encrypted) {
25576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                if (write_at_offset(buffers[head], sb.st_blksize, wfd, (off64_t)sb.st_blksize * block) != 0) {
25676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                    return -1;
25776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                }
25876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            }
25976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            head = (head + 1) % WINDOW_SIZE;
26076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            ++head_block;
26176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
26276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
26376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // read next block to tail
26476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (encrypted) {
26576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            size_t so_far = 0;
26676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            while (so_far < sb.st_blksize && pos < sb.st_size) {
26776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                ssize_t this_read = read(fd, buffers[tail] + so_far, sb.st_blksize - so_far);
26876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                if (this_read < 0) {
269f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker                    ALOGE("failed to read: %s\n", strerror(errno));
27076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                    return -1;
27176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                }
27276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                so_far += this_read;
27376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                pos += this_read;
27476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            }
27576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        } else {
27676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            // If we're not encrypting; we don't need to actually read
27776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            // anything, just skip pos forward as if we'd read a
27876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            // block.
27976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            pos += sb.st_blksize;
28076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
28176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        tail = (tail+1) % WINDOW_SIZE;
28276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
28376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
28476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    while (head != tail) {
28576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // write out head buffer
28676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        int block = head_block;
28776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        ret = ioctl(fd, FIBMAP, &block);
28876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (ret != 0) {
289f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker            ALOGE("failed to find block %d\n", head_block);
29076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            return -1;
29176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
29276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        add_block_to_ranges(&ranges, &range_alloc, &range_used, block);
29376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (encrypted) {
29476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            if (write_at_offset(buffers[head], sb.st_blksize, wfd, (off64_t)sb.st_blksize * block) != 0) {
29576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker                return -1;
29676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            }
29776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
29876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        head = (head + 1) % WINDOW_SIZE;
29976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        ++head_block;
30076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
30176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
30276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    fprintf(mapf, "%d\n", range_used);
30376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    for (i = 0; i < range_used; ++i) {
30476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        fprintf(mapf, "%d %d\n", ranges[i*2], ranges[i*2+1]);
30576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
30676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
30776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    fclose(mapf);
30876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    close(fd);
30976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (encrypted) {
31076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        close(wfd);
31176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
31276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
31376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    return 0;
31476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker}
31576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
3162efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongkervoid wipe_misc() {
317f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker    ALOGI("removing old commands from misc");
3182efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    int i;
3192efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    for (i = 0; i < fstab->num_entries; ++i) {
3202efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker        struct fstab_rec* v = &fstab->recs[i];
3212efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker        if (!v->mount_point) continue;
3222efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker        if (strcmp(v->mount_point, "/misc") == 0) {
323f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker            int fd = open(v->blk_device, O_WRONLY);
3242efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker            uint8_t zeroes[1088];   // sizeof(bootloader_message) from recovery
3252efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker            memset(zeroes, 0, sizeof(zeroes));
3262efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker
3272efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker            size_t written = 0;
3282efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker            size_t size = sizeof(zeroes);
3292efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker            while (written < size) {
3302efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker                ssize_t w = write(fd, zeroes, size-written);
3312efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker                if (w < 0 && errno != EINTR) {
332f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker                    ALOGE("zero write failed: %s\n", strerror(errno));
3332efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker                    return;
3342efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker                } else {
3352efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker                    written += w;
3362efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker                }
3372efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker            }
3382efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker
3392efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker            close(fd);
3402efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker        }
3412efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    }
3422efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker}
3432efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker
34476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongkervoid reboot_to_recovery() {
345f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker    ALOGI("rebooting to recovery");
34676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    property_set("sys.powerctl", "reboot,recovery");
34776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    sleep(10);
348f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker    ALOGE("reboot didn't succeed?");
34976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker}
35076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
35176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongkerint main(int argc, char** argv)
35276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker{
35376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    const char* input_path;
35476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    const char* map_file;
35576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int do_reboot = 1;
35676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
35776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (argc != 1 && argc != 3) {
35876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        fprintf(stderr, "usage: %s [<transform_path> <map_file>]\n", argv[0]);
35976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        return 2;
36076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
36176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
36276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (argc == 3) {
36376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // when command-line args are given this binary is being used
36476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // for debugging; don't reboot to recovery at the end.
36576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        input_path = argv[1];
36676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        map_file = argv[2];
36776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        do_reboot = 0;
36876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    } else {
36976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        input_path = parse_recovery_command_file();
37076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (input_path == NULL) {
37176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            // if we're rebooting to recovery without a package (say,
37276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            // to wipe data), then we don't need to do anything before
37376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            // going to recovery.
374f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker            ALOGI("no recovery command file or no update package arg");
37576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            reboot_to_recovery();
37676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            return 1;
37776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
37876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        map_file = CACHE_BLOCK_MAP;
37976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
38076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
381f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker    ALOGI("update package is %s", input_path);
382f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker
38376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // Turn the name of the file we're supposed to convert into an
38476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // absolute path, so we can find what filesystem it's on.
38576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    char path[PATH_MAX+1];
38676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (realpath(input_path, path) == NULL) {
387f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker        ALOGE("failed to convert %s to absolute path: %s", input_path, strerror(errno));
38876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        return 1;
38976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
39076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
39176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int encryptable;
39276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    int encrypted;
3932efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    if (read_fstab() == NULL) {
3942efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker        return 1;
3952efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    }
39676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    const char* blk_dev = find_block_device(path, &encryptable, &encrypted);
39776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (blk_dev == NULL) {
398f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker        ALOGE("failed to find block device for %s", path);
39976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        return 1;
40076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
40176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
40276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // If the filesystem it's on isn't encrypted, we only produce the
40376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // block map, we don't rewrite the file contents (it would be
40476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    // pointless to do so).
405f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker    ALOGI("encryptable: %s\n", encryptable ? "yes" : "no");
406f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker    ALOGI("  encrypted: %s\n", encrypted ? "yes" : "no");
40776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
40876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    if (!encryptable) {
40976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // If the file is on a filesystem that doesn't support
41076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // encryption (eg, /cache), then leave it alone.
41176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        //
41276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // TODO: change this to be !encrypted -- if the file is on
41376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // /data but /data isn't encrypted, we don't need to use the
41476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // block map mechanism.  We do for now so as to get more
41576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // testing of it (since most dogfood devices aren't
41676adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        // encrypted).
41776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
41876adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        unlink(RECOVERY_COMMAND_FILE_TMP);
41976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    } else {
420f449db2f30235a0c2fef4bc7bc41776e271a60a0Doug Zongker        ALOGI("writing block map %s", map_file);
42176adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        if (produce_block_map(path, map_file, blk_dev, encrypted) != 0) {
42276adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker            return 1;
42376adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker        }
42476adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    }
42576adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker
4262efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    wipe_misc();
42776adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    rename(RECOVERY_COMMAND_FILE_TMP, RECOVERY_COMMAND_FILE);
4282efc9d994ce59f9ebfc2290c2adc5d760e8939c2Doug Zongker    if (do_reboot) reboot_to_recovery();
42976adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker    return 0;
43076adfc5309936a07218ce53b5ab284d5746fa84cDoug Zongker}
431