security_huks/services/huks_service/core/hks_storage文件读写相关解读(三)

1. 知识分享

1. C库函数:readdir()

定义函数:struct dirent * readdir(DIR * dir);

函数说明:readdir()返回参数dir 目录流的下个目录进入点。

结构dirent 定义如下:

struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen;/* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1];/* file name (null-terminated) 文件名,最长255字符 */
}

返回值:成功则返回下个目录进入点. 有错误发生或读取到目录文件尾则返回NULL

2. 总体概述

该部分代码主要实现了文件存储提取的封装hks、文件名链表的操作函数、以及最后的根据进程名对目标路径上的文件进行全部销毁的功能

3. 代码解读

3.1 RecordKeyOperation

函数功能:记录密钥操作log打印(存储路径 keyAlias)

代码给出了keyAlias的结构:

/*
 * keyAlias: xxxxxxxxxxxxxxxxxxx********************xxxxxxxxxxxxxxxxxx
 *                              |<- anonymous len ->||<- suffix len ->|
 *           |<----------------- keyAlias len ----------------------->|
 */

函数实现:获取keyAlias的长度---->使用for循环将特定长度部分使用星号替代原来的内容得到outKeyAlias---->最后根据给定的operation进行log输出

//记录密钥操作log打印(存储路径 keyAlias)
static int32_t RecordKeyOperation(uint32_t operation, const char *path, const char *keyAlias)
{
    uint32_t bufSize = strlen(keyAlias) + 1;
    char *outKeyAlias = (char *)HksMalloc(bufSize);
    if (outKeyAlias == NULL) {
        return HKS_ERROR_MALLOC_FAIL;
    }
    (void)memset_s(outKeyAlias, bufSize, 0, bufSize);

    //将keyAlias中的特定长度部分用*替代得到outKeyAlias
    uint32_t keyAliasLen = strlen(keyAlias);
    for (uint32_t i = 0; i < keyAliasLen; ++i) {
        if ((keyAliasLen < (i + 1 + KEY_ALIAS_ANONYMOUS_LEN + KEY_ALIAS_SUFFIX_LEN)) &&
            ((i + 1 + KEY_ALIAS_SUFFIX_LEN) <= keyAliasLen)) {
            outKeyAlias[i] = '*';
        } else {
            outKeyAlias[i] = keyAlias[i];
        }
    }
    outKeyAlias[keyAliasLen] = '\0';

    //根据给定的operation进行日志输出
    int32_t ret = HKS_SUCCESS;
    switch (operation) {
        case KEY_OPERATION_SAVE:
            HKS_LOG_I("generate key or certchain, storage path: %s, key alias: %s", path, outKeyAlias);
            break;
        case KEY_OPERATION_GET:
            HKS_LOG_I("use key, storage path: %s, key alias: %s", path, outKeyAlias);
            break;
        case KEY_OPERATION_DELETE:
            HKS_LOG_I("delete key or certchain, storage path: %s, key alias: %s", path, outKeyAlias);
            break;
        default:
            ret = HKS_ERROR_INVALID_ARGUMENT;
    }

    HKS_FREE_PTR(outKeyAlias);
    return ret;
}

3.2 HksStoreKeyBlob

函数功能:根据给定的keyAlias和进程名将keyblob写入path对应文件夹下对应名字的文件中并通过RecordKeyOperation记录密钥操作log打印

函数实现:调用GetFileInfo根据所给参数构建fileInfo---->根据fileInfo中的内容调用RecordKeyOperation进行log打印---->调用SaveKeyBlob完成keyblob中内容的文件写入---->当支持备份时启用fileInfo中的备份信息调用SaveKeyBlob进行备份

SaveKeyBlob

3.3 HksStoreDeleteKeyBlob

函数功能:删除fileInfo中对应的文件keyblob

函数实现:跟3.2几乎一致最后的存储函数换为DeleteKeyBlob

注意一点——这里的代码没有跟3.2一样体现备份文件的删除——而是在DeleteKeyBlob中根据宏定义来判断是否需要进行备份文件的删除

函数实现时不太一致容易让人疑惑

3.4 HksStoreIsKeyBlobExist

