/** Sets a file's current position. @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to set the requested position on. @param Position The byte position from the start of the file to set. @retval EFI_SUCCESS The position was set. @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open directories. @retval EFI_DEVICE_ERROR An attempt was made to set the position of a deleted file. **/ EFI_STATUS EFIAPI FvSimpleFileSystemSetPosition ( IN EFI_FILE_PROTOCOL *This, IN UINT64 Position ) { FV_FILESYSTEM_INSTANCE *Instance; FV_FILESYSTEM_FILE *File; File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; if (File->FvFileInfo == Instance->Root->FvFileInfo) { if (Position != 0) { return EFI_UNSUPPORTED; } // // Reset directory position to first entry // File->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance); } else if (Position == 0xFFFFFFFFFFFFFFFFull) { File->Position = File->FvFileInfo->FileInfo.FileSize; } else { File->Position = Position; } return EFI_SUCCESS; }
/** Open the root directory on a volume. @param This A pointer to the volume to open the root directory. @param RootFile A pointer to the location to return the opened file handle for the root directory. @retval EFI_SUCCESS The device was opened. @retval EFI_UNSUPPORTED This volume does not support the requested file system type. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_ACCESS_DENIED The service denied access to the file. @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no longer supported. Any existing file handles for this volume are no longer valid. To access the files on the new medium, the volume must be reopened with OpenVolume(). **/ EFI_STATUS EFIAPI FvSimpleFileSystemOpenVolume ( IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **RootFile ) { EFI_STATUS Status; FV_FILESYSTEM_FILE *Root; CHAR16 *UiSection; EFI_GUID NameGuid; EFI_FV_FILE_ATTRIBUTES Attributes; UINT32 Authentication; UINTN Key; EFI_FV_FILETYPE FileType; UINTN Size; FV_FILESYSTEM_INSTANCE *Instance; FV_FILESYSTEM_FILE_INFO *FvFileInfo; EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; CHAR16 *Name; UINTN NameLen; UINTN NumChars; UINTN DestMax; Instance = FVFS_INSTANCE_FROM_SIMPLE_FS_THIS (This); Status = EFI_SUCCESS; if (Instance->Root == NULL) { // // Allocate file structure for root file // Root = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); if (Root == NULL) { return EFI_OUT_OF_RESOURCES; } Instance->Root = Root; Root->Instance = Instance; Root->Signature = FVFS_FILE_SIGNATURE; CopyMem (&Root->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); Root->FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO)); if (Root->FvFileInfo == NULL) { return EFI_OUT_OF_RESOURCES; } Root->FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO); Root->FvFileInfo->FileInfo.Attribute = EFI_FILE_DIRECTORY | EFI_FILE_READ_ONLY; // // Populate the instance's list of files. We consider anything a file that // has a UI_SECTION, which we consider to be its filename. // FvProtocol = Instance->FvProtocol; // // Allocate Key // Key = 0; do { FileType = EFI_FV_FILETYPE_ALL; Status = FvProtocol->GetNextFile ( FvProtocol, &Key, &FileType, &NameGuid, &Attributes, &Size ); if (EFI_ERROR (Status)) { ASSERT (Status == EFI_NOT_FOUND); break; } // // Get a file's name: If it has a UI section, use that, otherwise use // its NameGuid. // UiSection = NULL; Status = FvProtocol->ReadSection ( FvProtocol, &NameGuid, EFI_SECTION_USER_INTERFACE, 0, (VOID **)&UiSection, &Size, &Authentication ); if (!EFI_ERROR (Status)) { Name = UiSection; } else { Name = AllocateZeroPool (GUID_STRING_SIZE); if (Name == NULL) { return EFI_OUT_OF_RESOURCES; } NumChars = UnicodeSPrint (Name, GUID_STRING_SIZE, L"%g", &NameGuid); ASSERT ((NumChars + 1) * sizeof (CHAR16) == GUID_STRING_SIZE); } // // Found a file. // Allocate a file structure and populate it. // NameLen = StrSize (Name); if (FV_FILETYPE_IS_EXECUTABLE (FileType)) { NameLen += StrSize (L".efi") - sizeof (CHAR16); } FvFileInfo = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE_INFO) + NameLen - sizeof (CHAR16)); if (FvFileInfo == NULL) { return EFI_OUT_OF_RESOURCES; } FvFileInfo->Signature = FVFS_FILE_INFO_SIGNATURE; InitializeListHead (&FvFileInfo->Link); CopyMem (&FvFileInfo->NameGuid, &NameGuid, sizeof (EFI_GUID)); FvFileInfo->Type = FileType; // // Add ".efi" to filenames of drivers and applications. // DestMax = NameLen / sizeof (CHAR16); Status = StrnCpyS (&FvFileInfo->FileInfo.FileName[0], DestMax, Name, StrLen (Name)); ASSERT_EFI_ERROR (Status); if (FV_FILETYPE_IS_EXECUTABLE (FileType)) { Status = StrnCatS (&FvFileInfo->FileInfo.FileName[0], DestMax, L".efi", StrLen (L".efi")); ASSERT_EFI_ERROR (Status); } FvFileInfo->FileInfo.Size = sizeof (EFI_FILE_INFO) + NameLen - sizeof (CHAR16); Status = FvFsGetFileSize (FvProtocol, FvFileInfo); ASSERT_EFI_ERROR (Status); FvFileInfo->FileInfo.PhysicalSize = FvFileInfo->FileInfo.FileSize; FvFileInfo->FileInfo.Attribute = EFI_FILE_READ_ONLY; InsertHeadList (&Instance->FileInfoHead, &FvFileInfo->Link); FreePool (Name); } while (TRUE); if (Status == EFI_NOT_FOUND) { Status = EFI_SUCCESS; } } Instance->Root->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance); *RootFile = &Instance->Root->FileProtocol; return Status; }
/** Opens a new file relative to the source file's location. @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to the source location. This would typically be an open handle to a directory. @param NewHandle A pointer to the location to return the opened handle for the new file. @param FileName The Null-terminated string of the name of the file to be opened. The file name may contain the following path modifiers: "\", ".", and "..". @param OpenMode The mode to open the file. The only valid combinations that the file may be opened with are: Read, Read/Write, or Create/Read/Write. @param Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the attribute bits for the newly created file. @retval EFI_SUCCESS The file was opened. @retval EFI_NOT_FOUND The specified file could not be found on the device. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no longer supported. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write when the media is write-protected. @retval EFI_ACCESS_DENIED The service denied access to the file. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI FvSimpleFileSystemOpen ( IN EFI_FILE_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes ) { FV_FILESYSTEM_INSTANCE *Instance; FV_FILESYSTEM_FILE *File; FV_FILESYSTEM_FILE *NewFile; FV_FILESYSTEM_FILE_INFO *FvFileInfo; LIST_ENTRY *FvFileInfoLink; // // Check for a valid mode // switch (OpenMode) { case EFI_FILE_MODE_READ: break; default: return EFI_WRITE_PROTECTED; } File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; FileName = TrimFilePathToAbsolutePath (FileName); if (FileName == NULL) { return EFI_INVALID_PARAMETER; } if (FileName[0] == L'\\') { FileName++; } // // Check for opening root // if (StrCmp (FileName, L".") == 0 || StrCmp (FileName, L"") == 0) { NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); if (NewFile == NULL) { return EFI_OUT_OF_RESOURCES; } NewFile->Signature = FVFS_FILE_SIGNATURE; NewFile->Instance = Instance; NewFile->FvFileInfo = File->FvFileInfo; CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); InitializeListHead (&NewFile->Link); InsertHeadList (&Instance->FileHead, &NewFile->Link); NewFile->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance); *NewHandle = &NewFile->FileProtocol; return EFI_SUCCESS; } // // Do a linear search for a file in the FV with a matching filename // for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead); !IsNull (&Instance->FileInfoHead, FvFileInfoLink); FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) { FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink); if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileName) == 0) { NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); if (NewFile == NULL) { return EFI_OUT_OF_RESOURCES; } NewFile->Signature = FVFS_FILE_SIGNATURE; NewFile->Instance = Instance; NewFile->FvFileInfo = FvFileInfo; CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); InitializeListHead (&NewFile->Link); InsertHeadList (&Instance->FileHead, &NewFile->Link); *NewHandle = &NewFile->FileProtocol; return EFI_SUCCESS; } } return EFI_NOT_FOUND; }
/** Opens a new file relative to the source file's location. @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to the source location. This would typically be an open handle to a directory. @param NewHandle A pointer to the location to return the opened handle for the new file. @param FileName The Null-terminated string of the name of the file to be opened. The file name may contain the following path modifiers: "\", ".", and "..". @param OpenMode The mode to open the file. The only valid combinations that the file may be opened with are: Read, Read/Write, or Create/Read/Write. @param Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these are the attribute bits for the newly created file. @retval EFI_SUCCESS The file was opened. @retval EFI_NOT_FOUND The specified file could not be found on the device. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_MEDIA_CHANGED The device has a different medium in it or the medium is no longer supported. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED An attempt was made to create a file, or open a file for write when the media is write-protected. @retval EFI_ACCESS_DENIED The service denied access to the file. @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file. @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI FvSimpleFileSystemOpen ( IN EFI_FILE_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes ) { FV_FILESYSTEM_INSTANCE *Instance; FV_FILESYSTEM_FILE *File; FV_FILESYSTEM_FILE *NewFile; FV_FILESYSTEM_FILE_INFO *FvFileInfo; LIST_ENTRY *FvFileInfoLink; EFI_STATUS Status; UINTN FileNameLength; UINTN NewFileNameLength; CHAR16 *FileNameWithExtension; // // Check for a valid mode // switch (OpenMode) { case EFI_FILE_MODE_READ: break; default: return EFI_WRITE_PROTECTED; } File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; FileName = TrimFilePathToAbsolutePath (FileName); if (FileName == NULL) { return EFI_INVALID_PARAMETER; } if (FileName[0] == L'\\') { FileName++; } // // Check for opening root // if (StrCmp (FileName, L".") == 0 || StrCmp (FileName, L"") == 0) { NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); if (NewFile == NULL) { return EFI_OUT_OF_RESOURCES; } NewFile->Signature = FVFS_FILE_SIGNATURE; NewFile->Instance = Instance; NewFile->FvFileInfo = File->FvFileInfo; CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); InitializeListHead (&NewFile->Link); InsertHeadList (&Instance->FileHead, &NewFile->Link); NewFile->DirReadNext = NULL; if (!IsListEmpty (&Instance->FileInfoHead)) { NewFile->DirReadNext = FVFS_GET_FIRST_FILE_INFO (Instance); } *NewHandle = &NewFile->FileProtocol; return EFI_SUCCESS; } // // Do a linear search for a file in the FV with a matching filename // Status = EFI_NOT_FOUND; FvFileInfo = NULL; for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead); !IsNull (&Instance->FileInfoHead, FvFileInfoLink); FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) { FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink); if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileName) == 0) { Status = EFI_SUCCESS; break; } } // If the file has not been found check if the filename exists with an extension // in case there was no extension present. // FvFileSystem adds a 'virtual' extension '.EFI' to EFI applications and drivers // present in the Firmware Volume if (Status == EFI_NOT_FOUND) { FileNameLength = StrLen (FileName); // Does the filename already contain the '.EFI' extension? if (mUnicodeCollation->StriColl (mUnicodeCollation, FileName + FileNameLength - 4, L".efi") != 0) { // No, there was no extension. So add one and search again for the file // NewFileNameLength = FileNameLength + 1 + 4 = (Number of non-null character) + (file extension) + (a null character) NewFileNameLength = FileNameLength + 1 + 4; FileNameWithExtension = AllocatePool (NewFileNameLength * 2); StrCpyS (FileNameWithExtension, NewFileNameLength, FileName); StrCatS (FileNameWithExtension, NewFileNameLength, L".EFI"); for (FvFileInfoLink = GetFirstNode (&Instance->FileInfoHead); !IsNull (&Instance->FileInfoHead, FvFileInfoLink); FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, FvFileInfoLink)) { FvFileInfo = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink); if (mUnicodeCollation->StriColl (mUnicodeCollation, &FvFileInfo->FileInfo.FileName[0], FileNameWithExtension) == 0) { Status = EFI_SUCCESS; break; } } } } if (!EFI_ERROR (Status)) { NewFile = AllocateZeroPool (sizeof (FV_FILESYSTEM_FILE)); if (NewFile == NULL) { return EFI_OUT_OF_RESOURCES; } NewFile->Signature = FVFS_FILE_SIGNATURE; NewFile->Instance = Instance; NewFile->FvFileInfo = FvFileInfo; CopyMem (&NewFile->FileProtocol, &mFileSystemTemplate, sizeof (mFileSystemTemplate)); InitializeListHead (&NewFile->Link); InsertHeadList (&Instance->FileHead, &NewFile->Link); *NewHandle = &NewFile->FileProtocol; return EFI_SUCCESS; } return EFI_NOT_FOUND; }