Пример #1
0
bool FileUtils::mzExtractFile(unzFile uf,
                              const std::string &directory)
{
    unz_file_info64 fi;
    std::string filename;

    if (!mzGetInfo(uf, &fi, &filename)) {
        return false;
    }

    std::string fullPath(directory);
    fullPath += "/";
    fullPath += filename;

    std::string parentPath = io::dirName(fullPath);
    if (!io::createDirectories(parentPath)) {
        FLOGW("%s: Failed to create directory: %s",
              parentPath.c_str(), io::lastErrorString().c_str());
    }

    io::File file;
    if (!file.open(fullPath, io::File::OpenWrite)) {
        FLOGE("%s: Failed to open for writing: %s",
              fullPath.c_str(), file.errorString().c_str());
        return false;
    }

    int ret = unzOpenCurrentFile(uf);
    if (ret != UNZ_OK) {
        FLOGE("miniunz: Failed to open inner file: %s",
              mzUnzErrorString(ret).c_str());
        return false;
    }

    int n;
    char buf[32768];
    uint64_t bytesWritten;

    while ((n = unzReadCurrentFile(uf, buf, sizeof(buf))) > 0) {
        if (!file.write(buf, n, &bytesWritten)) {
            FLOGE("%s: Failed to write file: %s",
                  fullPath.c_str(), file.errorString().c_str());
            unzCloseCurrentFile(uf);
            return false;
        }
    }
    if (n != 0) {
        FLOGE("miniunz: Finished before reaching inner file's EOF: %s",
              mzUnzErrorString(n).c_str());
    }

    ret = unzCloseCurrentFile(uf);
    if (ret != UNZ_OK) {
        FLOGE("miniunz: Failed to close inner file: %s",
              mzUnzErrorString(ret).c_str());
        return false;
    }

    return n == 0;
}
Пример #2
0
PatcherError FileUtils::mzAddFile(zipFile zf,
                                  const std::string &name,
                                  const std::vector<unsigned char> &contents)
{
    // Obviously never true, but we'll keep it here just in case
    bool zip64 = (uint64_t) contents.size() >= ((1ull << 32) - 1);

    zip_fileinfo zi;
    memset(&zi, 0, sizeof(zi));

    int ret = zipOpenNewFileInZip2_64(
        zf,                     // file
        name.c_str(),           // filename
        &zi,                    // zip_fileinfo
        nullptr,                // extrafield_local
        0,                      // size_extrafield_local
        nullptr,                // extrafield_global
        0,                      // size_extrafield_global
        nullptr,                // comment
        Z_DEFLATED,             // method
        Z_DEFAULT_COMPRESSION,  // level
        0,                      // raw
        zip64                   // zip64
    );

    if (ret != ZIP_OK) {
        FLOGW("minizip: Failed to add file (error code: {}): [memory]", ret);

        return PatcherError::createArchiveError(
                ErrorCode::ArchiveWriteDataError, name);
    }

    // Write data to file
    ret = zipWriteInFileInZip(zf, contents.data(), contents.size());
    if (ret != ZIP_OK) {
        FLOGW("minizip: Failed to write data (error code: {}): [memory]", ret);
        zipCloseFileInZip(zf);

        return PatcherError::createArchiveError(
                ErrorCode::ArchiveWriteDataError, name);
    }

    zipCloseFileInZip(zf);

    return PatcherError();
}
Пример #3
0
PatchFilePatcher::PatchFilePatcher(const PatcherConfig * const pc,
                                   const FileInfo * const info,
                                   const PatchInfo::AutoPatcherArgs &args)
    : m_impl(new Impl())
{
    m_impl->pc = pc;
    m_impl->info = info;
    m_impl->args = args;

    // The arguments should have the patch to the file
    if (args.find(ArgFile) == args.end()) {
        LOGW("Arguments does not contain the path to a patch file");
        return;
    }

    m_impl->patchFile = pc->dataDirectory() + "/patches/" + args.at(ArgFile);

    std::string contents;
    auto ret = FileUtils::readToString(m_impl->patchFile, &contents);
    if (!ret) {
        LOGW("Failed to read patch file");
        return;
    }

    std::vector<std::string> lines;
    boost::split(lines, contents, boost::is_any_of("\n"));

    const std::regex reOrigFile("---\\s+(.+?)(?:$|\t)");

    for (auto it = lines.begin(); it != lines.end(); ++it) {
        std::smatch what;

        if (std::regex_search(*it, what, reOrigFile)) {
            std::string file = what.str(1);
            if (boost::starts_with(file, "\"") && boost::ends_with(file, "\"")) {
                file.erase(file.begin());
                file.erase(file.end() - 1);
            }

            // Skip files containing escaped characters
            if (file.find("\\") != std::string::npos) {
                FLOGW("Skipping file with escaped characters in filename: {}", file);
                continue;
            }

            // Strip leading slash (-p1)
            auto it = file.find("/");
            if (it != std::string::npos) {
                file.erase(file.begin(), file.begin() + it + 1);
            }

            FLOGD("Found file in patch: {}", file);

            m_impl->files.push_back(file);
        }
    }
}
Пример #4
0
void MultiBootPatcher::Impl::closeOutputArchive()
{
    assert(zOutput != nullptr);

    int ret = FileUtils::mzCloseOutputFile(zOutput);
    if (ret != ZIP_OK) {
        FLOGW("minizip: Failed to close archive (error code: {})", ret);
    }

    zOutput = nullptr;
}
Пример #5
0
/*!
 * \brief First pass of patching operation
 *
 * This performs the following operations:
 *
 * - If the PatchInfo has the `hasBootImage` parameter set to true for the
 *   current file, then patch the boot images and copy them to the output file.
 * - Files needed by an AutoPatcher are extracted to the temporary directory.
 * - Otherwise, the file is copied directly to the output zip.
 */