函数功能:封装一层检查fileInfo中对应的文件是否存在

函数实现:首先调用GetFileInfo进行fileInfo的构造---->然后调用核心函数IsKeyBlobExist判断fileInfo对应的文件是否存在(备份和主文件)

这里的备份文件的判断内置在IsKeyBlobExist中

3.5 HksStoreGetKeyBlobSize

函数功能:封装根据进程名跟keyAlias先调用GetFileInfo生成fileInfo然后获取给定路径下文件的大小
在这里插入图片描述

3.6 GetFileCount

函数功能:对一个文件路径下的文件进行计数

函数实现:这里是调用HksGetDirFile嵌套循环完成类似DFS的深搜完成文件的统计,具体实现会在另一个利用类似原理的函数中具体讲解
在这里插入图片描述

3.7 GetFileNameList

函数功能:将目录下所有的fileName构成一个列表

函数实现:这里能够实现类似深搜的不断下找文件目录主要是得益于HksGetDirFile这个函数

对其源代码解读我们可以发现其运作实现:

int32_t HksGetDirFile(void *dirp, struct HksFileDirentInfo *direntInfo)
{
	//首先是指针的内容赋值
    DIR *dir = (DIR *)dirp;
    //这个函数非常关键,它返回当前目录中的下一个目录结构dirent
    struct dirent *dire = readdir(dir);
	//当非空时
    while (dire != NULL) {
    	//寻找非文件目录
        if (dire->d_type != DT_REG) { /* only care about files. */
            dire = readdir(dir);
            continue;
        }
		//将其写入direntInfo中由dire带出
        uint32_t len = strlen(dire->d_name);
        if (memcpy_s(direntInfo->fileName, sizeof(direntInfo->fileName) - 1, dire->d_name, len) != EOK) {
            return HKS_ERROR_BAD_STATE;
        }
        direntInfo->fileName[len] = '\0';
        return HKS_SUCCESS;
    }

    return HKS_ERROR_NOT_EXIST;
}

我们可以看下GetFileNameList的源代码

//内部实现猜想:将目录下所有的fileName构成一个列表,如果遇到子目录则深入往下,从最里面的file开始添加
static int32_t GetFileNameList(const char *path, struct HksFileEntry *fileNameList, uint32_t *fileCount)
{
    if ((path == NULL) || (fileCount == NULL) || (fileNameList == NULL)) {
        return HKS_ERROR_NULL_POINTER;
    }
    //打开路径目录
    void *dir = HksOpenDir(path);
    if (dir == NULL) {
        HKS_LOG_W("can't open directory");
        *fileCount = 0;
        return HKS_SUCCESS;
    }

    uint32_t count = 0;
    struct HksFileDirentInfo dire = {{0}};
    //找到一个文件(而不是目录)存入dire
    int32_t ret = HksGetDirFile(dir, &dire);
    //构建统一目录下文件名列表
    while (ret == HKS_SUCCESS) {
        //由于在上头的HksGetDirFile获取到了文件所以在这里之间++
        //最下面也是HksGetDirFile所以这个++可以通用
        count++;
        //获取起长度
        uint32_t nameLen = strlen(dire.fileName);
        if ((*fileCount < count) || (fileNameList[count - 1].fileNameLen < (nameLen + 1))) {
            ret = HKS_ERROR_BUFFER_TOO_SMALL;
            break;
        }
        //将该文件名拷贝入filenameList
        if (strncpy_s(fileNameList[count - 1].fileName, fileNameList[count - 1].fileNameLen,
            dire.fileName, nameLen) != EOK) {
            ret = HKS_ERROR_BAD_STATE;
            break;
        }
        fileNameList[count - 1].fileName[nameLen] = '\0';
        //进行下一个文件的读取
        ret = HksGetDirFile(dir, &dire);
    }
    (void)HksCloseDir(dir);
    *fileCount = count;

    return HKS_SUCCESS;
}

3.8 GetFilePath

函数功能:获取两类文件的路径——密钥和证书

