文件存储各功能的封装、FileNameList的构造以及文件销毁函数的封装
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进行备份
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;
}