bool MultiBootPatcher::Impl::pass1(zipFile const zOutput,
                                   const std::string &temporaryDir,
                                   const std::unordered_set<std::string> &exclude)
{
    // Boot image params
    bool hasBootImage = info->patchInfo()->hasBootImage();
    auto piBootImages = info->patchInfo()->bootImages();

    int ret = unzGoToFirstFile(zInput);
    if (ret != UNZ_OK) {
        error = PatcherError::createArchiveError(
                ErrorCode::ArchiveReadHeaderError, std::string());
        return false;
    }

    do {
        if (cancelled) return false;

        unz_file_info64 fi;
        std::string curFile;

        if (!FileUtils::mzGetInfo(zInput, &fi, &curFile)) {
            error = PatcherError::createArchiveError(
                    ErrorCode::ArchiveReadHeaderError, curFile);
            return false;
        }

        updateFiles(++files, maxFiles);
        updateDetails(curFile);

        // Skip files that should be patched and added in pass 2
        if (exclude.find(curFile) != exclude.end()) {
            if (!FileUtils::mzExtractFile(zInput, temporaryDir)) {
                error = PatcherError::createArchiveError(
                        ErrorCode::ArchiveReadDataError, curFile);
                return false;
            }
            continue;
        }

        // Try to patch the patchinfo-defined boot images as well as
        // files that end in a common boot image extension

        bool inList = std::find(piBootImages.begin(), piBootImages.end(),
                                curFile) != piBootImages.end();
        bool isExtImg = boost::ends_with(curFile, ".img");
        bool isExtLok = boost::ends_with(curFile, ".lok");
        // Boot images should be over about 30 MiB. This check is here so the
        // patcher won't try to read a multi-gigabyte system image into RAM
        bool isSizeOK = fi.uncompressed_size <= 30 * 1024 * 1024;

        if (hasBootImage && (inList || isExtImg || isExtLok) && isSizeOK) {
            // Load the file into memory
            std::vector<unsigned char> data;

            if (!FileUtils::mzReadToMemory(zInput, &data,
                                           &laProgressCb, this)) {
                error = PatcherError::createArchiveError(
                        ErrorCode::ArchiveReadDataError, curFile);
                return false;
            }

            // If the file contains the boot image magic string, then
            // assume it really is a boot image and patch it
            if (data.size() >= 512) {
                const char *magic = BootImage::BootMagic;
                unsigned int size = BootImage::BootMagicSize;
                auto end = data.begin() + 512;
                auto it = std::search(data.begin(), end,
                                      magic, magic + size);
                if (it != end) {
                    if (!patchBootImage(&data)) {
                        return false;
                    }

                    // Update total size
                    maxBytes += (data.size() - fi.uncompressed_size);
                }
            }

            auto ret2 = FileUtils::mzAddFile(zOutput, curFile, data);
            if (!ret2) {
                error = ret2;
                return false;
            }

            bytes += data.size();
        } else {
            // Directly copy other files to the output zip

            // Rename the installer for mbtool
            if (curFile == "META-INF/com/google/android/update-binary") {
                curFile = "META-INF/com/google/android/update-binary.orig";
            }

            if (!FileUtils::mzCopyFileRaw(zInput, zOutput, curFile,
                                          &laProgressCb, this)) {
                FLOGW("minizip: Failed to copy raw data: {}", curFile);
                error = PatcherError::createArchiveError(
                        ErrorCode::ArchiveWriteDataError, curFile);
                return false;
            }

            bytes += fi.uncompressed_size;
        }
    } while ((ret = unzGoToNextFile(zInput)) == UNZ_OK);

    if (ret != UNZ_END_OF_LIST_OF_FILE) {
        error = PatcherError::createArchiveError(
                ErrorCode::ArchiveReadHeaderError, std::string());
        return false;
    }

    if (cancelled) return false;

    return true;
}
Пример #6
0
PatcherError FileUtils::mzAddFile(zipFile zf,
                                  const std::string &name,
                                  const std::string &path)
{
    // Copy file into archive
    std::ifstream file(path, std::ios::binary);
    if (file.fail()) {
        return PatcherError::createIOError(
                ErrorCode::FileOpenError, path);
    }

    file.seekg(0, std::ios::end);
    auto size = file.tellg();
    file.seekg(0, std::ios::beg);

    bool zip64 = (uint64_t) size >= ((1ull << 32) - 1);

    zip_fileinfo zi;
    memset(&zi, 0, sizeof(zi));

    mzGetFileTime(path, &zi.tmz_date, &zi.dosDate);

    int ret = zipOpenNewFileInZip2_64(
        zf,                     // file
        name.c_str(),           // filename
        &zi,                    // zip_fileinfo
        nullptr,                // extrafield_local
        0,                      // size_extrafield_local
        nullptr,                // extrafield_global
        0,                      // size_extrafield_global
        nullptr,                // comment
        Z_DEFLATED,             // method
        Z_DEFAULT_COMPRESSION,  // level
        0,                      // raw
        zip64                   // zip64
    );

    if (ret != ZIP_OK) {
        FLOGW("minizip: Failed to add file (error code: {}): {}", ret, path);

        return PatcherError::createArchiveError(
                ErrorCode::ArchiveWriteDataError, name);
    }

    // Write data to file
    char buf[32768];
    std::streamsize n;

    while (!file.eof()) {
        file.read(buf, 32768);
        n = file.gcount();

        ret = zipWriteInFileInZip(zf, buf, n);
        if (ret != ZIP_OK) {
            FLOGW("minizip: Failed to write data (error code: {}): {}",
                  ret, path);
            zipCloseFileInZip(zf);

            return PatcherError::createArchiveError(
                    ErrorCode::ArchiveWriteDataError, name);
        }
    }

    if (file.bad()) {
        zipCloseFileInZip(zf);

        return PatcherError::createIOError(
                ErrorCode::FileReadError, path);
    }

    zipCloseFileInZip(zf);

    return PatcherError();
}
Пример #7
0
ErrorCode FileUtils::mzAddFile(zipFile zf,
                               const std::string &name,
                               const std::string &path)
{
    // Copy file into archive
    io::File file;
    if (!file.open(path, io::File::OpenRead)) {
        FLOGE("%s: Failed to open for reading: %s",
              path.c_str(), file.errorString().c_str());
        return ErrorCode::FileOpenError;
    }

    uint64_t size;
    file.seek(0, io::File::SeekEnd);
    file.tell(&size);
    file.seek(0, io::File::SeekBegin);

    bool zip64 = size >= ((1ull << 32) - 1);

    zip_fileinfo zi;
    memset(&zi, 0, sizeof(zi));

    mzGetFileTime(path, &zi.tmz_date, &zi.dosDate);

    int ret = zipOpenNewFileInZip2_64(
                  zf,                     // file
                  name.c_str(),           // filename
                  &zi,                    // zip_fileinfo
                  nullptr,                // extrafield_local
                  0,                      // size_extrafield_local
                  nullptr,                // extrafield_global
                  0,                      // size_extrafield_global
                  nullptr,                // comment
                  Z_DEFLATED,             // method
                  Z_DEFAULT_COMPRESSION,  // level
                  0,                      // raw
                  zip64                   // zip64
              );

    if (ret != ZIP_OK) {
        FLOGW("minizip: Failed to add file (error code: %d): %s",
              ret, path.c_str());

        return ErrorCode::ArchiveWriteDataError;
    }

    // Write data to file
    char buf[32768];
    uint64_t bytesRead;

    while (file.read(buf, sizeof(buf), &bytesRead)) {
        ret = zipWriteInFileInZip(zf, buf, bytesRead);
        if (ret != ZIP_OK) {
            FLOGW("minizip: Failed to write data (error code: %d): %s",
                  ret, path.c_str());
            zipCloseFileInZip(zf);

            return ErrorCode::ArchiveWriteDataError;
        }
    }
    if (file.error() != io::File::ErrorEndOfFile) {
        zipCloseFileInZip(zf);

        FLOGE("%s: Failed to read file: %s",
              path.c_str(), file.errorString().c_str());
        return ErrorCode::FileReadError;
    }

    zipCloseFileInZip(zf);

    return ErrorCode::NoError;
}