/** @file Handle operations in files and directories from UDF/ECMA-167 file systems. Copyright (C) 2014-2017 Paulo Alcantara Copyright (c) 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Udf.h" EFI_FILE_PROTOCOL gUdfFileIoOps = { EFI_FILE_PROTOCOL_REVISION, UdfOpen, UdfClose, UdfDelete, UdfRead, UdfWrite, UdfGetPosition, UdfSetPosition, UdfGetInfo, UdfSetInfo, UdfFlush, NULL, NULL, NULL, NULL }; #define _ROOT_FILE(_PrivData) (_PrivData)->Root #define _PARENT_FILE(_PrivData) \ ((_PrivData)->IsRootDirectory ? (_PrivData)->Root : &(_PrivData)->File) #define _FILE(_PrivData) _PARENT_FILE(_PrivData) /** Open the root directory on a volume. @param This Protocol instance pointer. @param Root Returns an Open file handle for the root directory @retval EFI_SUCCESS The device was opened. @retval EFI_UNSUPPORTED This volume does not support the file system. @retval EFI_NO_MEDIA The device has no media. @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. **/ EFI_STATUS EFIAPI UdfOpenVolume ( IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **Root ) { EFI_TPL OldTpl; EFI_STATUS Status; PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; PRIVATE_UDF_FILE_DATA *PrivFileData; OldTpl = gBS->RaiseTPL (TPL_CALLBACK); if ((This == NULL) || (Root == NULL)) { Status = EFI_INVALID_PARAMETER; goto Error_Invalid_Params; } PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This); if (PrivFsData->OpenFiles == 0) { // // There is no more open files. Read volume information again since it was // cleaned up on the last UdfClose() call. // Status = ReadUdfVolumeInformation ( PrivFsData->BlockIo, PrivFsData->DiskIo, &PrivFsData->Volume ); if (EFI_ERROR (Status)) { goto Error_Read_Udf_Volume; } } CleanupFileInformation (&PrivFsData->Root); // // Find root directory file. // Status = FindRootDirectory ( PrivFsData->BlockIo, PrivFsData->DiskIo, &PrivFsData->Volume, &PrivFsData->Root ); if (EFI_ERROR (Status)) { goto Error_Find_Root_Dir; } PrivFileData = (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA)); if (PrivFileData == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error_Alloc_Priv_File_Data; } PrivFileData->Signature = PRIVATE_UDF_FILE_DATA_SIGNATURE; PrivFileData->SimpleFs = This; PrivFileData->Root = &PrivFsData->Root; PrivFileData->IsRootDirectory = TRUE; CopyMem ( (VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps, sizeof (EFI_FILE_PROTOCOL) ); *Root = &PrivFileData->FileIo; PrivFsData->OpenFiles++; gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; Error_Alloc_Priv_File_Data: CleanupFileInformation (&PrivFsData->Root); Error_Find_Root_Dir: Error_Read_Udf_Volume: Error_Invalid_Params: gBS->RestoreTPL (OldTpl); return Status; } /** Opens a new file relative to the source file's location. @param This The protocol instance pointer. @param NewHandle Returns File Handle for FileName. @param FileName Null terminated string. "\", ".", and ".." are supported. @param OpenMode Open mode for file. @param Attributes Only used for EFI_FILE_MODE_CREATE. @retval EFI_SUCCESS The device was opened. @retval EFI_NOT_FOUND The specified file could not be found on the device. @retval EFI_NO_MEDIA The device has no media. @retval EFI_MEDIA_CHANGED The media has changed. @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_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI UdfOpen ( IN EFI_FILE_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes ) { EFI_TPL OldTpl; EFI_STATUS Status; PRIVATE_UDF_FILE_DATA *PrivFileData; PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; CHAR16 FilePath[UDF_PATH_LENGTH]; UDF_FILE_INFO File; PRIVATE_UDF_FILE_DATA *NewPrivFileData; CHAR16 *TempFileName; ZeroMem (FilePath, sizeof FilePath); OldTpl = gBS->RaiseTPL (TPL_CALLBACK); if ((This == NULL) || (NewHandle == NULL) || (FileName == NULL)) { Status = EFI_INVALID_PARAMETER; goto Error_Invalid_Params; } if (OpenMode != EFI_FILE_MODE_READ) { Status = EFI_WRITE_PROTECTED; goto Error_Invalid_Params; } PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs); // // Build full path // if (*FileName == L'\\') { StrCpyS (FilePath, UDF_PATH_LENGTH, FileName); } else { StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName); StrCatS (FilePath, UDF_PATH_LENGTH, L"\\"); StrCatS (FilePath, UDF_PATH_LENGTH, FileName); } MangleFileName (FilePath); if (FilePath[0] == L'\0') { Status = EFI_NOT_FOUND; goto Error_Bad_FileName; } Status = FindFile ( PrivFsData->BlockIo, PrivFsData->DiskIo, &PrivFsData->Volume, FilePath, _ROOT_FILE (PrivFileData), _PARENT_FILE (PrivFileData), &_PARENT_FILE (PrivFileData)->FileIdentifierDesc->Icb, &File ); if (EFI_ERROR (Status)) { goto Error_Find_File; } NewPrivFileData = (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA)); if (NewPrivFileData == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error_Alloc_New_Priv_File_Data; } CopyMem ( (VOID *)NewPrivFileData, (VOID *)PrivFileData, sizeof (PRIVATE_UDF_FILE_DATA) ); CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO)); NewPrivFileData->IsRootDirectory = FALSE; StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath); FileName = NewPrivFileData->AbsoluteFileName; while ((TempFileName = StrStr (FileName, L"\\")) != NULL) { FileName = TempFileName + 1; } StrCpyS (NewPrivFileData->FileName, UDF_FILENAME_LENGTH, FileName); Status = GetFileSize ( PrivFsData->BlockIo, PrivFsData->DiskIo, &PrivFsData->Volume, &NewPrivFileData->File, &NewPrivFileData->FileSize ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "%a: GetFileSize() fails with status - %r.\n", __func__, Status )); goto Error_Get_File_Size; } NewPrivFileData->FilePosition = 0; ZeroMem ( (VOID *)&NewPrivFileData->ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO) ); *NewHandle = &NewPrivFileData->FileIo; PrivFsData->OpenFiles++; gBS->RestoreTPL (OldTpl); return Status; Error_Get_File_Size: FreePool ((VOID *)NewPrivFileData); Error_Alloc_New_Priv_File_Data: CleanupFileInformation (&File); Error_Find_File: Error_Bad_FileName: Error_Invalid_Params: gBS->RestoreTPL (OldTpl); return Status; } /** Read data from the file. @param This Protocol instance pointer. @param BufferSize On input size of buffer, on output amount of data in buffer. @param Buffer The buffer in which data is read. @retval EFI_SUCCESS Data was read. @retval EFI_NO_MEDIA The device has no media. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size. **/ EFI_STATUS EFIAPI UdfRead ( IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { EFI_TPL OldTpl; EFI_STATUS Status; PRIVATE_UDF_FILE_DATA *PrivFileData; PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; UDF_VOLUME_INFO *Volume; UDF_FILE_INFO *Parent; UDF_READ_DIRECTORY_INFO *ReadDirInfo; EFI_BLOCK_IO_PROTOCOL *BlockIo; EFI_DISK_IO_PROTOCOL *DiskIo; UDF_FILE_INFO FoundFile; UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc; VOID *NewFileEntryData; CHAR16 FileName[UDF_FILENAME_LENGTH]; UINT64 FileSize; UINT64 BufferSizeUint64; ZeroMem (FileName, sizeof FileName); OldTpl = gBS->RaiseTPL (TPL_CALLBACK); if ((This == NULL) || (BufferSize == NULL) || ((*BufferSize != 0) && (Buffer == NULL))) { Status = EFI_INVALID_PARAMETER; goto Error_Invalid_Params; } PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs); BlockIo = PrivFsData->BlockIo; DiskIo = PrivFsData->DiskIo; Volume = &PrivFsData->Volume; ReadDirInfo = &PrivFileData->ReadDirInfo; NewFileIdentifierDesc = NULL; NewFileEntryData = NULL; Parent = _PARENT_FILE (PrivFileData); Status = EFI_VOLUME_CORRUPTED; if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) { if (PrivFileData->FilePosition > PrivFileData->FileSize) { // // File's position is beyond the EOF // Status = EFI_DEVICE_ERROR; goto Error_File_Beyond_The_Eof; } if (PrivFileData->FilePosition == PrivFileData->FileSize) { *BufferSize = 0; Status = EFI_SUCCESS; goto Done; } BufferSizeUint64 = *BufferSize; Status = ReadFileData ( BlockIo, DiskIo, Volume, Parent, PrivFileData->FileSize, &PrivFileData->FilePosition, Buffer, &BufferSizeUint64 ); ASSERT (BufferSizeUint64 <= MAX_UINTN); *BufferSize = (UINTN)BufferSizeUint64; } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) { if ((ReadDirInfo->FidOffset == 0) && (PrivFileData->FilePosition > 0)) { Status = EFI_DEVICE_ERROR; *BufferSize = 0; goto Done; } for ( ; ;) { Status = ReadDirectoryEntry ( BlockIo, DiskIo, Volume, &Parent->FileIdentifierDesc->Icb, Parent->FileEntry, ReadDirInfo, &NewFileIdentifierDesc ); if (EFI_ERROR (Status)) { if (Status == EFI_DEVICE_ERROR) { FreePool (ReadDirInfo->DirectoryData); ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO)); *BufferSize = 0; Status = EFI_SUCCESS; } goto Done; } // // After calling function ReadDirectoryEntry(), if 'NewFileIdentifierDesc' // is NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the // code reaches here, 'NewFileIdentifierDesc' must be not NULL. // // The ASSERT here is for addressing a false positive NULL pointer // dereference issue raised from static analysis. // ASSERT (NewFileIdentifierDesc != NULL); if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) { break; } FreePool ((VOID *)NewFileIdentifierDesc); } Status = FindFileEntry ( BlockIo, DiskIo, Volume, &NewFileIdentifierDesc->Icb, &NewFileEntryData ); if (EFI_ERROR (Status)) { goto Error_Find_Fe; } ASSERT (NewFileEntryData != NULL); if (FE_ICB_FILE_TYPE (NewFileEntryData) == UdfFileEntrySymlink) { Status = ResolveSymlink ( BlockIo, DiskIo, Volume, Parent, NewFileEntryData, &FoundFile ); if (EFI_ERROR (Status)) { goto Error_Resolve_Symlink; } FreePool ((VOID *)NewFileEntryData); NewFileEntryData = FoundFile.FileEntry; Status = GetFileNameFromFid (NewFileIdentifierDesc, ARRAY_SIZE (FileName), FileName); if (EFI_ERROR (Status)) { FreePool ((VOID *)FoundFile.FileIdentifierDesc); goto Error_Get_FileName; } FreePool ((VOID *)NewFileIdentifierDesc); NewFileIdentifierDesc = FoundFile.FileIdentifierDesc; } else { FoundFile.FileIdentifierDesc = NewFileIdentifierDesc; FoundFile.FileEntry = NewFileEntryData; Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, ARRAY_SIZE (FileName), FileName); if (EFI_ERROR (Status)) { goto Error_Get_FileName; } } Status = GetFileSize ( BlockIo, DiskIo, Volume, &FoundFile, &FileSize ); if (EFI_ERROR (Status)) { goto Error_Get_File_Size; } Status = SetFileInfo ( &FoundFile, FileSize, FileName, BufferSize, Buffer ); if (EFI_ERROR (Status)) { goto Error_Set_File_Info; } PrivFileData->FilePosition++; Status = EFI_SUCCESS; } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) { // // Code should never reach here. // ASSERT (FALSE); Status = EFI_DEVICE_ERROR; } Error_Set_File_Info: Error_Get_File_Size: Error_Get_FileName: Error_Resolve_Symlink: if (NewFileEntryData != NULL) { FreePool (NewFileEntryData); } Error_Find_Fe: if (NewFileIdentifierDesc != NULL) { FreePool ((VOID *)NewFileIdentifierDesc); } Done: Error_File_Beyond_The_Eof: Error_Invalid_Params: gBS->RestoreTPL (OldTpl); return Status; } /** Close the file handle. @param This Protocol instance pointer. @retval EFI_SUCCESS The file was closed. **/ EFI_STATUS EFIAPI UdfClose ( IN EFI_FILE_PROTOCOL *This ) { EFI_TPL OldTpl; EFI_STATUS Status; PRIVATE_UDF_FILE_DATA *PrivFileData; OldTpl = gBS->RaiseTPL (TPL_CALLBACK); Status = EFI_SUCCESS; if (This == NULL) { Status = EFI_INVALID_PARAMETER; goto Exit; } PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); if (!PrivFileData->IsRootDirectory) { CleanupFileInformation (&PrivFileData->File); if (PrivFileData->ReadDirInfo.DirectoryData != NULL) { FreePool (PrivFileData->ReadDirInfo.DirectoryData); } } FreePool ((VOID *)PrivFileData); Exit: gBS->RestoreTPL (OldTpl); return Status; } /** Close and delete the file handle. @param This Protocol instance pointer. @retval EFI_SUCCESS The file was closed and deleted. @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. **/ EFI_STATUS EFIAPI UdfDelete ( IN EFI_FILE_PROTOCOL *This ) { PRIVATE_UDF_FILE_DATA *PrivFileData; if (This == NULL) { return EFI_INVALID_PARAMETER; } PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); (VOID)PrivFileData->FileIo.Close (This); return EFI_WARN_DELETE_FAILURE; } /** Write data to a file. @param This Protocol instance pointer. @param BufferSize On input size of buffer, on output amount of data in buffer. @param Buffer The buffer in which data to write. @retval EFI_SUCCESS Data was written. @retval EFI_UNSUPPORTED Writes to Open directory are not supported. @retval EFI_NO_MEDIA The device has no media. @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 device is write protected. @retval EFI_ACCESS_DENIED The file was open for read only. @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI UdfWrite ( IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, IN VOID *Buffer ) { return EFI_UNSUPPORTED; } /** Get file's current position. @param This Protocol instance pointer. @param Position Byte position from the start of the file. @retval EFI_SUCCESS Position was updated. @retval EFI_UNSUPPORTED Seek request for directories is not valid. **/ EFI_STATUS EFIAPI UdfGetPosition ( IN EFI_FILE_PROTOCOL *This, OUT UINT64 *Position ) { PRIVATE_UDF_FILE_DATA *PrivFileData; if ((This == NULL) || (Position == NULL)) { return EFI_INVALID_PARAMETER; } PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); // // As per UEFI spec, if the file handle is a directory, then the current file // position has no meaning and the operation is not supported. // if (IS_FID_DIRECTORY_FILE (PrivFileData->File.FileIdentifierDesc)) { return EFI_UNSUPPORTED; } // // The file is not a directory. So, return its position. // *Position = PrivFileData->FilePosition; return EFI_SUCCESS; } /** Set file's current position. @param This Protocol instance pointer. @param Position Byte position from the start of the file. @retval EFI_SUCCESS Position was updated. @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. **/ EFI_STATUS EFIAPI UdfSetPosition ( IN EFI_FILE_PROTOCOL *This, IN UINT64 Position ) { EFI_STATUS Status; PRIVATE_UDF_FILE_DATA *PrivFileData; UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc; if (This == NULL) { return EFI_INVALID_PARAMETER; } Status = EFI_UNSUPPORTED; PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); FileIdentifierDesc = _FILE (PrivFileData)->FileIdentifierDesc; ASSERT (FileIdentifierDesc != NULL); if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) { // // If the file handle is a directory, the _only_ position that may be set is // zero. This has no effect of starting the read proccess of the directory // entries over. // if (Position == 0) { PrivFileData->FilePosition = Position; PrivFileData->ReadDirInfo.FidOffset = 0; Status = EFI_SUCCESS; } } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) { // // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be // set to the EOF. // if (Position == 0xFFFFFFFFFFFFFFFF) { PrivFileData->FilePosition = PrivFileData->FileSize; } else { PrivFileData->FilePosition = Position; } Status = EFI_SUCCESS; } return Status; } /** Get information about a file. @param This Protocol instance pointer. @param InformationType Type of information to return in Buffer. @param BufferSize On input size of buffer, on output amount of data in buffer. @param Buffer The buffer to return data. @retval EFI_SUCCESS Data was returned. @retval EFI_UNSUPPORTED InformationType is not supported. @retval EFI_NO_MEDIA The device has no media. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED The device is write protected. @retval EFI_ACCESS_DENIED The file was open for read only. @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. **/ EFI_STATUS EFIAPI UdfGetInfo ( IN EFI_FILE_PROTOCOL *This, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer ) { EFI_STATUS Status; PRIVATE_UDF_FILE_DATA *PrivFileData; PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData; EFI_FILE_SYSTEM_INFO *FileSystemInfo; UINTN FileSystemInfoLength; UINT64 VolumeSize; UINT64 FreeSpaceSize; EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel; UINTN FileSystemVolumeLabelLength; CHAR16 VolumeLabel[64]; if ((This == NULL) || (InformationType == NULL) || (BufferSize == NULL) || ((*BufferSize != 0) && (Buffer == NULL))) { return EFI_INVALID_PARAMETER; } PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This); PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs); Status = EFI_UNSUPPORTED; if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { Status = SetFileInfo ( _FILE (PrivFileData), PrivFileData->FileSize, PrivFileData->FileName, BufferSize, Buffer ); } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel); if (EFI_ERROR (Status)) { return Status; } FileSystemInfoLength = StrSize (VolumeLabel) + sizeof (EFI_FILE_SYSTEM_INFO); if (*BufferSize < FileSystemInfoLength) { *BufferSize = FileSystemInfoLength; return EFI_BUFFER_TOO_SMALL; } FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer; StrCpyS ( FileSystemInfo->VolumeLabel, (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_INFO) / sizeof (CHAR16), VolumeLabel ); Status = GetVolumeSize ( PrivFsData->BlockIo, PrivFsData->DiskIo, &PrivFsData->Volume, &VolumeSize, &FreeSpaceSize ); if (EFI_ERROR (Status)) { return Status; } FileSystemInfo->Size = FileSystemInfoLength; FileSystemInfo->ReadOnly = TRUE; FileSystemInfo->BlockSize = PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize; FileSystemInfo->VolumeSize = VolumeSize; FileSystemInfo->FreeSpace = FreeSpaceSize; *BufferSize = FileSystemInfoLength; Status = EFI_SUCCESS; } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel); if (EFI_ERROR (Status)) { return Status; } FileSystemVolumeLabelLength = StrSize (VolumeLabel) + sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL); if (*BufferSize < FileSystemVolumeLabelLength) { *BufferSize = FileSystemVolumeLabelLength; return EFI_BUFFER_TOO_SMALL; } FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer; StrCpyS ( FileSystemVolumeLabel->VolumeLabel, (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL) / sizeof (CHAR16), VolumeLabel ); Status = EFI_SUCCESS; } return Status; } /** Set information about a file. @param This Protocol instance pointer. @param InformationType Type of information in Buffer. @param BufferSize Size of buffer. @param Buffer The data to write. @retval EFI_SUCCESS Data was set. @retval EFI_UNSUPPORTED InformationType is not supported. @retval EFI_NO_MEDIA The device has no media. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED The device is write protected. @retval EFI_ACCESS_DENIED The file was open for read only. **/ EFI_STATUS EFIAPI UdfSetInfo ( IN EFI_FILE_PROTOCOL *This, IN EFI_GUID *InformationType, IN UINTN BufferSize, IN VOID *Buffer ) { return EFI_WRITE_PROTECTED; } /** Flush data back for the file handle. @param This Protocol instance pointer. @retval EFI_SUCCESS Data was flushed. @retval EFI_UNSUPPORTED Writes to Open directory are not supported. @retval EFI_NO_MEDIA The device has no media. @retval EFI_DEVICE_ERROR The device reported an error. @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. @retval EFI_WRITE_PROTECTED The device is write protected. @retval EFI_ACCESS_DENIED The file was open for read only. @retval EFI_VOLUME_FULL The volume is full. **/ EFI_STATUS EFIAPI UdfFlush ( IN EFI_FILE_PROTOCOL *This ) { return EFI_WRITE_PROTECTED; }