1716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// Copyright 2014 The Android Open Source Project 2716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// 3716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// This software is licensed under the terms of the GNU General Public 4716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// License version 2, as published by the Free Software Foundation, and 5716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// may be copied, distributed, and modified under those terms. 6716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// 7716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// This program is distributed in the hope that it will be useful, 8716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// but WITHOUT ANY WARRANTY; without even the implied warranty of 9716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// GNU General Public License for more details. 11716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 12716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include "android/filesystems/ramdisk_extractor.h" 13716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 14716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include "android/base/Compiler.h" 15716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include "android/base/Log.h" 16716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include "android/base/String.h" 17716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 18716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include <inttypes.h> 19716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include <stdio.h> 20716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include <stdlib.h> 21716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include <string.h> 22716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#include <zlib.h> 23716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 24716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#define DEBUG 0 25716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 26716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#if DEBUG 27716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner# define D(...) printf(__VA_ARGS__), fflush(stdout) 28716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#else 29716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner# define D(...) ((void)0) 30716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner#endif 31716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 32716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// Ramdisk images are gzipped cpio archives using the new ASCII 33716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// format as described at [1]. Hence this source file first implements 34716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// a gzip-based input stream class, then 35716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// 36716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// [1] http://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt 37716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 38716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turnernamespace { 39716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 40716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// Helper class used to implement a gzip-based input stream. 41716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// Usage is as follows: 42716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// 43716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// GZipInputStream input(filePath); 44716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// if (input.error()) { 45716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// fprintf(stderr, "Could not open file: %s\n", 46716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// filePath, strerror(input.error())); 47716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// } else { 48716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// uint8_t header[32]; 49716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// if (!doRead(&input, header, sizeof header)) { 50716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// ... error, could not read header. 51716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// } 52716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// } 53716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// .. stream is closed automatically on scope exit. 54716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turnerclass GZipInputStream { 55716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turnerpublic: 56716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Open a new input stream to read from file |filePath|. 57716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // The constructor can never fail, so call error() after 58716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // this to see if an error occured. 59716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner explicit GZipInputStream(const char* filePath) { 60716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner mFile = gzopen(filePath, "rb"); 61716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (mFile == Z_NULL) { 62716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner mFile = NULL; 63716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner mError = errno; 64716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } else { 65716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner mError = 0; 66716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 67716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 68716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 69716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Return the last error that occured on this stream, 70716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // or 0 if everything's well. Note that as soon as an 71716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // error occurs, the stream cannot be used anymore. 72716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner int error() const { return mError; } 73716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 74716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Close the stream, note that this is called automatically 75716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // from the destructor, but clients might want to do this 76716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // before. 77716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner void close() { 78716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (mFile) { 79716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner gzclose(mFile); 80716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner mFile = NULL; 81716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 82716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 83716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 84716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner ~GZipInputStream() { 85716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner close(); 86716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 87716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 88716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Try to read up to |len| bytes of data from the input 89716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // stream into |buffer|. On success, return true and sets 90716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // |*readBytes| to the number of bytes that were read. 91716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // On failure, return false and set error(). 92716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner bool tryRead(void* buffer, size_t len, size_t* readBytes) { 93716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner *readBytes = 0; 94716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 95716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (mError) { 96716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 97716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 98716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 99716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (len == 0) { 100716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return true; 101716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 102716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 103716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Warning, gzread() takes an unsigned int parameter for 104716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // the length, but will return an error if its value 105716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // exceeds INT_MAX anyway. 106716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char* buff = reinterpret_cast<char*>(buffer); 107716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 108716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner while (len > 0) { 109716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner size_t avail = len; 110716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (avail > INT_MAX) 111716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner avail = INT_MAX; 112716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 113716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner int ret = gzread(mFile, buff, static_cast<unsigned int>(avail)); 114716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (ret < 0) { 115716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner gzerror(mFile, &mError); 116716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner break; 117716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 118716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (ret == 0) { 119716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (gzeof(mFile)) { 120716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner break; 121716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 122716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner gzerror(mFile, &mError); 123716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner break; 124716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 125716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner len -= ret; 126716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner buff += ret; 127716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner *readBytes += ret; 128716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 129716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 130716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return (!mError && *readBytes > 0); 131716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 132716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 133716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Read exactly |len| bytes of data into |buffer|. On success, 134716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // return true, on failure, return false and set error(). 135716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner bool doRead(void* buffer, size_t len) { 136716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner size_t readCount = 0; 137716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (!tryRead(buffer, len, &readCount)) { 138716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 139716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 140716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (readCount < len) { 141716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner mError = EIO; 142716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 143716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 144716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return true; 145716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 146716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 147716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner bool doSkip(size_t len) { 148716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (mError) { 149716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 150716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 151716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (gzseek(mFile, len, SEEK_CUR) < 0) { 152716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner gzerror(mFile, &mError); 153716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 154716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 155716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return true; 156716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 157716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 158716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turnerprivate: 159716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner DISALLOW_COPY_AND_ASSIGN(GZipInputStream); 160716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 161716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner gzFile mFile; 162716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner int mError; 163716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner}; 164716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 165716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// Parse an hexadecimal string of 8 characters. On success, 166716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// return true and sets |*value| to its value. On failure, 167716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner// return false. 168716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turnerbool parse_hex8(const char* input, uint32_t* value) { 169716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner uint32_t result = 0; 170716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner for (int n = 0; n < 8; ++n) { 171716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner int c = input[n]; 172716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner unsigned d = static_cast<unsigned>(c - '0'); 173716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (d >= 10) { 174716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner d = static_cast<unsigned>(c - 'a'); 175716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (d >= 6) { 176716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner d = static_cast<unsigned>(c - 'A'); 177716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (d >= 6) { 178716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 179716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 180716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 181716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner d += 10; 182716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 183716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner result = (result << 4) | d; 184716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 185716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner *value = result; 186716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return true; 187716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner} 188716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 189716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner} // namespace 190716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 191716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turnerbool android_extractRamdiskFile(const char* ramdiskPath, 192716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner const char* fileName, 193716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char** out, 194716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner size_t* outSize) { 195716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner *out = NULL; 196716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner *outSize = 0; 197716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 198716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner GZipInputStream input(ramdiskPath); 199716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (input.error()) { 200716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner errno = input.error(); 201716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 202716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 203716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 204716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Type of cpio new ASCII header. 205716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner struct cpio_newc_header { 206716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_magic[6]; 207716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_ino[8]; 208716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_mode[8]; 209716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_uid[8]; 210716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_gid[8]; 211716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_nlink[8]; 212716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_mtime[8]; 213716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_filesize[8]; 214716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_devmajor[8]; 215716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_devminor[8]; 216716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_rdevmajor[8]; 217716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_rdevminor[8]; 218716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_namesize[8]; 219716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner char c_check[8]; 220716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner }; 221716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 222716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner size_t fileNameLen = strlen(fileName); 223716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 224716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner for (;;) { 225716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Read the header then check it. 226716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner cpio_newc_header header; 227716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (!input.doRead(&header, sizeof header)) { 228716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Assume end of input here. 229716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("Could not find %s in ramdisk image at %s\n", 230716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner fileName, ramdiskPath); 231716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 232716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 233716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 234716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("HEADER %.6s\n", header.c_magic); 235716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (memcmp(header.c_magic, "070701", 6) != 0) { 236716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("Not a valid ramdisk image file: %s\n", ramdiskPath); 237716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner errno = EINVAL; 238716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 239716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 240716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 241716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Compare file names, note that files with a size of 0 are 242716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // hard links and should be ignored. 243716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner uint32_t nameSize; 244716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner uint32_t entrySize; 245716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (!parse_hex8(header.c_namesize, &nameSize) || 246716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner !parse_hex8(header.c_filesize, &entrySize)) { 247716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("Could not parse ramdisk file entry header!"); 248716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner break; 249716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 250716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 251716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("---- %d nameSize=%d entrySize=%d\n", __LINE__, nameSize, entrySize); 252716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 253716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // The header is followed by the name, followed by 4-byte padding 254716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // with NUL bytes. Compute the number of bytes to skip over the 255716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // name. 256716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner size_t skipName = 257716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner ((sizeof header + nameSize + 3) & ~3) - sizeof header; 258716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 259716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // The file data is 4-byte padded with NUL bytes too. 260716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner size_t skipFile = (entrySize + 3) & ~3; 261716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner size_t skipCount = 0; 262716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 263716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Last record is named 'TRAILER!!!' and indicates end of archive. 264716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner static const char kTrailer[] = "TRAILER!!!"; 265716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner static const size_t kTrailerSize = sizeof(kTrailer) - 1U; 266716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 267716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if ((entrySize == 0 || nameSize != fileNameLen + 1U) && 268716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner nameSize != kTrailerSize + 1U) { 269716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("---- %d Skipping\n", __LINE__); 270716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner skipCount = skipName + skipFile; 271716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } else { 272716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Read the name and compare it. 273716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner nameSize -= 1U; 274716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner android::base::String entryName; 275716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner entryName.resize(nameSize); 276716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (!input.doRead(&entryName[0], nameSize)) { 277716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("Could not read ramdisk file entry name!"); 278716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner break; 279716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 280716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("---- %d Name=[%s]\n", __LINE__, entryName.c_str()); 281716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner skipCount -= nameSize; 282716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 283716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Check for last entry. 284716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (nameSize == kTrailerSize && 285716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner !strcmp(entryName.c_str(), kTrailer)) { 286716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("End of archive reached. Could not find %s in ramdisk image at %s", 287716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner fileName, ramdiskPath); 288716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 289716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 290716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 291716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Check for the search file name. 292716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (nameSize == entryName.size() && 293716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner !strcmp(entryName.c_str(), fileName)) { 294716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Found it !! Skip over padding. 295716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (!input.doSkip(skipName - nameSize)) { 296716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("Could not skip ramdisk name entry!"); 297716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner break; 298716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 299716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 300716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner // Then read data into head-allocated buffer. 301716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner *out = reinterpret_cast<char*>(malloc(entrySize)); 302716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner *outSize = entrySize; 303716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 304716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return input.doRead(*out, entrySize); 305716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 306716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 307716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner if (!input.doSkip(skipCount)) { 308716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner D("Could not skip ramdisk entry!"); 309716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner break; 310716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 311716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner } 312716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner 313716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner errno = input.error(); 314716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner return false; 315716e5e10b4f8c30c4195411e868aa8745d24f59cDavid 'Digit' Turner} 316