ErrorCode FsUtil::runDecryptZCat()

in aios/filesystem/fslib/tools/fsutil/FsUtil.cpp [527:663]


ErrorCode FsUtil::runDecryptZCat(const char *srcPath, const char *cipherOption, bool optionUseBase64) {
    autil::cipher::CipherOption option(autil::cipher::CipherType::CT_UNKNOWN);
    if (cipherOption == nullptr) {
        if (!getCipherOption(option)) {
            return EC_BADARGS;
        }
    } else {
        if (!option.fromKVString(cipherOption, optionUseBase64)) {
            return EC_BADARGS;
        }
    }

    FileMeta fileMeta;
    ErrorCode ret = FileSystem::getFileMeta(srcPath, fileMeta);
    if (ret != EC_OK) {
        cerr << "fail to get length of file <" << srcPath << ">. " << FileSystem::getErrorString(ret) << endl;
        return ret;
    }
    unique_ptr<File> rFile(FileSystem::openFile(srcPath, READ));
    if (!rFile->isOpened()) {
        cerr << "open file <" << srcPath << "> for read fail. " << FileSystem::getErrorString(rFile->getLastError())
             << endl;
        return rFile->getLastError();
    }
    volatile bool hasError = false;
    ErrorCode rCode = EC_OK;
    auto decrypter = autil::cipher::AESCipherCreator::createStreamDecrypter(option, 2 * 1024 * 1024 /* 2 MB */);
    if (decrypter == nullptr) {
        cerr << "create stream decrypter fail." << endl;
        return EC_UNKNOWN;
    }
    size_t totalDecryptLen = 0;
    std::thread readThread([&]() {
        size_t bufferLen = 2 * 1024 * 1024;
        SafeBuffer buffer(bufferLen);
        while (!hasError) {
            auto readLen = rFile->read(buffer.getBuffer(), bufferLen);
            if (readLen < 0) {
                cerr << "read file <" << srcPath << ">  fail. " << FileSystem::getErrorString(rFile->getLastError())
                     << endl;
                rCode = rFile->getLastError();
                hasError = true;
                continue;
            }
            if (readLen > 0) {
                if (!decrypter->append((const unsigned char *)buffer.getBuffer(), readLen)) {
                    cerr << "decrypter append data fail." << endl;
                    rCode = EC_UNKNOWN;
                    hasError = true;
                    continue;
                }
            }
            totalDecryptLen += readLen;
            if (rFile->isEof()) {
                break;
            }
        }
        if (!decrypter->seal()) {
            cerr << "decrypter seal fail." << endl;
            rCode = EC_UNKNOWN;
            hasError = true;
        }
    });

    ErrorCode wCode = EC_OK;
    std::thread writeThread([&]() {
        std::unique_ptr<AESCipherDataReader> reader(new AESCipherDataReader(decrypter, hasError));
        if (!GZipHeaderParser<AESCipherDataReader>::parse(reader)) {
            hasError = true;
            wCode = EC_UNKNOWN;
            return;
        }
        z_stream strm;
        strm.zalloc = Z_NULL;
        strm.zfree = Z_NULL;
        strm.opaque = Z_NULL;
        strm.avail_in = 0;
        strm.next_in = Z_NULL;
        if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
            cerr << "gzip infalte init error" << endl;
            hasError = true;
            wCode = EC_UNKNOWN;
            return;
        }
        size_t bufferLen = 2 * 1024 * 1024;
        SafeBuffer buffer(bufferLen + 1);
        SafeBuffer outBuffer(bufferLen);
        while (true) {
            auto readLen = reader->read(buffer.getBuffer(), bufferLen);
            if (readLen < 0) {
                cerr << "read decrypted file data fail. " << endl;
                inflateEnd(&strm);
                hasError = true;
                wCode = EC_UNKNOWN;
                return;
            }
            if (readLen > 0) {
                char *inBuf = buffer.getBuffer();
                char *outBuf = outBuffer.getBuffer();
                inBuf[readLen] = 0;
                uint32_t bufferNow = 0;
                uint32_t bufferEnd = readLen;
                while (bufferNow < bufferEnd) {
                    strm.avail_out = bufferLen;
                    strm.next_out = (Bytef *)outBuf;
                    strm.avail_in = bufferEnd - bufferNow;
                    strm.next_in = (Bytef *)&inBuf[bufferNow];
                    int ret = inflate(&strm, Z_NO_FLUSH);
                    if ((ret != Z_STREAM_END) && (ret != Z_OK)) {
                        cerr << "infalte error(" << ret << ")" << endl;
                        inflateEnd(&strm);
                        hasError = true;
                        wCode = EC_UNKNOWN;
                        return;
                    }
                    bufferNow = bufferEnd - strm.avail_in;
                    auto dSize = bufferLen - strm.avail_out;
                    fwrite(outBuf, sizeof(char), dSize, stdout);
                    if (ret == Z_STREAM_END) {
                        inflateEnd(&strm);
                        return;
                    }
                }
            }
            if (reader->isEof()) {
                break;
            }
        }
        inflateEnd(&strm);
    });
    readThread.join();
    writeThread.join();
    if (hasError) {
        return rCode != EC_OK ? rCode : wCode;
    }
    return EC_OK;
}