/** @file | |
EFI_FILE_PROTOCOL.GetInfo() member function for the Virtio Filesystem driver. | |
Copyright (C) 2020, Red Hat, Inc. | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include <Guid/FileSystemInfo.h> // gEfiFileSystemInfoGuid | |
#include <Guid/FileSystemVolumeLabelInfo.h> // gEfiFileSystemVolumeLabelInfo... | |
#include <Library/BaseLib.h> // StrSize() | |
#include <Library/BaseMemoryLib.h> // CompareGuid() | |
#include "VirtioFsDxe.h" | |
/** | |
Provide EFI_FILE_INFO about this particular file. | |
**/ | |
STATIC | |
EFI_STATUS | |
GetFileInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
VIRTIO_FS_FILE *VirtioFsFile; | |
VIRTIO_FS *VirtioFs; | |
UINTN AllocSize; | |
UINTN BasenameSize; | |
EFI_STATUS Status; | |
EFI_FILE_INFO *FileInfo; | |
VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE FuseAttr; | |
VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This); | |
VirtioFs = VirtioFsFile->OwnerFs; | |
AllocSize = *BufferSize; | |
// | |
// Calculate the needed size. | |
// | |
BasenameSize = 0; | |
Status = VirtioFsGetBasename ( | |
VirtioFsFile->CanonicalPathname, | |
NULL, | |
&BasenameSize | |
); | |
ASSERT (Status == EFI_BUFFER_TOO_SMALL); | |
*BufferSize = OFFSET_OF (EFI_FILE_INFO, FileName) + BasenameSize; | |
if (*BufferSize > AllocSize) { | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// Set the structure size, and store the basename. | |
// | |
FileInfo = Buffer; | |
FileInfo->Size = *BufferSize; | |
Status = VirtioFsGetBasename ( | |
VirtioFsFile->CanonicalPathname, | |
FileInfo->FileName, | |
&BasenameSize | |
); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Fetch the file attributes, and convert them into the caller's buffer. | |
// | |
Status = VirtioFsFuseGetAttr (VirtioFs, VirtioFsFile->NodeId, &FuseAttr); | |
if (!EFI_ERROR (Status)) { | |
Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, FileInfo); | |
} | |
return (Status == EFI_BUFFER_TOO_SMALL) ? EFI_DEVICE_ERROR : Status; | |
} | |
/** | |
Provide EFI_FILE_SYSTEM_INFO about the filesystem this file lives on. | |
**/ | |
STATIC | |
EFI_STATUS | |
GetFileSystemInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
VIRTIO_FS_FILE *VirtioFsFile; | |
VIRTIO_FS *VirtioFs; | |
UINTN AllocSize; | |
UINTN LabelSize; | |
EFI_STATUS Status; | |
VIRTIO_FS_FUSE_STATFS_RESPONSE FilesysAttr; | |
UINT64 MaxBlocks; | |
EFI_FILE_SYSTEM_INFO *FilesysInfo; | |
VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This); | |
VirtioFs = VirtioFsFile->OwnerFs; | |
AllocSize = *BufferSize; | |
// | |
// Calculate the needed size. | |
// | |
LabelSize = StrSize (VirtioFs->Label); | |
*BufferSize = OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel) + LabelSize; | |
if (*BufferSize > AllocSize) { | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// Fetch the filesystem attributes. | |
// | |
Status = VirtioFsFuseStatFs (VirtioFs, VirtioFsFile->NodeId, &FilesysAttr); | |
if (EFI_ERROR (Status)) { | |
return (Status == EFI_BUFFER_TOO_SMALL) ? EFI_DEVICE_ERROR : Status; | |
} | |
// | |
// Sanity checks... | |
// | |
if (FilesysAttr.Frsize != FilesysAttr.Bsize) { | |
return EFI_UNSUPPORTED; | |
} | |
if ((FilesysAttr.Frsize == 0) || (FilesysAttr.Blocks == 0) || | |
(FilesysAttr.Bavail > FilesysAttr.Blocks)) | |
{ | |
return EFI_DEVICE_ERROR; | |
} | |
MaxBlocks = DivU64x32 (MAX_UINT64, FilesysAttr.Frsize); | |
if ((FilesysAttr.Blocks > MaxBlocks) || (FilesysAttr.Bavail > MaxBlocks)) { | |
return EFI_DEVICE_ERROR; | |
} | |
// | |
// Fill in EFI_FILE_SYSTEM_INFO. | |
// | |
FilesysInfo = Buffer; | |
FilesysInfo->Size = *BufferSize; | |
FilesysInfo->ReadOnly = FALSE; | |
FilesysInfo->VolumeSize = MultU64x32 ( | |
FilesysAttr.Blocks, | |
FilesysAttr.Frsize | |
); | |
FilesysInfo->FreeSpace = MultU64x32 ( | |
FilesysAttr.Bavail, | |
FilesysAttr.Frsize | |
); | |
FilesysInfo->BlockSize = FilesysAttr.Frsize; | |
CopyMem (FilesysInfo->VolumeLabel, VirtioFs->Label, LabelSize); | |
return EFI_SUCCESS; | |
} | |
/** | |
Return the filesystem label as EFI_FILE_SYSTEM_VOLUME_LABEL. | |
**/ | |
STATIC | |
EFI_STATUS | |
GetFileSystemVolumeLabelInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
VIRTIO_FS_FILE *VirtioFsFile; | |
VIRTIO_FS *VirtioFs; | |
UINTN AllocSize; | |
UINTN LabelSize; | |
EFI_FILE_SYSTEM_VOLUME_LABEL *FilesysVolumeLabel; | |
VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This); | |
VirtioFs = VirtioFsFile->OwnerFs; | |
AllocSize = *BufferSize; | |
// | |
// Calculate the needed size. | |
// | |
LabelSize = StrSize (VirtioFs->Label); | |
*BufferSize = (OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL, VolumeLabel) + | |
LabelSize); | |
if (*BufferSize > AllocSize) { | |
return EFI_BUFFER_TOO_SMALL; | |
} | |
// | |
// Store the label. | |
// | |
FilesysVolumeLabel = Buffer; | |
CopyMem (FilesysVolumeLabel->VolumeLabel, VirtioFs->Label, LabelSize); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
VirtioFsSimpleFileGetInfo ( | |
IN EFI_FILE_PROTOCOL *This, | |
IN EFI_GUID *InformationType, | |
IN OUT UINTN *BufferSize, | |
OUT VOID *Buffer | |
) | |
{ | |
if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { | |
return GetFileInfo (This, BufferSize, Buffer); | |
} | |
if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { | |
return GetFileSystemInfo (This, BufferSize, Buffer); | |
} | |
if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { | |
return GetFileSystemVolumeLabelInfo (This, BufferSize, Buffer); | |
} | |
return EFI_UNSUPPORTED; | |
} |