blob: d17ce5b7eed9bb1875f55a7aafc7b3cb9dc3feb9 [file] [log] [blame]
/** @file
Routines dealing with setting/getting file/volume info
Copyright (c) 2005 - 2015, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Fat.h"
/**
Get the volume's info into Buffer.
@param Volume - FAT file system volume.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing volume info.
@retval EFI_SUCCESS - Get the volume info successfully.
@retval EFI_BUFFER_TOO_SMALL - The buffer is too small.
**/
EFI_STATUS
FatGetVolumeInfo (
IN FAT_VOLUME *Volume,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
);
/**
Set the volume's info.
@param Volume - FAT file system volume.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing the new volume info.
@retval EFI_SUCCESS - Set the volume info successfully.
@retval EFI_BAD_BUFFER_SIZE - The buffer size is error.
@retval EFI_WRITE_PROTECTED - The volume is read only.
@return other - An error occurred when operation the disk.
**/
EFI_STATUS
FatSetVolumeInfo (
IN FAT_VOLUME *Volume,
IN UINTN BufferSize,
IN VOID *Buffer
);
/**
Set or Get the some types info of the file into Buffer.
@param IsSet - TRUE:The access is set, else is get
@param FHand - The handle of file
@param Type - The type of the info
@param BufferSize - Size of Buffer
@param Buffer - Buffer containing volume info
@retval EFI_SUCCESS - Get the info successfully
@retval EFI_DEVICE_ERROR - Can not find the OFile for the file
**/
EFI_STATUS
FatSetOrGetInfo (
IN BOOLEAN IsSet,
IN EFI_FILE_PROTOCOL *FHand,
IN EFI_GUID *Type,
IN OUT UINTN *BufferSize,
IN OUT VOID *Buffer
);
/**
Get the open file's info into Buffer.
@param OFile - The open file.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing file info.
@retval EFI_SUCCESS - Get the file info successfully.
@retval EFI_BUFFER_TOO_SMALL - The buffer is too small.
**/
EFI_STATUS
FatGetFileInfo (
IN FAT_OFILE *OFile,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
return FatGetDirEntInfo (OFile->Volume, OFile->DirEnt, BufferSize, Buffer);
}
/**
Get the volume's info into Buffer.
@param Volume - FAT file system volume.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing volume info.
@retval EFI_SUCCESS - Get the volume info successfully.
@retval EFI_BUFFER_TOO_SMALL - The buffer is too small.
**/
EFI_STATUS
FatGetVolumeInfo (
IN FAT_VOLUME *Volume,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
UINTN Size;
UINTN NameSize;
UINTN ResultSize;
CHAR16 Name[FAT_NAME_LEN + 1];
EFI_STATUS Status;
EFI_FILE_SYSTEM_INFO *Info;
UINT8 ClusterAlignment;
Size = SIZE_OF_EFI_FILE_SYSTEM_INFO;
Status = FatGetVolumeEntry (Volume, Name);
NameSize = StrSize (Name);
ResultSize = Size + NameSize;
ClusterAlignment = Volume->ClusterAlignment;
//
// If we don't have valid info, compute it now
//
FatComputeFreeInfo (Volume);
Status = EFI_BUFFER_TOO_SMALL;
if (*BufferSize >= ResultSize) {
Status = EFI_SUCCESS;
Info = Buffer;
ZeroMem (Info, SIZE_OF_EFI_FILE_SYSTEM_INFO);
Info->Size = ResultSize;
Info->ReadOnly = Volume->ReadOnly;
Info->BlockSize = (UINT32)Volume->ClusterSize;
Info->VolumeSize = LShiftU64 (Volume->MaxCluster, ClusterAlignment);
Info->FreeSpace = LShiftU64 (
Volume->FatInfoSector.FreeInfo.ClusterCount,
ClusterAlignment
);
CopyMem ((CHAR8 *)Buffer + Size, Name, NameSize);
}
*BufferSize = ResultSize;
return Status;
}
/**
Get the volume's label info into Buffer.
@param Volume - FAT file system volume.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing volume's label info.
@retval EFI_SUCCESS - Get the volume's label info successfully.
@retval EFI_BUFFER_TOO_SMALL - The buffer is too small.
**/
EFI_STATUS
FatGetVolumeLabelInfo (
IN FAT_VOLUME *Volume,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
UINTN Size;
UINTN NameSize;
UINTN ResultSize;
CHAR16 Name[FAT_NAME_LEN + 1];
EFI_STATUS Status;
Size = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL;
Status = FatGetVolumeEntry (Volume, Name);
NameSize = StrSize (Name);
ResultSize = Size + NameSize;
Status = EFI_BUFFER_TOO_SMALL;
if (*BufferSize >= ResultSize) {
Status = EFI_SUCCESS;
CopyMem ((CHAR8 *)Buffer + Size, Name, NameSize);
}
*BufferSize = ResultSize;
return Status;
}
/**
Set the volume's info.
@param Volume - FAT file system volume.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing the new volume info.
@retval EFI_SUCCESS - Set the volume info successfully.
@retval EFI_BAD_BUFFER_SIZE - The buffer size is error.
@retval EFI_WRITE_PROTECTED - The volume is read only.
@return other - An error occurred when operation the disk.
**/
EFI_STATUS
FatSetVolumeInfo (
IN FAT_VOLUME *Volume,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
EFI_FILE_SYSTEM_INFO *Info;
Info = (EFI_FILE_SYSTEM_INFO *)Buffer;
if ((BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + 2) || (Info->Size > BufferSize)) {
return EFI_BAD_BUFFER_SIZE;
}
return FatSetVolumeEntry (Volume, Info->VolumeLabel);
}
/**
Set the volume's label info.
@param Volume - FAT file system volume.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing the new volume label info.
@retval EFI_SUCCESS - Set the volume label info successfully.
@retval EFI_WRITE_PROTECTED - The disk is write protected.
@retval EFI_BAD_BUFFER_SIZE - The buffer size is error.
@return other - An error occurred when operation the disk.
**/
EFI_STATUS
FatSetVolumeLabelInfo (
IN FAT_VOLUME *Volume,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
if (BufferSize < SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 2) {
return EFI_BAD_BUFFER_SIZE;
}
return FatSetVolumeEntry (Volume, Info->VolumeLabel);
}
/**
Set the file info.
@param Volume - FAT file system volume.
@param IFile - The instance of the open file.
@param OFile - The open file.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing the new file info.
@retval EFI_SUCCESS - Set the file info successfully.
@retval EFI_ACCESS_DENIED - It is the root directory
or the directory attribute bit can not change
or try to change a directory size
or something else.
@retval EFI_UNSUPPORTED - The new file size is larger than 4GB.
@retval EFI_WRITE_PROTECTED - The disk is write protected.
@retval EFI_BAD_BUFFER_SIZE - The buffer size is error.
@retval EFI_INVALID_PARAMETER - The time info or attributes info is error.
@retval EFI_OUT_OF_RESOURCES - Can not allocate new memory.
@retval EFI_VOLUME_CORRUPTED - The volume is corrupted.
@return other - An error occurred when operation the disk.
**/
EFI_STATUS
FatSetFileInfo (
IN FAT_VOLUME *Volume,
IN FAT_IFILE *IFile,
IN FAT_OFILE *OFile,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
EFI_STATUS Status;
EFI_FILE_INFO *NewInfo;
FAT_OFILE *DotOFile;
FAT_OFILE *Parent;
CHAR16 NewFileName[EFI_PATH_STRING_LENGTH];
EFI_TIME ZeroTime;
FAT_DIRENT *DirEnt;
FAT_DIRENT *TempDirEnt;
UINT8 NewAttribute;
BOOLEAN ReadOnly;
ZeroMem (&ZeroTime, sizeof (EFI_TIME));
Parent = OFile->Parent;
DirEnt = OFile->DirEnt;
//
// If this is the root directory, we can't make any updates
//
if (Parent == NULL) {
return EFI_ACCESS_DENIED;
}
//
// Make sure there's a valid input buffer
//
NewInfo = Buffer;
if ((BufferSize < SIZE_OF_EFI_FILE_INFO + 2) || (NewInfo->Size > BufferSize)) {
return EFI_BAD_BUFFER_SIZE;
}
ReadOnly = (BOOLEAN)(IFile->ReadOnly || (DirEnt->Entry.Attributes & EFI_FILE_READ_ONLY));
//
// if a zero time is specified, then the original time is preserved
//
if (CompareMem (&ZeroTime, &NewInfo->CreateTime, sizeof (EFI_TIME)) != 0) {
if (!FatIsValidTime (&NewInfo->CreateTime)) {
return EFI_INVALID_PARAMETER;
}
if (!ReadOnly) {
FatEfiTimeToFatTime (&NewInfo->CreateTime, &DirEnt->Entry.FileCreateTime);
}
}
if (CompareMem (&ZeroTime, &NewInfo->ModificationTime, sizeof (EFI_TIME)) != 0) {
if (!FatIsValidTime (&NewInfo->ModificationTime)) {
return EFI_INVALID_PARAMETER;
}
if (!ReadOnly) {
FatEfiTimeToFatTime (&NewInfo->ModificationTime, &DirEnt->Entry.FileModificationTime);
}
OFile->PreserveLastModification = TRUE;
}
if (NewInfo->Attribute & (~EFI_FILE_VALID_ATTR)) {
return EFI_INVALID_PARAMETER;
}
NewAttribute = (UINT8)NewInfo->Attribute;
//
// Can not change the directory attribute bit
//
if ((NewAttribute ^ DirEnt->Entry.Attributes) & EFI_FILE_DIRECTORY) {
return EFI_ACCESS_DENIED;
}
//
// Set the current attributes even if the IFile->ReadOnly is TRUE
//
DirEnt->Entry.Attributes = (UINT8)((DirEnt->Entry.Attributes &~EFI_FILE_VALID_ATTR) | NewAttribute);
//
// Open the filename and see if it refers to an existing file
//
Status = FatLocateOFile (&Parent, NewInfo->FileName, DirEnt->Entry.Attributes, NewFileName);
if (EFI_ERROR (Status)) {
return Status;
}
if (*NewFileName != 0) {
//
// File was not found. We do not allow rename of the current directory if
// there are open files below the current directory
//
if (!IsListEmpty (&OFile->ChildHead) || (Parent == OFile)) {
return EFI_ACCESS_DENIED;
}
if (ReadOnly) {
return EFI_ACCESS_DENIED;
}
Status = FatRemoveDirEnt (OFile->Parent, DirEnt);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Create new dirent
//
Status = FatCreateDirEnt (Parent, NewFileName, DirEnt->Entry.Attributes, &TempDirEnt);
if (EFI_ERROR (Status)) {
return Status;
}
FatCloneDirEnt (TempDirEnt, DirEnt);
FatFreeDirEnt (DirEnt);
DirEnt = TempDirEnt;
DirEnt->OFile = OFile;
OFile->DirEnt = DirEnt;
OFile->Parent = Parent;
RemoveEntryList (&OFile->ChildLink);
InsertHeadList (&Parent->ChildHead, &OFile->ChildLink);
//
// If this is a directory, synchronize its dot directory entry
//
if (OFile->ODir != NULL) {
//
// Synchronize its dot entry
//
FatResetODirCursor (OFile);
ASSERT (OFile->Parent != NULL);
for (DotOFile = OFile; DotOFile != OFile->Parent->Parent; DotOFile = DotOFile->Parent) {
Status = FatGetNextDirEnt (OFile, &DirEnt);
if (EFI_ERROR (Status) || (DirEnt == NULL) || !FatIsDotDirEnt (DirEnt)) {
return EFI_VOLUME_CORRUPTED;
}
FatCloneDirEnt (DirEnt, DotOFile->DirEnt);
Status = FatStoreDirEnt (OFile, DirEnt);
if (EFI_ERROR (Status)) {
return Status;
}
}
}
//
// If the file is renamed, we should append the ARCHIVE attribute
//
OFile->Archive = TRUE;
} else if (Parent != OFile) {
//
// filename is to a different filename that already exists
//
return EFI_ACCESS_DENIED;
}
//
// If the file size has changed, apply it
//
if (NewInfo->FileSize != OFile->FileSize) {
if ((OFile->ODir != NULL) || ReadOnly) {
//
// If this is a directory or the file is read only, we can't change the file size
//
return EFI_ACCESS_DENIED;
}
if (NewInfo->FileSize > OFile->FileSize) {
Status = FatExpandOFile (OFile, NewInfo->FileSize);
} else {
Status = FatTruncateOFile (OFile, (UINTN)NewInfo->FileSize);
}
if (EFI_ERROR (Status)) {
return Status;
}
FatUpdateDirEntClusterSizeInfo (OFile);
}
OFile->Dirty = TRUE;
return FatOFileFlush (OFile);
}
/**
Set or Get the some types info of the file into Buffer.
@param IsSet - TRUE:The access is set, else is get
@param FHand - The handle of file
@param Type - The type of the info
@param BufferSize - Size of Buffer
@param Buffer - Buffer containing volume info
@retval EFI_SUCCESS - Get the info successfully
@retval EFI_DEVICE_ERROR - Can not find the OFile for the file
**/
EFI_STATUS
FatSetOrGetInfo (
IN BOOLEAN IsSet,
IN EFI_FILE_PROTOCOL *FHand,
IN EFI_GUID *Type,
IN OUT UINTN *BufferSize,
IN OUT VOID *Buffer
)
{
FAT_IFILE *IFile;
FAT_OFILE *OFile;
FAT_VOLUME *Volume;
EFI_STATUS Status;
IFile = IFILE_FROM_FHAND (FHand);
OFile = IFile->OFile;
Volume = OFile->Volume;
Status = OFile->Error;
if (Status == EFI_NOT_FOUND) {
return EFI_DEVICE_ERROR;
}
FatWaitNonblockingTask (IFile);
FatAcquireLock ();
//
// Verify the file handle isn't in an error state
//
if (!EFI_ERROR (Status)) {
//
// Get the proper information based on the request
//
Status = EFI_UNSUPPORTED;
if (IsSet) {
if (CompareGuid (Type, &gEfiFileInfoGuid)) {
Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetFileInfo (Volume, IFile, OFile, *BufferSize, Buffer);
}
if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {
Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeInfo (Volume, *BufferSize, Buffer);
}
if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
Status = Volume->ReadOnly ? EFI_WRITE_PROTECTED : FatSetVolumeLabelInfo (Volume, *BufferSize, Buffer);
}
} else {
if (CompareGuid (Type, &gEfiFileInfoGuid)) {
Status = FatGetFileInfo (OFile, BufferSize, Buffer);
}
if (CompareGuid (Type, &gEfiFileSystemInfoGuid)) {
Status = FatGetVolumeInfo (Volume, BufferSize, Buffer);
}
if (CompareGuid (Type, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
Status = FatGetVolumeLabelInfo (Volume, BufferSize, Buffer);
}
}
}
Status = FatCleanupVolume (Volume, NULL, Status, NULL);
FatReleaseLock ();
return Status;
}
/**
Get the some types info of the file into Buffer.
@param FHand - The handle of file.
@param Type - The type of the info.
@param BufferSize - Size of Buffer.
@param Buffer - Buffer containing volume info.
@retval EFI_SUCCESS - Get the info successfully.
@retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
**/
EFI_STATUS
EFIAPI
FatGetInfo (
IN EFI_FILE_PROTOCOL *FHand,
IN EFI_GUID *Type,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer
)
{
return FatSetOrGetInfo (FALSE, FHand, Type, BufferSize, Buffer);
}
/**
Set the some types info of the file into Buffer.
@param FHand - The handle of file.
@param Type - The type of the info.
@param BufferSize - Size of Buffer
@param Buffer - Buffer containing volume info.
@retval EFI_SUCCESS - Set the info successfully.
@retval EFI_DEVICE_ERROR - Can not find the OFile for the file.
**/
EFI_STATUS
EFIAPI
FatSetInfo (
IN EFI_FILE_PROTOCOL *FHand,
IN EFI_GUID *Type,
IN UINTN BufferSize,
IN VOID *Buffer
)
{
return FatSetOrGetInfo (TRUE, FHand, Type, &BufferSize, Buffer);
}