/** 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); }
EFI_STATUS FatIFileAccess ( IN EFI_FILE_PROTOCOL *FHand, IN IO_MODE IoMode, IN OUT UINTN *BufferSize, IN OUT VOID *Buffer, IN EFI_FILE_IO_TOKEN *Token ) /*++ Routine Description: Get the file info from the open file of the IFile into Buffer. Arguments: FHand - The file handle to access. IoMode - Indicate whether the access mode is reading or writing. BufferSize - Size of Buffer. Buffer - Buffer containing read data. Token - A pointer to the token associated with the transaction. Returns: EFI_SUCCESS - Get the file info successfully. EFI_DEVICE_ERROR - Can not find the OFile for the file. EFI_VOLUME_CORRUPTED - The file type of open file is error. EFI_WRITE_PROTECTED - The disk is write protect. EFI_ACCESS_DENIED - The file is read-only. other - An error occurred when operating on the disk. --*/ { EFI_STATUS Status; FAT_IFILE *IFile; FAT_OFILE *OFile; FAT_VOLUME *Volume; UINT64 EndPosition; FAT_TASK *Task; IFile = IFILE_FROM_FHAND (FHand); OFile = IFile->OFile; Volume = OFile->Volume; Task = NULL; // // Write to a directory is unsupported // if ((OFile->ODir != NULL) && (IoMode == WRITE_DATA)) { return EFI_UNSUPPORTED; } if (OFile->Error == EFI_NOT_FOUND) { return EFI_DEVICE_ERROR; } if (IoMode == READ_DATA) { // // If position is at EOF, then return device error // if (IFile->Position > OFile->FileSize) { return EFI_DEVICE_ERROR; } } else { // // Check if the we can write data // if (Volume->ReadOnly) { return EFI_WRITE_PROTECTED; } if (IFile->ReadOnly) { return EFI_ACCESS_DENIED; } } 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; } } FatAcquireLock (); Status = OFile->Error; if (!EFI_ERROR (Status)) { if (OFile->ODir != NULL) { // // Read a directory is supported // ASSERT (IoMode == READ_DATA); Status = FatIFileReadDir (IFile, BufferSize, Buffer); OFile = NULL; } else { // // Access a file // EndPosition = IFile->Position + *BufferSize; if (EndPosition > OFile->FileSize) { // // The position goes beyond the end of file // if (IoMode == READ_DATA) { // // Adjust the actual size read // *BufferSize -= (UINTN) EndPosition - OFile->FileSize; } else { // // We expand the file size of OFile // Status = FatGrowEof (OFile, EndPosition); if (EFI_ERROR (Status)) { // // Must update the file's info into the file's Directory Entry // and then flush the dirty cache info into disk. // *BufferSize = 0; FatOFileFlush (OFile); OFile = NULL; goto Done; } FatUpdateDirEntClusterSizeInfo (OFile); } } Status = FatAccessOFile (OFile, IoMode, (UINTN) IFile->Position, BufferSize, Buffer, Task); IFile->Position += *BufferSize; } } if (Token != NULL) { if (!EFI_ERROR (Status)) { Status = FatQueueTask (IFile, Task); } else { FatDestroyTask (Task); } } Done: // // On EFI_SUCCESS case, not calling FatCleanupVolume(): // 1) The Cache flush operation is avoided to enhance // performance. Caller is responsible to call Flush() when necessary. // 2) The volume dirty bit is probably set already, and is expected to be // cleaned in subsequent Flush() or other operations. // 3) Write operation doesn't affect OFile/IFile structure, so // Reference checking is not necessary. // if (EFI_ERROR (Status)) { Status = FatCleanupVolume (Volume, OFile, Status, NULL); } FatReleaseLock (); return Status; }
EFI_STATUS FatOFileOpen ( IN FAT_OFILE *OFile, OUT FAT_IFILE **NewIFile, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT8 Attributes ) /*++ Routine Description: Open a file for a file name relative to an existing OFile. The IFile of the newly opened file is passed out. Arguments: OFile - The file that serves as a starting reference point. NewIFile - The newly generated IFile instance. FileName - The file name relative to the OFile. OpenMode - Open mode. Attributes - Attributes to set if the file is created. Returns: EFI_SUCCESS - Open the file successfully. EFI_INVALID_PARAMETER - The open mode is conflict with the attributes or the file name is not valid. EFI_NOT_FOUND - Conficts between dir intention and attribute. EFI_WRITE_PROTECTED - Can't open for write if the volume is read only. EFI_ACCESS_DENIED - If the file's attribute is read only, and the open is for read-write fail it. EFI_OUT_OF_RESOURCES - Can not allocate the memory. --*/ { 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); }