77a7a157创建于 1月30日历史提交
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2026 Huawei Device Co., Ltd.
 */

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <cstring>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include "dec_test.h"
#include "token_setproc.h"

#define LOG(msg) std::cout << "[dectool][" << __FILE__ << ":" << __LINE__ << "] " << msg << std::endl
#define LOG_ERROR(msg) std::cerr << "[dectool][ERROR][" << __FILE__ << ":" << __LINE__ << "] " << msg << std::endl

struct Command {
    std::string cmd;
    std::string tokenid;
    std::string path;
    std::string dstpath;
    std::string mode;
    std::string userid;
    std::string persist;
    std::string timestamp;
    bool expect;
    bool has_expect;
};

uint64_t stringToUint64(const std::string& str)
{
    try {
        return std::stoull(str, nullptr, 10);
    } catch (const std::exception& e) {
        LOG_ERROR("Failed to convert string to uint64_t: " << str << ", error: " << e.what());
        return 0;
    }
}

int32_t stringToInt32(const std::string& str)
{
    try {
        return std::stoi(str, nullptr, 10);
    } catch (const std::exception& e) {
        LOG_ERROR("Failed to convert string to int32_t: " << str << ", error: " << e.what());
        return 0;
    }
}

uint32_t stringToUint32(const std::string& str)
{
    try {
        return std::stoul(str, nullptr, 0);
    } catch (const std::exception& e) {
        LOG_ERROR("Failed to convert string to uint32_t: " << str << ", error: " << e.what());
        return 0;
    }
}

Command parseCommand(int argc, char* argv[])
{
    Command cmd;
    cmd.expect = false;
    cmd.has_expect = false;

    for (int i = 1; i < argc; i++) {
        std::string arg = argv[i];

        if (arg == "--cmd") {
            cmd.cmd = argv[++i];
        } else if (arg == "--tokenid") {
            cmd.tokenid = argv[++i];
        } else if (arg == "--path") {
            cmd.path = argv[++i];
        } else if (arg == "--dstpath") {
            cmd.dstpath = argv[++i];
        } else if (arg == "--mode") {
            cmd.mode = argv[++i];
        } else if (arg == "--user_id") {
            cmd.userid = argv[++i];
        } else if (arg == "--persist") {
            cmd.persist = argv[++i];
        } else if (arg == "--timestamp") {
            cmd.timestamp = argv[++i];
        } else if (arg == "--expect") {
            cmd.has_expect = true;
            std::string expect = argv[++i];
            cmd.expect = (expect == "true");
        }
    }

    return cmd;
}

int handleRead(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    std::ifstream file(cmd.path.c_str(), std::ios::binary);
    if (!file.is_open()) {
        LOG_ERROR("Failed to open file for reading: " << cmd.path << ", errno: " << errno << " - " << strerror(errno));
        return -1;
    }

    std::string content((std::istreambuf_iterator<char>(file)),
                        std::istreambuf_iterator<char>());
    file.close();

    LOG("Successfully read file: " << cmd.path);
    return 0;
}

int handleWrite(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    std::ofstream file(cmd.path.c_str(), std::ios::binary | std::ios::app);
    if (!file.is_open()) {
        LOG_ERROR("Failed to open file for writing: " << cmd.path << ", errno: " << errno << " - " << strerror(errno));
        return -1;
    }

    file << "Test data written by dectool\n";
    file.close();

    LOG("Successfully wrote to file: " << cmd.path);
    return 0;
}

int handleCreate(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    std::ofstream file(cmd.path.c_str());
    if (!file.is_open()) {
        LOG_ERROR("Failed to create file: " << cmd.path << ", errno: " << errno << " - " << strerror(errno));
        return -1;
    }

    file.close();
    LOG("Successfully created file: " << cmd.path);
    return 0;
}

int handleReaddir(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    DIR* dir = opendir(cmd.path.c_str());
    if (!dir) {
        LOG_ERROR("Failed to open directory: " << cmd.path << ", errno: " << errno << " - " << strerror(errno));
        return -1;
    }

    struct dirent* entry;
    int count = 0;
    while ((entry = readdir(dir)) != nullptr) {
        count++;
    }

    closedir(dir);
    LOG("Successfully read directory: " << cmd.path << ", found " << count << " entries");
    return 0;
}

