/** @file Routines dealing with file open. Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
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 - Conficts 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 ((EFI_D_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); }