ErrorCode FsUtil::runDecrypt()

in aios/filesystem/fslib/tools/fsutil/FsUtil.cpp [341:482]


ErrorCode FsUtil::runDecrypt(const char *srcPath, const char *dstPath, 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;
        }
    }

    auto beginTs = autil::TimeUtility::currentTime();
    cout << "-------------------------------------------------" << endl;
    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();
    }

    if (std::string(dstPath) != "/dev/null" && FileSystem::isExist(dstPath) == EC_TRUE) {
        cerr << "target path <" << dstPath << "> already exist. " << endl;
        return EC_BADARGS;
    }
    unique_ptr<File> wFile(FileSystem::openFile(dstPath, WRITE));
    if (!wFile->isOpened()) {
        cerr << "open file <" << dstPath << "> for write fail. " << FileSystem::getErrorString(wFile->getLastError())
             << endl;
        return wFile->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;
    }

    Md5StreamPtr rFileMd5;
    Md5StreamPtr wFileMd5;
    if (autil::EnvUtil::getEnv("PRINT_MD5", false)) {
        rFileMd5.reset(new Md5Stream);
        wFileMd5.reset(new Md5Stream);
    }

    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 (rFileMd5) {
                    rFileMd5->Put((const uint8_t *)buffer.getBuffer(), readLen);
                }
                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;
        }
        rFile->close();
    });

    ErrorCode wCode = EC_OK;
    size_t totalWriteLen = 0;
    std::thread writeThread([&]() {
        size_t bufferLen = 2 * 1024 * 1024;
        SafeBuffer buffer(bufferLen);
        while (!hasError) {
            auto ret = decrypter->get((unsigned char *)buffer.getBuffer(), bufferLen);
            if (ret > 0) {
                if (wFileMd5) {
                    wFileMd5->Put((const uint8_t *)buffer.getBuffer(), ret);
                }
                if (wFile->write(buffer.getBuffer(), ret) != ret) {
                    cerr << "write to dst file <" << dstPath << "> fail.  "
                         << FileSystem::getErrorString(wFile->getLastError()) << endl;
                    wCode = wFile->getLastError();
                    hasError = true;
                }
                totalWriteLen += ret;
                continue;
            }
            if (decrypter->isEof()) {
                break;
            }
        }
        wCode = wFile->close();
        if (wCode != EC_OK) {
            cerr << "close dst file <" << dstPath << "> fail.  " << FileSystem::getErrorString(wFile->getLastError())
                 << endl;
            hasError = true;
        }
    });

    readThread.join();
    writeThread.join();
    if (hasError) {
        return rCode != EC_OK ? rCode : wCode;
    }

    auto interval = autil::TimeUtility::currentTime() - beginTs;
    cout << "decryption interval:" << (double)interval / 1000000 << " seconds" << endl;
    cout << "cipher file length:" << totalDecryptLen << ", plain file length:" << totalWriteLen << endl;
    cout << "=================================================" << endl;
    cout << "== key hex:" << decrypter->getKeyHexString() << endl;
    cout << "== iv hex:" << decrypter->getIvHexString() << endl;
    cout << "== salt hex:" << decrypter->getSaltHexString() << endl;
    if (rFileMd5 && wFileMd5) {
        cout << "++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
        cout << "++ src file md5:" << rFileMd5->GetMd5String() << endl;
        cout << "++ dst file md5:" << wFileMd5->GetMd5String() << endl;
    }
    return EC_OK;
}