int handleMkdir(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    std::string path = cmd.path;
    if(path.empty()) {
        printf("path is empty\n");
        return -1;
    }

    const char lastChar = path.back();
    if(lastChar != '\\' && lastChar != '/') {
        path.append("/");
    }
    printf("start mkdir %s\n", path.c_str());
    int len = path.length();
    char tmpDirPath[256] = { 0 };
    for (int i = 0; i < len; i++) {
        tmpDirPath[i] = path[i];
        if (tmpDirPath[i] == '\\' || tmpDirPath[i] == '/') {
            printf("tmpDirPath:%s\n", tmpDirPath);
            if (access(tmpDirPath, 0) == -1) {
                printf("tmpDirPath:%s not exist\n", tmpDirPath);
                int ret = mkdir(tmpDirPath, S_IRWXU);
                if (ret == -1) {
                    printf("mkdir failed %s\n", strerror(errno));
                    return -1;
                }
            } else {
                printf("tmpDirPath:%s exists\n", tmpDirPath);
            }
        }
    }
    printf("mkdir success path:%s\n", path.c_str());
    return 0;
}

int handleRemove(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    if (std::remove(cmd.path.c_str()) == 0) {
        LOG("Successfully removed file: " << cmd.path);
        return 0;
    }

    LOG_ERROR("Failed to remove file: " << cmd.path << ", errno: " << errno << " - " << strerror(errno));
    return -1;
}

std::string GetFileDir(const std::string &fileName)
{
    size_t lastSlashPos = fileName.find_last_of("/\\");

    if (lastSlashPos == std::string::npos) {
        printf("cant find file:%s\n", fileName.c_str());
        return "";
    }

    std::string fileDir = fileName.substr(0, lastSlashPos);
    return fileDir;
}


int handleCopy(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    std::string srcPath = cmd.path;
    std::string dstPath = cmd.dstpath;
    printf("copy %s to %s \n", srcPath.c_str(), dstPath.c_str());
    std::ifstream in(srcPath, std::ios::binary);
    std::ofstream out(dstPath, std::ios::binary);

    if (!in) {
        std::cerr << "open fail" << std::endl;
        return 1;
    }

    if (!out) {
        std::cerr << "open fail" << std::endl;
        return 1;
    }

    out << in.rdbuf();

    in.close();
    out.close();

    std::cout << "copy success" << std::endl;

    return 0;
}

int handleRename(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    std::string fileName = cmd.path;
    std::__fs::filesystem::path filePath = cmd.path;
    std::string newName = GetFileDir(cmd.path);
    newName.append("/new");
    newName.append(filePath.filename());
    printf("fileName:%s newName:%s\n", fileName.c_str(), newName.c_str());
    int ret = rename(fileName.c_str(), newName.c_str());
    if (ret != 0) {
        printf("rename failed err:%s\n", strerror(errno));
        return -1;
    }

    ret = rename(newName.c_str(), fileName.c_str());
    if (ret != 0) {
        printf("rename back failed err:%s\n", strerror(errno));
        return -1;
    }
    return 0;

    LOG_ERROR("Failed to rename " << cmd.path << " to " << cmd.dstpath << ", errno: " << errno << " - " << strerror(errno));
    return -1;
}

int handleRename2(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    if (std::rename(cmd.path.c_str(), cmd.dstpath.c_str()) == 0) {
        LOG("Successfully renamed " << cmd.path << " to " << cmd.dstpath);
        return 0;
    }

    LOG_ERROR("Failed to rename " << cmd.path << " to " << cmd.dstpath << ", errno: " << errno << " - " << strerror(errno));
    return -1;
}

int handleAccess(const Command& cmd)
{
    SetSelfTokenID(stringToUint64(cmd.tokenid));
    int mode = 0;
    if (!cmd.mode.empty()) {
        try {
            mode = std::stoi(cmd.mode);
        } catch (const std::exception& e) {
            LOG_ERROR("Invalid mode value: " << cmd.mode << ", error: " << e.what());
            return -1;
        }
    }

    int checkMode = 0;
    switch (mode) {
        case 0: checkMode = F_OK; break;
        case 1: checkMode = R_OK; break;
        case 2: checkMode = W_OK; break;
        case 3: checkMode = R_OK | W_OK; break;
        default:
            LOG_ERROR("Invalid mode specified: " << mode);
            return -1;
    }

    if (access(cmd.path.c_str(), checkMode) == 0) {
        LOG("Access check passed for " << cmd.path << " with mode " << mode);
        return 0;
    }

    LOG_ERROR("Access check failed for " << cmd.path << " with mode " << mode << ", errno: " << errno << " - " << strerror(errno));
    return -1;
}