3.9 filename链表的相关操作

  • FileNameListFree:通过for循环将每个结点中的filename进行释放,最后释放filename
  • FileNameListInit:通过for循环进行空间的分配
  • GetAndCheckFileCount:调用GetFileCount获取路径对应的文件个数然后与传入的inputCount进行一致性比较

3.10 HksGetKeyAliasByProcessName

函数功能:封装的功能函数完成对fileInfo的构造,文件的计数以及keyNameList的构建

//根据keyInfo对文件数目进行计数得到count
//根据count进行文件名链表的构建
static int32_t GetKeyAliasByProcessName(const struct HksStoreFileInfo *fileInfo, struct HksKeyInfo *keyInfoList,
    uint32_t *listCount)
{
    uint32_t fileCount;
    //获取并对文件数目进行检查
    int32_t ret = GetAndCheckFileCount(fileInfo->mainPath.path, &fileCount, listCount);
    if (ret != HKS_SUCCESS) {
        return ret;
    }

    if (fileCount == 0) {
        *listCount = 0;
        return HKS_SUCCESS;
    }

    struct HksFileEntry *fileNameList = NULL;
    //fileName链表初始化
    ret = FileNameListInit(&fileNameList, fileCount);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("init file name list failed.");
        return ret;
    }

    uint32_t realFileCount = fileCount;
    //进行文件名链表的构造
    do {
        ret = GetFileNameList(fileInfo->mainPath.path, fileNameList, &realFileCount);
        if (ret != HKS_SUCCESS) {
            HKS_LOG_E("get file name list failed, ret = %d", ret);
            break;
        }

        for (uint32_t i = 0; i < realFileCount; ++i) {
            ret = ConstructBlob(fileNameList[i].fileName, &(keyInfoList[i].alias));
            if (ret != HKS_SUCCESS) {
                HKS_LOG_E("construct blob failed, ret = %d", ret);
                break;
            }
        }
    } while (0);

    FileNameListFree(&fileNameList, fileCount);
    if (ret != HKS_SUCCESS) {
        return ret;
    }

    *listCount = realFileCount;
    return ret;
}

//首先对fileInfo进行构造
//然后调用GetKeyAliasByProcessName根据keyInfo构建keyInfo链表对文件数目进行计数
//并进行keynameList的构建
int32_t HksGetKeyAliasByProcessName(const struct HksBlob *processName, struct HksKeyInfo *keyInfoList,
    uint32_t *listCount)
{
    /* params have been checked by caller functions */
    struct HksStoreFileInfo fileInfo;
    (void)memset_s(&fileInfo, sizeof(fileInfo), 0, sizeof(fileInfo));

    int32_t ret;
    do {
        //对fileInfo中的各个字段进行空间分配
        ret = FileInfoInit(&fileInfo);
        if (ret != HKS_SUCCESS) {
            HKS_LOG_E("hks file info init failed, ret = %d.", ret);
            break;
        }
        //获取两类文件的路径——密钥和证书
        ret = GetFilePath(processName, HKS_STORAGE_TYPE_KEY, &fileInfo);
        if (ret != HKS_SUCCESS) {
            HKS_LOG_E("hks get file info failed, ret = %d.", ret);
            break;
        }
        //根据keyInfo对文件数目进行计数
        //根据count进行文件名链表的构建
        ret = GetKeyAliasByProcessName(&fileInfo, keyInfoList, listCount);
        if (ret != HKS_SUCCESS) {
            HKS_LOG_E("get key alias by processName failed, ret = %d.", ret);
        }
    } while (0);

    FileInfoFree(&fileInfo);
    return ret;
}

3.11 HksStoreDestory

函数功能:根据进程名对相应的文件目录进行销毁

函数实现:首先调用ConstructName进行无效字符的转换---->调用StoreDestory将三个类型的文件存储路径下的文件全部销毁

