blob: f3fd6566ea3f791456ea64cc340ea9767634d2ba [file] [log] [blame]
/** @file
Routines dealing with file open.
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Fat.h"
/**
Create an Open instance for the existing OFile.
The IFile of the newly opened file is passed out.
@param OFile - The file that serves as a starting reference point.
@param PtrIFile - The newly generated IFile instance.
@retval EFI_OUT_OF_RESOURCES - Can not allocate the memory for the IFile
@retval EFI_SUCCESS - Create the new IFile for the OFile successfully
**/
EFI_STATUS
FatAllocateIFile (
IN FAT_OFILE *OFile,
OUT FAT_IFILE **PtrIFile
)
{
FAT_IFILE *IFile;
ASSERT_VOLUME_LOCKED (OFile->Volume);
//
// Allocate a new open instance
//
IFile = AllocateZeroPool (sizeof (FAT_IFILE));
if (IFile == NULL) {
return EFI_OUT_OF_RESOURCES;
}
IFile->Signature = FAT_IFILE_SIGNATURE;
CopyMem (&(IFile->Handle), &FatFileInterface, sizeof (EFI_FILE_PROTOCOL));
//
// Report the correct revision number based on the DiskIo2 availability
//
if (OFile->Volume->DiskIo2 != NULL) {
IFile->Handle.Revision = EFI_FILE_PROTOCOL_REVISION2;
} else {
IFile->Handle.Revision = EFI_FILE_PROTOCOL_REVISION;
}
IFile->OFile = OFile;
InsertTailList (&OFile->Opens, &IFile->Link);
InitializeListHead (&IFile->Tasks);
*PtrIFile = IFile;
return EFI_SUCCESS;
}
/**
Open a file for a file name relative to an existing OFile.
The IFile of the newly opened file is passed out.
@param OFile - The file that serves as a starting reference point.
@param NewIFile - The newly generated IFile instance.
@param FileName - The file name relative to the OFile.
@param OpenMode - Open mode.
@param Attributes - Attributes to set if the file is created.
@retval EFI_SUCCESS - Open the file successfully.
@retval EFI_INVALID_PARAMETER - The open mode is conflict with the attributes
or the file name is not valid.
@retval EFI_NOT_FOUND - Conflicts between dir intention and attribute.
@retval EFI_WRITE_PROTECTED - Can't open for write if the volume is read only.
@retval EFI_ACCESS_DENIED - If the file's attribute is read only, and the
open is for read-write fail it.
@retval EFI_OUT_OF_RESOURCES - Can not allocate the memory.
**/
EFI_STATUS
FatOFileOpen (
IN FAT_OFILE *OFile,
OUT FAT_IFILE **NewIFile,
IN CHAR16 *FileName,
IN UINT64 OpenMode,
IN UINT8 Attributes
)
{
FAT_VOLUME *Volume;
EFI_STATUS Status;
CHAR16 NewFileName[EFI_PATH_STRING_LENGTH];
FAT_DIRENT *DirEnt;
UINT8 FileAttributes;
BOOLEAN WriteMode;
DirEnt = NULL;
Volume = OFile->Volume;
ASSERT_VOLUME_LOCKED (Volume);
WriteMode = (BOOLEAN)(OpenMode & EFI_FILE_MODE_WRITE);
if (Volume->ReadOnly && WriteMode) {
return EFI_WRITE_PROTECTED;
}
//
// Verify the source file handle isn't in an error state
//
Status = OFile->Error;
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get new OFile for the file
//
Status = FatLocateOFile (&OFile, FileName, Attributes, NewFileName);
if (EFI_ERROR (Status)) {
return Status;
}
if (*NewFileName != 0) {
//
// If there's a remaining part of the name, then we had
// better be creating the file in the directory
//
if ((OpenMode & EFI_FILE_MODE_CREATE) == 0) {
return EFI_NOT_FOUND;
}
Status = FatCreateDirEnt (OFile, NewFileName, Attributes, &DirEnt);
if (EFI_ERROR (Status)) {
return Status;
}
ASSERT (DirEnt != NULL);
Status = FatOpenDirEnt (OFile, DirEnt);
if (EFI_ERROR (Status)) {
return Status;
}
OFile = DirEnt->OFile;
if (OFile->ODir != NULL) {
//
// If we just created a directory, we need to create "." and ".."
//
Status = FatCreateDotDirEnts (OFile);
if (EFI_ERROR (Status)) {
return Status;
}
}
}
//
// If the file's attribute is read only, and the open is for
// read-write, then the access is denied.
//
FileAttributes = OFile->DirEnt->Entry.Attributes;
if (((FileAttributes & EFI_FILE_READ_ONLY) != 0) && ((FileAttributes & FAT_ATTRIBUTE_DIRECTORY) == 0) && WriteMode) {
return EFI_ACCESS_DENIED;
}
//
// Create an open instance of the OFile
//
Status = FatAllocateIFile (OFile, NewIFile);
if (EFI_ERROR (Status)) {
return Status;
}
(*NewIFile)->ReadOnly = (BOOLEAN) !WriteMode;
DEBUG ((DEBUG_INFO, "FSOpen: Open '%S' %r\n", FileName, Status));
return FatOFileFlush (OFile);
}
/**
Implements OpenEx() of Simple File System Protocol.
@param FHand - File handle of the file serves as a starting reference point.
@param NewHandle - Handle of the file that is newly opened.
@param FileName - File name relative to FHand.
@param OpenMode - Open mode.
@param Attributes - Attributes to set if the file is created.
@param Token - A pointer to the token associated with the transaction.:
@retval EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.
The OpenMode is not supported.
The Attributes is not the valid attributes.
@retval EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string.
@retval EFI_SUCCESS - Open the file successfully.
@return Others - The status of open file.
**/
EFI_STATUS
EFIAPI
FatOpenEx (
IN EFI_FILE_PROTOCOL *FHand,
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
IN UINT64 OpenMode,
IN UINT64 Attributes,
IN OUT EFI_FILE_IO_TOKEN *Token
)
{
FAT_IFILE *IFile;
FAT_IFILE *NewIFile;
FAT_OFILE *OFile;
EFI_STATUS Status;
FAT_TASK *Task;
//
// Perform some parameter checking
//
if (FileName == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Check for a valid mode
//
switch (OpenMode) {
case EFI_FILE_MODE_READ:
case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
break;
default:
return EFI_INVALID_PARAMETER;
}
//
// Check for valid Attributes for file creation case.
//
if (((OpenMode & EFI_FILE_MODE_CREATE) != 0) && ((Attributes & (EFI_FILE_READ_ONLY | (~EFI_FILE_VALID_ATTR))) != 0)) {
return EFI_INVALID_PARAMETER;
}
IFile = IFILE_FROM_FHAND (FHand);
OFile = IFile->OFile;
Task = NULL;
if (Token == NULL) {
FatWaitNonblockingTask (IFile);
} else {
//
// Caller shouldn't call the non-blocking interfaces if the low layer doesn't support DiskIo2.
// But if it calls, the below check can avoid crash.
//
if (FHand->Revision < EFI_FILE_PROTOCOL_REVISION2) {
return EFI_UNSUPPORTED;
}
Task = FatCreateTask (IFile, Token);
if (Task == NULL) {
return EFI_OUT_OF_RESOURCES;
}
}
//
// Lock
//
FatAcquireLock ();
//
// Open the file
//
Status = FatOFileOpen (OFile, &NewIFile, FileName, OpenMode, (UINT8)Attributes);
//
// If the file was opened, return the handle to the caller
//
if (!EFI_ERROR (Status)) {
*NewHandle = &NewIFile->Handle;
}
//
// Unlock
//
Status = FatCleanupVolume (OFile->Volume, NULL, Status, Task);
FatReleaseLock ();
if (Token != NULL) {
if (!EFI_ERROR (Status)) {
Status = FatQueueTask (IFile, Task);
} else {
FatDestroyTask (Task);
}
}
return Status;
}
/**
Implements Open() of Simple File System Protocol.
@param FHand - File handle of the file serves as a starting reference point.
@param NewHandle - Handle of the file that is newly opened.
@param FileName - File name relative to FHand.
@param OpenMode - Open mode.
@param Attributes - Attributes to set if the file is created.
@retval EFI_INVALID_PARAMETER - The FileName is NULL or the file string is empty.
The OpenMode is not supported.
The Attributes is not the valid attributes.
@retval EFI_OUT_OF_RESOURCES - Can not allocate the memory for file string.
@retval EFI_SUCCESS - Open the file successfully.
@return Others - The status of open file.
**/
EFI_STATUS
EFIAPI
FatOpen (
IN EFI_FILE_PROTOCOL *FHand,
OUT EFI_FILE_PROTOCOL **NewHandle,
IN CHAR16 *FileName,
IN UINT64 OpenMode,
IN UINT64 Attributes
)
{
return FatOpenEx (FHand, NewHandle, FileName, OpenMode, Attributes, NULL);
}