int handleSet(const Command& cmd)
{
    if (cmd.tokenid.empty()) {
        LOG_ERROR("tokenid is required for set command");
        return -1;
    }

    if (cmd.path.empty()) {
        LOG_ERROR("path is required for set command");
        return -1;
    }

    if (cmd.mode.empty()) {
        LOG_ERROR("mode is required for set command");
        return -1;
    }

    uint64_t tokenid = stringToUint64(cmd.tokenid);

    uint32_t mode = stringToUint32(cmd.mode);

    bool persistFlag = false;
    if (!cmd.persist.empty()) {
        persistFlag = (cmd.persist == "true");
    }

    uint64_t timestamp = 0;
    if (!cmd.timestamp.empty()) {
        timestamp = stringToUint64(cmd.timestamp);
    }

    int32_t userId = 0;
    if (!cmd.userid.empty()) {
        userId = stringToInt32(cmd.userid);
    }

    LOG("Calling SetPath: tokenid=" << tokenid << ", path=" << cmd.path 
        << ", mode=" << mode << ", persistFlag=" << persistFlag 
        << ", timestamp=" << timestamp << ", userId=" << userId);

    int result = SetPath(tokenid, cmd.path, mode, persistFlag, timestamp, userId);
    LOG("SetPath returned: " << result);

    return result;
}

int handleConstraint(const Command& cmd)
{
    if (cmd.path.empty()) {
        LOG_ERROR("path is required for constraint command");
        return -1;
    }

    LOG("Calling ConstraintPath: path=" << cmd.path);
    int result = ConstraintPath(cmd.path);
    LOG("ConstraintPath returned: " << result);

    return result;
}

int handleCheck(const Command& cmd)
{
    if (cmd.tokenid.empty()) {
        LOG_ERROR("tokenid is required for check command");
        return -1;
    }

    if (cmd.path.empty()) {
        LOG_ERROR("path is required for check command");
        return -1;
    }

    uint64_t tokenid = stringToUint64(cmd.tokenid);

    uint32_t mode = 0;
    if (!cmd.mode.empty()) {
        mode = stringToUint32(cmd.mode);
    } else {
        LOG_ERROR("mode is required for check command");
        return -1;
    }

    LOG("Calling CheckPath: tokenid=" << tokenid << ", path=" << cmd.path << ", mode=" << mode);
    int result = CheckPath(tokenid, cmd.path, mode);
    LOG("CheckPath returned: " << result);

    return result;
}

int handleQuery(const Command& cmd)
{
    if (cmd.tokenid.empty()) {
        LOG_ERROR("tokenid is required for query command");
        return -1;
    }

    if (cmd.path.empty()) {
        LOG_ERROR("path is required for query command");
        return -1;
    }

    uint64_t tokenid = stringToUint64(cmd.tokenid);

    uint32_t mode = 0;
    if (!cmd.mode.empty()) {
        mode = stringToUint32(cmd.mode);
    } else {
        LOG_ERROR("mode is required for query command");
        return -1;
    }

    LOG("Calling QueryPath: tokenid=" << tokenid << ", path=" << cmd.path << ", mode=" << mode);
    int result = QueryPath(tokenid, cmd.path, mode);
    LOG("QueryPath returned: " << result);

    return result;
}

int handleDelete(const Command& cmd)
{
    if (cmd.tokenid.empty()) {
        LOG_ERROR("tokenid is required for delete command");
        return -1;
    }

    if (cmd.path.empty()) {
        LOG_ERROR("path is required for delete command");
        return -1;
    }

    uint64_t tokenid = stringToUint64(cmd.tokenid);

    uint64_t timestamp = 0;
    if (!cmd.timestamp.empty()) {
        timestamp = stringToUint64(cmd.timestamp);
    }

    LOG("Calling DeletePath: tokenid=" << tokenid << ", path=" << cmd.path << ", timestamp=" << timestamp);
    int result = DeletePath(tokenid, cmd.path, timestamp);
    LOG("DeletePath returned: " << result);

    return result;
}

int handleDeleteByUser(const Command& cmd)
{
    if (cmd.userid.empty()) {
        LOG_ERROR("userid is required for delete_by_user command");
        return -1;
    }

    if (cmd.path.empty()) {
        LOG_ERROR("path is required for delete_by_user command");
        return -1;
    }

    int32_t userId = stringToInt32(cmd.userid);

    LOG("Calling DeletePathByUser: user_id=" << userId << ", path=" << cmd.path);
    int result = DeletePathByUser(userId, cmd.path);
    LOG("DeletePathByUser returned: " << result);

    return result;
}