//将一个目录下的所有文件夹或者文件全部销毁
static int32_t DestoryType(const char *storePath, const char *typePath, uint32_t bakFlag)
{
    char *destoryPath = (char *)HksMalloc(HKS_MAX_FILE_NAME_LEN);
    if (destoryPath == NULL) {
        return HKS_ERROR_MALLOC_FAIL;
    }
    (void)memset_s(destoryPath, HKS_MAX_FILE_NAME_LEN, 0, HKS_MAX_FILE_NAME_LEN);

    int32_t ret = GetPath(storePath, typePath, destoryPath, HKS_MAX_FILE_NAME_LEN, bakFlag);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("Get Path failed! ret = 0x%X", ret);
        HKS_FREE_PTR(destoryPath);
        return ret;
    }

    ret = HksIsDirExist(destoryPath);
    if (ret != HKS_SUCCESS) {
        HKS_FREE_PTR(destoryPath);
        return HKS_SUCCESS;
    }
    //目录的销毁
    ret = HksRemoveDir(destoryPath);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("Destory dir failed! ret = 0x%X", ret);
    }

    HKS_FREE_PTR(destoryPath);
    return ret;
}

//将三个类型的文件存储路径下的文件全部销毁
static int32_t StoreDestory(const char *processNameEncoded, uint32_t bakFlag)
{
    int32_t ret;
    char *rootPath = NULL;
    if (bakFlag == HKS_STORAGE_BAK_FLAG_TRUE) {
        ret = GetStoreRootPath(HKS_STORAGE_BACKUP_PATH, &rootPath);
    } else {
        ret = GetStoreRootPath(HKS_STORAGE_MAIN_PATH, &rootPath);
    }
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("get root path failed");
        return ret;
    }

    char *storePath = (char *)HksMalloc(HKS_MAX_FILE_NAME_LEN);
    if (storePath == NULL) {
        return HKS_ERROR_MALLOC_FAIL;
    }
    (void)memset_s(storePath, HKS_MAX_FILE_NAME_LEN, 0, HKS_MAX_FILE_NAME_LEN);

    ret = GetPath(rootPath, processNameEncoded, storePath, HKS_MAX_FILE_NAME_LEN, bakFlag);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_E("Get Path failed! ret = 0x%X", ret);
        HKS_FREE_PTR(storePath);
        return ret;
    }

    ret = DestoryType(storePath, HKS_KEY_STORE_ROOT_KEY_PATH, bakFlag);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_I("Destory info dir failed! ret = 0x%X", ret); /* continue delete */
    }

    ret = DestoryType(storePath, HKS_KEY_STORE_KEY_PATH, bakFlag);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_I("Destory key dir failed! ret = 0x%X", ret); /* continue delete */
    }

    ret = DestoryType(storePath, HKS_KEY_STORE_CERTCHAIN_PATH, bakFlag);
    if (ret != HKS_SUCCESS) {
        HKS_LOG_I("Destory certchain dir failed! ret = 0x%X", ret); /* continue delete */
    }

    HKS_FREE_PTR(storePath);
    return HKS_SUCCESS;
}

//根据进程名对相应的文件目录进行销毁
int32_t HksStoreDestory(const struct HksBlob *processName)
{
    char *name = (char *)HksMalloc(HKS_MAX_FILE_NAME_LEN);
    if (name == NULL) {
        return HKS_ERROR_MALLOC_FAIL;
    }
    (void)memset_s(name, HKS_MAX_FILE_NAME_LEN, 0, HKS_MAX_FILE_NAME_LEN);

    int32_t ret;
    do {
        ret = ConstructName(processName, name, HKS_MAX_FILE_NAME_LEN);
        if (ret != HKS_SUCCESS) {
            HKS_LOG_E("Construct process name failed! ret = 0x%X.", ret);
            break;
        }
        //将三个类型的文件存储路径下的文件全部销毁
        ret = StoreDestory(name, HKS_STORAGE_BAK_FLAG_FLASE);
        if (ret != HKS_SUCCESS) {
            HKS_LOG_E("Hks destory dir failed! ret = 0x%X.", ret);
            break;
        }

#ifdef SUPPORT_STORAGE_BACKUP
        ret = StoreDestory(name, HKS_STORAGE_BAK_FLAG_TRUE);
        if (ret != HKS_SUCCESS) {
            HKS_LOG_E("Hks destory back dir failed! ret = 0x%X.", ret);
            break;
        }
#endif
    } while (0);

    HKS_FREE_PTR(name);
    return ret;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

国家一级假勤奋研究牲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值