/** 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; }
/** Closes a specified file handle. @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to close. @retval EFI_SUCCESS The file was closed. **/ EFI_STATUS EFIAPI FvSimpleFileSystemClose ( IN EFI_FILE_PROTOCOL *This ) { FV_FILESYSTEM_INSTANCE *Instance; FV_FILESYSTEM_FILE *File; File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; if (File != Instance->Root) { RemoveEntryList (&File->Link); FreePool (File); } return EFI_SUCCESS; }
/** Returns a file's current position. @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to get the current position on. @param Position The address to return the file's current position value. @retval EFI_SUCCESS The position was returned. @retval EFI_UNSUPPORTED The request is not valid on open directories. @retval EFI_DEVICE_ERROR An attempt was made to get the position from a deleted file. **/ EFI_STATUS EFIAPI FvSimpleFileSystemGetPosition ( IN EFI_FILE_PROTOCOL *This, OUT 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) { return EFI_UNSUPPORTED; } else { *Position = File->Position; return EFI_SUCCESS; } }
/** Writes data to a file. @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to write data to. @param BufferSize On input, the size of the Buffer. On output, the amount of data actually written. In both cases, the size is measured in bytes. @param Buffer The buffer of data to write. @retval EFI_SUCCESS Data was written. @retval EFI_UNSUPPORTED Writes to open directory files are not supported. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED The file or medium is write-protected. @retval EFI_ACCESS_DENIED The file was opened read only. @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI FvSimpleFileSystemWrite ( IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, IN VOID *Buffer ) { FV_FILESYSTEM_INSTANCE *Instance; FV_FILESYSTEM_FILE *File; File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; if (File->FvFileInfo == Instance->Root->FvFileInfo) { return EFI_UNSUPPORTED; } else { return EFI_WRITE_PROTECTED; } }
/** Returns information about a file. @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle the requested information is for. @param InformationType The type identifier for the information being requested. @param BufferSize On input, the size of Buffer. On output, the amount of data returned in Buffer. In both cases, the size is measured in bytes. @param Buffer A pointer to the data buffer to return. The buffer's type is indicated by InformationType. @retval EFI_SUCCESS The information was returned. @retval EFI_UNSUPPORTED The InformationType is not known. @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_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. BufferSize has been updated with the size needed to complete the request. **/ EFI_STATUS EFIAPI FvSimpleFileSystemGetInfo ( IN EFI_FILE_PROTOCOL *This, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { FV_FILESYSTEM_FILE *File; EFI_FILE_SYSTEM_INFO *FsInfoOut; EFI_FILE_SYSTEM_VOLUME_LABEL *FsVolumeLabel; FV_FILESYSTEM_INSTANCE *Instance; UINTN Size; EFI_STATUS Status; File = FVFS_FILE_FROM_FILE_THIS (This); if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { // // Return filesystem info // Instance = File->Instance; Size = sizeof (EFI_FILE_SYSTEM_INFO) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16); if (*BufferSize < Size) { *BufferSize = Size; return EFI_BUFFER_TOO_SMALL; } // // Cast output buffer for convenience // FsInfoOut = (EFI_FILE_SYSTEM_INFO *) Buffer; CopyMem (FsInfoOut, &mFsInfoTemplate, sizeof (EFI_FILE_SYSTEM_INFO)); Status = StrnCpyS (FsInfoOut->VolumeLabel, (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)) / sizeof (CHAR16), Instance->VolumeLabel, StrLen (Instance->VolumeLabel)); ASSERT_EFI_ERROR (Status); FsInfoOut->Size = Size; return Status; } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { // // Return file info // return FvFsGetFileInfo (File->FvFileInfo, BufferSize, (EFI_FILE_INFO *) Buffer); } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { // // Return Volume Label // Instance = File->Instance; Size = sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL) + StrSize (Instance->VolumeLabel) - sizeof (CHAR16);; if (*BufferSize < Size) { *BufferSize = Size; return EFI_BUFFER_TOO_SMALL; } FsVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL*) Buffer; Status = StrnCpyS (FsVolumeLabel->VolumeLabel, (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_VOLUME_LABEL, VolumeLabel)) / sizeof (CHAR16), Instance->VolumeLabel, StrLen (Instance->VolumeLabel)); ASSERT_EFI_ERROR (Status); return Status; } else { return EFI_UNSUPPORTED; } }
/** Reads data from a file. @param This A pointer to the EFI_FILE_PROTOCOL instance that is the file handle to read data from. @param BufferSize On input, the size of the Buffer. On output, the amount of data returned in Buffer. In both cases, the size is measured in bytes. @param Buffer The buffer into which the data is read. @retval EFI_SUCCESS Data was read. @retval EFI_NO_MEDIA The device has no medium. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_DEVICE_ERROR An attempt was made to read from a deleted file. @retval EFI_DEVICE_ERROR On entry, the current file position is beyond the end of the file. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. BufferSize has been updated with the size needed to complete the request. **/ EFI_STATUS EFIAPI FvSimpleFileSystemRead ( IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { FV_FILESYSTEM_INSTANCE *Instance; FV_FILESYSTEM_FILE *File; EFI_STATUS Status; LIST_ENTRY *FvFileInfoLink; VOID *FileBuffer; UINTN FileSize; File = FVFS_FILE_FROM_FILE_THIS (This); Instance = File->Instance; if (File->FvFileInfo == Instance->Root->FvFileInfo) { if (File->DirReadNext) { // // Directory read: populate Buffer with an EFI_FILE_INFO // Status = FvFsGetFileInfo (File->DirReadNext, BufferSize, Buffer); if (!EFI_ERROR (Status)) { // // Successfully read a directory entry, now update the pointer to the // next file, which will be read on the next call to this function // FvFileInfoLink = GetNextNode (&Instance->FileInfoHead, &File->DirReadNext->Link); if (IsNull (&Instance->FileInfoHead, FvFileInfoLink)) { // // No more files left // File->DirReadNext = NULL; } else { File->DirReadNext = FVFS_FILE_INFO_FROM_LINK (FvFileInfoLink); } } return Status; } else { // // Directory read. All entries have been read, so return a zero-size // buffer. // *BufferSize = 0; return EFI_SUCCESS; } } else { FileSize = (UINTN)File->FvFileInfo->FileInfo.FileSize; FileBuffer = AllocateZeroPool (FileSize); if (FileBuffer == NULL) { return EFI_DEVICE_ERROR; } Status = FvFsReadFile (File->Instance->FvProtocol, File->FvFileInfo, &FileSize, &FileBuffer); if (EFI_ERROR (Status)) { return EFI_DEVICE_ERROR; } if (*BufferSize + File->Position > FileSize) { *BufferSize = (UINTN)(FileSize - File->Position); } CopyMem (Buffer, (UINT8*)FileBuffer + File->Position, *BufferSize); File->Position += *BufferSize; return EFI_SUCCESS; } }
/** 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; }