ErrorCode MinizipUtils::add_file(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 = static_cast<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) {
        LOGE("minizip: Failed to open inner file: %s",
             zip_error_string(ret).c_str());

        return ErrorCode::ArchiveWriteDataError;
    }

    // Write data to file
    ret = zipWriteInFileInZip(zf, contents.data(),
                              static_cast<uint32_t>(contents.size()));
    if (ret != ZIP_OK) {
        LOGE("minizip: Failed to write inner file data: %s",
             zip_error_string(ret).c_str());
        zipCloseFileInZip(zf);

        return ErrorCode::ArchiveWriteDataError;
    }

    ret = zipCloseFileInZip(zf);
    if (ret != ZIP_OK) {
        LOGE("minizip: Failed to close inner file: %s",
             zip_error_string(ret).c_str());

        return ErrorCode::ArchiveWriteDataError;
    }

    return ErrorCode::NoError;
}
Beispiel #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();
}
bool OdinPatcher::Impl::processContents()
{
    archive_entry *entry;
    int laRet;
    int mzRet;

    zipFile zf = MinizipUtils::ctxGetZipFile(zOutput);

    while ((laRet = archive_read_next_header(aInput, &entry)) == ARCHIVE_OK) {
        if (cancelled) return false;

        const char *name = archive_entry_pathname(entry);
        if (!name) {
            continue;
        }

        updateDetails(name);

        if (strcmp(name, "boot.img") == 0) {
            LOGD("Handling boot.img");

            // Boot images should never be over about 30 MiB. This check is here
            // so the patcher won't try to read a multi-gigabyte system image
            // into RAM
            la_int64_t size = archive_entry_size(entry);
            if (size > 30 * 1024 * 1024) {
                LOGE("Boot image exceeds 30 MiB: %" PRId64, size);
                error = ErrorCode::BootImageTooLargeError;
                return false;
            }

            std::vector<unsigned char> data;
            if (size > 0) {
                data.reserve(size);
            }
            char buf[10240];
            la_ssize_t n;
            while ((n = archive_read_data(aInput, buf, sizeof(buf))) > 0) {
                data.insert(data.end(), buf, buf + n);
            }
            if (n != 0) {
                LOGE("libarchive: Failed to read data: %s",
                     archive_error_string(aInput));
                error = ErrorCode::ArchiveReadDataError;
                return false;
            }

            if (!MultiBootPatcher::patchBootImage(pc, info, &data, &error)) {
                return false;
            }

            auto errorRet = MinizipUtils::addFile(zf, name, data);
            if (errorRet != ErrorCode::NoError) {
                error = errorRet;
                return false;
            }

            continue;
        } else if (!StringUtils::starts_with(name, "cache.img")
                && !StringUtils::starts_with(name, "system.img")) {
            LOGD("Skipping %s", name);
            if (archive_read_data_skip(aInput) != ARCHIVE_OK) {
                LOGE("libarchive: Failed to skip data: %s",
                     archive_error_string(aInput));
                error = ErrorCode::ArchiveReadDataError;
                return false;
            }
            continue;
        }

        LOGD("Handling %s", name);

        std::string zipName(name);
        if (StringUtils::ends_with(name, ".ext4")) {
            zipName.erase(zipName.size() - 5);
        }
        zipName += ".sparse";

        // Ha! I'll be impressed if a Samsung firmware image does NOT need zip64
        int zip64 = archive_entry_size(entry) > ((1ll << 32) - 1);

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

        // Open file in output zip
        mzRet = zipOpenNewFileInZip2_64(
            zf,                    // file
            zipName.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 (mzRet != ZIP_OK) {
            LOGE("minizip: Failed to open new file in output zip: %s",
                 MinizipUtils::zipErrorString(mzRet).c_str());
            error = ErrorCode::ArchiveWriteHeaderError;
            return false;
        }

        la_ssize_t nRead;
        char buf[10240];
        while ((nRead = archive_read_data(aInput, buf, sizeof(buf))) > 0) {
            if (cancelled) return false;

            mzRet = zipWriteInFileInZip(zf, buf, nRead);
            if (mzRet != ZIP_OK) {
                LOGE("minizip: Failed to write %s in output zip: %s",
                     zipName.c_str(),
                     MinizipUtils::zipErrorString(mzRet).c_str());
                error = ErrorCode::ArchiveWriteDataError;
                zipCloseFileInZip(zf);
                return false;
            }
        }
        if (nRead != 0) {
            LOGE("libarchive: Failed to read %s: %s",
                 name, archive_error_string(aInput));
            error = ErrorCode::ArchiveReadDataError;
            zipCloseFileInZip(zf);
            return false;
        }

        // Close file in output zip
        mzRet = zipCloseFileInZip(zf);
        if (mzRet != ZIP_OK) {
            LOGE("minizip: Failed to close file in output zip: %s",
                 MinizipUtils::zipErrorString(mzRet).c_str());
            error = ErrorCode::ArchiveWriteDataError;
            return false;
        }
    }

    if (laRet != ARCHIVE_EOF) {
        LOGE("libarchive: Failed to read header: %s",
             archive_error_string(aInput));
        error = ErrorCode::ArchiveReadHeaderError;
        return false;
    }

    if (cancelled) return false;

    return true;
}
Beispiel #4
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();
}
Beispiel #5
0
bool FileUtils::mzCopyFileRaw(unzFile uf,
                              zipFile zf,
                              const std::string &name,
                              void (*cb)(uint64_t bytes, void *), void *userData)
{
    unz_file_info64 ufi;

    if (!mzGetInfo(uf, &ufi, nullptr)) {
        return false;
    }

    bool zip64 = ufi.uncompressed_size >= ((1ull << 32) - 1);

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

    zfi.dosDate = ufi.dosDate;
    zfi.tmz_date.tm_sec = ufi.tmu_date.tm_sec;
    zfi.tmz_date.tm_min = ufi.tmu_date.tm_min;
    zfi.tmz_date.tm_hour = ufi.tmu_date.tm_hour;
    zfi.tmz_date.tm_mday = ufi.tmu_date.tm_mday;
    zfi.tmz_date.tm_mon = ufi.tmu_date.tm_mon;
    zfi.tmz_date.tm_year = ufi.tmu_date.tm_year;
    zfi.internal_fa = ufi.internal_fa;
    zfi.external_fa = ufi.external_fa;

    int method;
    int level;

    // Open raw file in input zip
    int ret = unzOpenCurrentFile2(
        uf,                     // file
        &method,                // method
        &level,                 // level
        1                       // raw
    );
    if (ret != UNZ_OK) {
        return false;
    }

    // Open raw file in output zip
    ret = zipOpenNewFileInZip2_64(
        zf,             // file
        name.c_str(),   // filename
        &zfi,           // zip_fileinfo
        nullptr,        // extrafield_local
        0,              // size_extrafield_local
        nullptr,        // extrafield_global
        0,              // size_extrafield_global
        nullptr,        // comment
        method,         // method
        level,          // level
        1,              // raw
        zip64           // zip64
    );
    if (ret != ZIP_OK) {
        unzCloseCurrentFile(uf);
        return false;
    }

    uint64_t bytes = 0;

    // Exceeds Android's default stack size, unfortunately, so allocate
    // on the heap
    std::vector<unsigned char> buf(1024 * 1024); // 1MiB
    int bytes_read;
    double ratio;

    while ((bytes_read = unzReadCurrentFile(uf, buf.data(), buf.size())) > 0) {
        bytes += bytes_read;
        if (cb) {
            // Scale this to the uncompressed size for the purposes of a
            // progress bar
            ratio = (double) bytes / ufi.compressed_size;
            cb(ratio * ufi.uncompressed_size, userData);
        }

        ret = zipWriteInFileInZip(zf, buf.data(), bytes_read);
        if (ret != ZIP_OK) {
            unzCloseCurrentFile(uf);
            zipCloseFileInZip(zf);
            return false;
        }
    }

    unzCloseCurrentFile(uf);
    zipCloseFileInZipRaw64(zf, ufi.uncompressed_size, ufi.crc);

    return bytes_read == 0;
}
ErrorCode MinizipUtils::add_file(zipFile zf,
                                 const std::string &name,
                                 const std::string &path)
{
    // Copy file into archive
    StandardFile file;
    int ret;

    auto open_ret = FileUtils::open_file(file, path,
                                         FileOpenMode::ReadOnly);
    if (!open_ret) {
        LOGE("%s: Failed to open for reading: %s",
             path.c_str(), open_ret.error().message().c_str());
        return ErrorCode::FileOpenError;
    }

    auto size = file.seek(0, SEEK_END);
    if (!size) {
        LOGE("%s: Failed to seek file: %s",
             path.c_str(), size.error().message().c_str());
        return ErrorCode::FileSeekError;
    }
    auto seek_ret = file.seek(0, SEEK_SET);
    if (!seek_ret) {
        LOGE("%s: Failed to seek file: %s",
             path.c_str(), seek_ret.error().message().c_str());
        return ErrorCode::FileSeekError;
    }

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

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

    if (!get_file_time(path, &zi.dos_date)) {
        LOGE("%s: Failed to get modification time", path.c_str());
        return ErrorCode::FileOpenError;
    }

    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) {
        LOGE("minizip: Failed to open inner file: %s",
             zip_error_string(ret).c_str());

        return ErrorCode::ArchiveWriteDataError;
    }

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

    while (true) {
        auto bytes_read = file.read(buf, sizeof(buf));
        if (!bytes_read) {
            LOGE("%s: Failed to read data: %s",
                 path.c_str(), bytes_read.error().message().c_str());
            zipCloseFileInZip(zf);

            return ErrorCode::FileReadError;
        } else if (bytes_read.value() == 0) {
            break;
        }

        ret = zipWriteInFileInZip(
                zf, buf, static_cast<uint32_t>(bytes_read.value()));
        if (ret != ZIP_OK) {
            LOGE("minizip: Failed to write inner file data: %s",
                 zip_error_string(ret).c_str());
            zipCloseFileInZip(zf);

            return ErrorCode::ArchiveWriteDataError;
        }
    }

    ret = zipCloseFileInZip(zf);
    if (ret != ZIP_OK) {
        LOGE("minizip: Failed to close inner file: %s",
             zip_error_string(ret).c_str());

        return ErrorCode::ArchiveWriteDataError;
    }

    return ErrorCode::NoError;
}
bool MinizipUtils::copy_file_raw(unzFile uf,
                                 zipFile zf,
                                 const std::string &name,
                                 void (*cb)(uint64_t bytes, void *),
                                 void *userData)
{
    unz_file_info64 ufi;

    if (!get_info(uf, &ufi, nullptr)) {
        return false;
    }

    bool zip64 = ufi.uncompressed_size >= ((1ull << 32) - 1);

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

    zfi.dos_date = ufi.dos_date;
    zfi.internal_fa = ufi.internal_fa;
    zfi.external_fa = ufi.external_fa;

    int method;
    int level;

    // Open raw file in input zip
    int ret = unzOpenCurrentFile2(
        uf,                     // file
        &method,                // method
        &level,                 // level
        1                       // raw
    );
    if (ret != UNZ_OK) {
        LOGE("miniunz: Failed to open inner file: %s",
             unz_error_string(ret).c_str());
        return false;
    }

    // Open raw file in output zip
    ret = zipOpenNewFileInZip2_64(
        zf,                             // file
        name.c_str(),                   // filename
        &zfi,                           // zip_fileinfo
        nullptr,                        // extrafield_local
        0,                              // size_extrafield_local
        nullptr,                        // extrafield_global
        0,                              // size_extrafield_global
        nullptr,                        // comment
        static_cast<uint16_t>(method),  // method
        level,                          // level
        1,                              // raw
        zip64                           // zip64
    );
    if (ret != ZIP_OK) {
        LOGE("minizip: Failed to open inner file: %s",
             zip_error_string(ret).c_str());
        unzCloseCurrentFile(uf);
        return false;
    }

    uint64_t bytes = 0;

    // minizip no longer supports buffers larger than UINT16_MAX
    char buf[UINT16_MAX];
    int bytes_read;
    double ratio;

    while ((bytes_read = unzReadCurrentFile(uf, buf, sizeof(buf))) > 0) {
        bytes += static_cast<uint64_t>(bytes_read);
        if (cb) {
            // Scale this to the uncompressed size for the purposes of a
            // progress bar
            ratio = static_cast<double>(bytes)
                    / static_cast<double>(ufi.compressed_size);
            cb(static_cast<uint64_t>(
                    ratio * static_cast<double>(ufi.uncompressed_size)),
               userData);
        }

        ret = zipWriteInFileInZip(zf, buf, static_cast<uint32_t>(bytes_read));
        if (ret != ZIP_OK) {
            LOGE("minizip: Failed to write data to inner file: %s",
                 zip_error_string(ret).c_str());
            unzCloseCurrentFile(uf);
            zipCloseFileInZip(zf);
            return false;
        }
    }
    if (bytes_read != 0) {
        LOGE("miniunz: Finished before reaching inner file's EOF: %s",
             unz_error_string(bytes_read).c_str());
    }

    bool close_success = true;

    ret = unzCloseCurrentFile(uf);
    if (ret != UNZ_OK) {
        LOGE("miniunz: Failed to close inner file: %s",
             unz_error_string(ret).c_str());
        close_success = false;
    }
    ret = zipCloseFileInZipRaw64(zf, ufi.uncompressed_size, ufi.crc);
    if (ret != ZIP_OK) {
        LOGE("minizip: Failed to close inner file: %s",
             zip_error_string(ret).c_str());
        close_success = false;
    }

    return bytes_read == 0 && close_success;
}
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;
}