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