uefi创建文件的时候如果路径中有某一级目录不存在会报错,所以要创建文件夹以满足目录的要求,如果只是创建路径中不存在的目录不会有问题,但是如果写个循环依次创建每一级文件夹,就会创建原来就已经存在的文件夹,这个时候就会出现文件系统解析的问题,可能导致文件丢失
#define PARTITION_HANDLE EFI_HANDLE
#define FILE_MODE_READ 0x0000000000000001ULL
#define FILE_MODE_WRITE 0x0000000000000002ULL
#define FILE_MODE_CREATE 0x8000000000000000ULL
//这三个属性对应的值在uefi中有提供
CHAR16* StrChr16(const CHAR16* src,INT16 chr)
{
CHAR16* tmp = (CHAR16*)src;
if(NULL == src)
{
return NULL;
}
while((*tmp != 0) && (*(tmp++) != chr));
if(*tmp == 0)
{
tmp = NULL;
}
else
{
--tmp;
}
return tmp;
}
/**
判断是否能找到指定目录
**/
EFI_BASE_RET
EfiIsDirFound(
IN PARTITION_HANDLE Handle,
IN CHAR16 *Path)
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Sfs;
FILE_HANDLE *Root;
FILE_HANDLE *pFile;
//打开文件系统协议
Status = gBS->HandleProtocol(
Handle,
&gEfiSimpleFileSystemProtocolGuid,
(VOID**)&Sfs);
if(EFI_ERROR(Status))
{
return EFI_BASE_DEVICE_UNSUPPORTED;
}
Status = Sfs->OpenVolume(Sfs, &Root);
if(EFI_ERROR(Status))
{
return EFI_BASE_MEDIA_OPEN_ERROR;
}
//打开文件
Status = Root->Open(Root, &pFile, Path, EFI_FILE_MODE_READ, EFI_FILE_DIRECTORY);
if( !EFI_ERROR(Status) )
{
pFile->Close(pFile);
return EFI_BASE_SUCCESS;
}
if ( EFI_ACCESS_DENIED == Status )
{
return EFI_BASE_FILE_ACCESS_DENIED;
}
return EFI_BASE_NOT_FOUND;
}
/**
根据分区句柄和文件相对路径获取文件句柄
**/
EFI_BASE_RET EfiOpenFile(
IN PARTITION_HANDLE Handle,
IN CHAR16*Path,
IN UINT64 OpenMode,
OUT FILE_HANDLE**ppFile )
{
EFI_STATUS Status;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Sfs;
FILE_HANDLE *Root;
CHAR16 TmpPath[260];
StrCpy(TmpPath, Path);
//打开文件系统协议
Status = gBS->HandleProtocol(
Handle,
&gEfiSimpleFileSystemProtocolGuid,
(VOID**)&Sfs);
if(EFI_ERROR(Status))
{
return EFI_BASE_DEVICE_UNSUPPORTED;
}
Status = Sfs->OpenVolume(Sfs, &Root);
if(EFI_ERROR(Status))
{
return EFI_BASE_MEDIA_OPEN_ERROR;
}
//打开文件夹
if(0x0 != (OpenMode & FILE_MODE_CREATE))
{
CHAR16 *tmp = TmpPath;
while((L'\\' == *tmp) || (L' ' == *tmp))
{
++tmp;
}
while(NULL != (tmp = StrChr16(tmp,L'\\')))
{
*tmp = L'\0';
if(EFI_BASE_SUCCESS != EfiIsDirFound(Handle, TmpPath))
{
Status = Root->Open(
Root,
ppFile,
TmpPath,
FILE_MODE_READ | FILE_MODE_WRITE | FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
if (EFI_ERROR(Status))
{
return EFI_BASE_FILE_CREATE_ERROR;
}
(*ppFile)->Close(*ppFile);
}
*tmp = L'\\';
++tmp;
}
}
//打开文件
Status = Root->Open(Root, ppFile, TmpPath, OpenMode, 0);
if(!EFI_ERROR(Status))
{
return EFI_BASE_SUCCESS;
}
return EFI_BASE_FILE_OPEN_ERROR;
}