int handleDestroy(const Command& cmd)
{
    if (cmd.tokenid.empty()) {
        LOG_ERROR("tokenid is required for destroy command");
        return -1;
    }

    uint64_t tokenid = stringToUint64(cmd.tokenid);

    uint64_t timestamp = 0;
    if (!cmd.timestamp.empty()) {
        timestamp = stringToUint64(cmd.timestamp);
    }

    LOG("Calling DestroyByTokenid: tokenid=" << tokenid << ", timestamp=" << timestamp);
    int result = DestroyByTokenid(tokenid, timestamp);
    LOG("DestroyByTokenid returned: " << result);

    return result;
}

int handleForcedPrefix(const Command& cmd)
{
    if (cmd.path.empty()) {
        LOG_ERROR("path is required for forced_prefix command");
        return -1;
    }

    LOG("Calling SetPrefix: path=" << cmd.path);
    int result = SetPrefix(cmd.path);
    LOG("SetPrefix returned: " << result);

    return result;
}

int main(int argc, char* argv[])
{
    LOG("Starting dectool with " << argc << " arguments");

    if (argc < 2) {
        LOG_ERROR("Usage: " << argv[0] << " --cmd <command> [options]");
        return -1;
    }

    Command cmd = parseCommand(argc, argv);
    LOG("Parsed command: cmd=" << cmd.cmd << ", path=" << cmd.path << ", has_expect=" << cmd.has_expect << ", expect=" << cmd.expect);

    int result = -1;

    LOG("tokenid=" << cmd.tokenid);

    uint64_t tokenid = stringToUint64(cmd.tokenid);

    OpenDevDec();

    if (cmd.cmd == "read") {
        result = handleRead(cmd);
    } else if (cmd.cmd == "write") {
        result = handleWrite(cmd);
    } else if (cmd.cmd == "create") {
        result = handleCreate(cmd);
    } else if (cmd.cmd == "readdir") {
        result = handleReaddir(cmd);
    } else if (cmd.cmd == "mkdir") {
        result = handleMkdir(cmd);
    } else if (cmd.cmd == "remove") {
        result = handleRemove(cmd);
    } else if (cmd.cmd == "rename") {
        result = handleRename(cmd);
    } else if (cmd.cmd == "rename2") {
        if (cmd.dstpath.empty()) {
            LOG_ERROR("dstpath is required for rename command");
            return -1;
        }
        result = handleRename2(cmd);
    } else if (cmd.cmd == "copy") {
        result = handleCopy(cmd);
    }  else if (cmd.cmd == "access") {
        result = handleAccess(cmd);
    } else if (cmd.cmd == "set") {
        result = handleSet(cmd);
    } else if (cmd.cmd == "constraint") {
        result = handleConstraint(cmd);
    } else if (cmd.cmd == "check") {
        result = handleCheck(cmd);
    } else if (cmd.cmd == "query") {
        result = handleQuery(cmd);
    } else if (cmd.cmd == "delete") {
        result = handleDelete(cmd);
    } else if (cmd.cmd == "delete_by_user") {
        result = handleDeleteByUser(cmd);
    } else if (cmd.cmd == "destroy") {
        result = handleDestroy(cmd);
    } else if (cmd.cmd == "forced_prefix") {
        result = handleForcedPrefix(cmd);
    } else {
        LOG_ERROR("Unknown command: " << cmd.cmd);
        return -1;
    }

    LOG("Command '" << cmd.cmd << "' executed with result: " << result);

    if (!cmd.has_expect) {
        LOG("No expect parameter specified, returning 0");
        return 0;
    } else {
        if (cmd.expect) {
            if (result == 0) {
                LOG("Command succeeded as expected (expect=true, result=0), returning 0");
                return 0;
            } else {
                LOG_ERROR("Command failed unexpectedly (expect=true, result=" << result << "), returning -1");
                return -1;
            }
        } else {
            if (result != 0) {
                LOG("Command failed as expected (expect=false, result=" << result << "), returning 0");
                return 0;
            } else {
                LOG_ERROR("Command succeeded unexpectedly (expect=false, result=0), returning -1");
                return -1;
            }
        }
    }
}