EFI_STATUS EFIAPI GetVolumeHandleWithDir(CHAR16 *SearchDir, OUT EFI_HANDLE *Handle) { EFI_STATUS Status; UINTN HandlesSize; UINTN Idx; EFI_HANDLE *Handles; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FS = NULL; EFI_FILE_PROTOCOL *FP = NULL; EFI_FILE_PROTOCOL *FP2 = NULL; // get all handles with EFI_SIMPLE_FILE_SYSTEM_PROTOCOL Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandlesSize, &Handles); if (EFI_ERROR(Status)) { Print(L"LocateHandleBuffer: %r\n", Status); return Status; } Print(L"LocateHandleBuffer: %r, got %d handles\n", Status, HandlesSize); // find handle that contains SearchDir for (Idx = 0; Idx < HandlesSize; Idx++) { // get EFI_SIMPLE_FILE_SYSTEM_PROTOCOL first Print(L"Trying handle: %p\n", Handles[Idx]); Status = gBS->OpenProtocol(Handles[Idx], &gEfiSimpleFileSystemProtocolGuid, (void **)&FS, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (EFI_ERROR(Status)) { Print(L"OpenProtocol(gEfiSimpleFileSystemProtocolGuid): %r\n", Status); continue; } // open volume Status = FS->OpenVolume(FS, &FP); if (EFI_ERROR(Status)) { Print(L"OpenVolume(): %r\n", Status); gBS->CloseProtocol(Handles[Idx], &gEfiSimpleFileSystemProtocolGuid, gImageHandle, NULL); continue; } // try to open injection dir Status = FP->Open(FP, &FP2, SearchDir, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) { Print(L"Open(%s): %r\n", SearchDir, Status); FP->Close(FP); gBS->CloseProtocol(Handles[Idx], &gEfiSimpleFileSystemProtocolGuid, gImageHandle, NULL); continue; } // we have found it - close it and return handle FP2->Close(FP2); FP->Close(FP); *Handle = Handles[Idx]; return EFI_SUCCESS; } // not found return EFI_NOT_FOUND; }
/** Set the size of a file. This is a helper function for SetFileInfo(). @param[in] Instance A pointer to the description of the volume the file belongs to. @param[in] File A pointer to the description of the file. @param[in] NewSize The requested new size for the file. @retval EFI_SUCCESS The size was set. @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed. **/ STATIC EFI_STATUS SetFileSize ( IN BOOTMON_FS_INSTANCE *Instance, IN BOOTMON_FS_FILE *BootMonFsFile, IN UINTN NewSize ) { EFI_STATUS Status; UINT32 OldSize; LIST_ENTRY *RegionToFlushLink; LIST_ENTRY *NextRegionToFlushLink; BOOTMON_FS_FILE_REGION *Region; EFI_FILE_PROTOCOL *File; CHAR8 *Buffer; UINTN BufferSize; UINT64 StoredPosition; OldSize = BootMonFsFile->Info->FileSize; // // In case of file truncation, force the regions waiting for writing to // not overflow the new size of the file. // if (NewSize < OldSize) { for (RegionToFlushLink = GetFirstNode (&BootMonFsFile->RegionToFlushLink); !IsNull (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink); ) { NextRegionToFlushLink = GetNextNode (&BootMonFsFile->RegionToFlushLink, RegionToFlushLink); Region = (BOOTMON_FS_FILE_REGION*)RegionToFlushLink; if (Region->Offset > NewSize) { RemoveEntryList (RegionToFlushLink); FreePool (Region->Buffer); FreePool (Region); } else { Region->Size = MIN (Region->Size, NewSize - Region->Offset); } RegionToFlushLink = NextRegionToFlushLink; } } else if (NewSize > OldSize) { // Increasing a file's size is potentially complicated as it may require // moving the image description on media. The simplest way to do it is to // seek past the end of the file (which is valid in UEFI) and perform a // Write. File = &BootMonFsFile->File; // Save position Status = File->GetPosition (File, &StoredPosition); if (EFI_ERROR (Status)) { return Status; } // Set position at the end of the file Status = File->SetPosition (File, OldSize); if (EFI_ERROR (Status)) { return Status; } BufferSize = NewSize - OldSize; Buffer = AllocateZeroPool (BufferSize); if (Buffer == NULL) { return EFI_OUT_OF_RESOURCES; } Status = File->Write (File, &BufferSize, Buffer); FreePool (Buffer); if (EFI_ERROR (Status)) { return Status; } // Restore saved position Status = File->SetPosition (File, StoredPosition); if (EFI_ERROR (Status)) { return Status; } } BootMonFsFile->Info->FileSize = NewSize; return EFI_SUCCESS; }
/** print out the standard format output volume entry. @param[in] TheList a list of files from the volume. **/ EFI_STATUS PrintSfoVolumeInfoTableEntry( IN CONST EFI_SHELL_FILE_INFO *TheList ) { EFI_STATUS Status; EFI_SHELL_FILE_INFO *Node; CHAR16 *DirectoryName; EFI_FILE_SYSTEM_INFO *SysInfo; UINTN SysInfoSize; SHELL_FILE_HANDLE ShellFileHandle; EFI_FILE_PROTOCOL *EfiFpHandle; // // Get the first valid handle (directories) // for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link) ; !IsNull(&TheList->Link, &Node->Link) && Node->Handle == NULL ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&TheList->Link, &Node->Link) ); if (Node->Handle == NULL) { DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link))->FullName); // // We need to open something up to get system information // Status = gEfiShellProtocol->OpenFileByName( DirectoryName, &ShellFileHandle, EFI_FILE_MODE_READ ); ASSERT_EFI_ERROR(Status); FreePool(DirectoryName); // // Get the Volume Info from ShellFileHandle // SysInfo = NULL; SysInfoSize = 0; EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle); Status = EfiFpHandle->GetInfo( EfiFpHandle, &gEfiFileSystemInfoGuid, &SysInfoSize, SysInfo ); if (Status == EFI_BUFFER_TOO_SMALL) { SysInfo = AllocateZeroPool(SysInfoSize); Status = EfiFpHandle->GetInfo( EfiFpHandle, &gEfiFileSystemInfoGuid, &SysInfoSize, SysInfo ); } ASSERT_EFI_ERROR(Status); gEfiShellProtocol->CloseFile(ShellFileHandle); } else { // // Get the Volume Info from Node->Handle // SysInfo = NULL; SysInfoSize = 0; EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle); Status = EfiFpHandle->GetInfo( EfiFpHandle, &gEfiFileSystemInfoGuid, &SysInfoSize, SysInfo ); if (Status == EFI_BUFFER_TOO_SMALL) { SysInfo = AllocateZeroPool(SysInfoSize); Status = EfiFpHandle->GetInfo( EfiFpHandle, &gEfiFileSystemInfoGuid, &SysInfoSize, SysInfo ); } ASSERT_EFI_ERROR(Status); } ShellPrintHiiEx ( -1, -1, NULL, STRING_TOKEN (STR_GEN_SFO_HEADER), gShellLevel2HiiHandle, L"ls" ); // // print VolumeInfo table // ASSERT(SysInfo != NULL); ShellPrintHiiEx ( 0, gST->ConOut->Mode->CursorRow, NULL, STRING_TOKEN (STR_LS_SFO_VOLINFO), gShellLevel2HiiHandle, SysInfo->VolumeLabel, SysInfo->VolumeSize, SysInfo->ReadOnly?L"TRUE":L"FALSE", SysInfo->FreeSpace, SysInfo->BlockSize ); SHELL_FREE_NON_NULL(SysInfo); return (Status); }
/** Function to Copy one file to another location If the destination exists the user will be prompted and the result put into *resp @param[in] Source pointer to source file name @param[in] Dest pointer to destination file name @param[out] Resp pointer to response from question. Pass back on looped calling @param[in] SilentMode whether to run in quiet mode or not @retval SHELL_SUCCESS The source file was copied to the destination **/ SHELL_STATUS EFIAPI CopySingleFile( IN CONST CHAR16 *Source, IN CONST CHAR16 *Dest, OUT VOID **Resp, IN BOOLEAN SilentMode ) { VOID *Response; UINTN ReadSize; SHELL_FILE_HANDLE SourceHandle; SHELL_FILE_HANDLE DestHandle; EFI_STATUS Status; VOID *Buffer; CHAR16 *TempName; UINTN Size; EFI_SHELL_FILE_INFO *List; SHELL_STATUS ShellStatus; UINT64 SourceFileSize; UINT64 DestFileSize; EFI_FILE_PROTOCOL *DestVolumeFP; EFI_FILE_SYSTEM_INFO *DestVolumeInfo; UINTN DestVolumeInfoSize; ASSERT(Resp != NULL); SourceHandle = NULL; DestHandle = NULL; Response = *Resp; List = NULL; DestVolumeInfo = NULL; ReadSize = PcdGet16(PcdShellFileOperationSize); // Why bother copying a file to itself if (StrCmp(Source, Dest) == 0) { return (SHELL_SUCCESS); } // // Open destination file without create // Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); // // close file // if (DestHandle != NULL) { ShellCloseFile(&DestHandle); DestHandle = NULL; } // // if the destination file existed check response and possibly prompt user // if (!EFI_ERROR(Status)) { if (Response == NULL && !SilentMode) { Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response); } // // possibly return based on response // if (!SilentMode) { switch (*(SHELL_PROMPT_RESPONSE*)Response) { case ShellPromptResponseNo: // // return success here so we dont stop the process // return (SHELL_SUCCESS); case ShellPromptResponseCancel: *Resp = Response; // // indicate to stop everything // return (SHELL_ABORTED); case ShellPromptResponseAll: *Resp = Response; case ShellPromptResponseYes: break; default: return SHELL_ABORTED; } } } if (ShellIsDirectory(Source) == EFI_SUCCESS) { Status = ShellCreateDirectory(Dest, &DestHandle); if (EFI_ERROR(Status)) { return (SHELL_ACCESS_DENIED); } // // Now copy all the files under the directory... // TempName = NULL; Size = 0; StrnCatGrow(&TempName, &Size, Source, 0); StrnCatGrow(&TempName, &Size, L"\\*", 0); if (TempName != NULL) { ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List); *TempName = CHAR_NULL; StrnCatGrow(&TempName, &Size, Dest, 0); StrnCatGrow(&TempName, &Size, L"\\", 0); ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp); ShellCloseFileMetaArg(&List); SHELL_FREE_NON_NULL(TempName); Size = 0; } } else { // // open file with create enabled // Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); if (EFI_ERROR(Status)) { return (SHELL_ACCESS_DENIED); } // // open source file // Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0); ASSERT_EFI_ERROR(Status); // //get file size of source file and freespace available on destination volume // ShellGetFileSize(SourceHandle, &SourceFileSize); ShellGetFileSize(DestHandle, &DestFileSize); // //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space // if(DestFileSize < SourceFileSize){ SourceFileSize -= DestFileSize; } else { SourceFileSize = 0; } // //get the system volume info to check the free space // DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle); DestVolumeInfo = NULL; DestVolumeInfoSize = 0; Status = DestVolumeFP->GetInfo( DestVolumeFP, &gEfiFileSystemInfoGuid, &DestVolumeInfoSize, DestVolumeInfo ); if (Status == EFI_BUFFER_TOO_SMALL) { DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize); Status = DestVolumeFP->GetInfo( DestVolumeFP, &gEfiFileSystemInfoGuid, &DestVolumeInfoSize, DestVolumeInfo ); } // //check if enough space available on destination drive to complete copy // if (DestVolumeInfo->FreeSpace < SourceFileSize) { // //not enough space on destination directory to copy file // SHELL_FREE_NON_NULL(DestVolumeInfo); ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle); return(SHELL_VOLUME_FULL); } else { // // copy data between files // Buffer = AllocateZeroPool(ReadSize); ASSERT(Buffer != NULL); while (ReadSize == PcdGet16(PcdShellFileOperationSize) && !EFI_ERROR(Status)) { Status = ShellReadFile(SourceHandle, &ReadSize, Buffer); Status = ShellWriteFile(DestHandle, &ReadSize, Buffer); } } SHELL_FREE_NON_NULL(DestVolumeInfo); } // // close files // if (DestHandle != NULL) { ShellCloseFile(&DestHandle); DestHandle = NULL; } if (SourceHandle != NULL) { ShellCloseFile(&SourceHandle); SourceHandle = NULL; } // // return // return (SHELL_SUCCESS); }
EFI_STATUS BdsFileSystemLoadImage ( IN EFI_DEVICE_PATH *DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH *RemainingDevicePath, IN EFI_ALLOCATE_TYPE Type, IN OUT EFI_PHYSICAL_ADDRESS* Image, OUT UINTN *ImageSize ) { FILEPATH_DEVICE_PATH* FilePathDevicePath; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; EFI_FILE_PROTOCOL *Fs; EFI_STATUS Status; EFI_FILE_INFO *FileInfo; EFI_FILE_PROTOCOL *File; UINTN Size; ASSERT (IS_DEVICE_PATH_NODE(RemainingDevicePath,MEDIA_DEVICE_PATH,MEDIA_FILEPATH_DP)); FilePathDevicePath = (FILEPATH_DEVICE_PATH*)RemainingDevicePath; Status = gBS->HandleProtocol(Handle,&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsProtocol); if (EFI_ERROR(Status)) { return Status; } // Try to Open the volume and get root directory Status = FsProtocol->OpenVolume (FsProtocol, &Fs); if (EFI_ERROR(Status)) { return Status; } File = NULL; Status = Fs->Open(Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) { return Status; } Size = 0; File->GetInfo(File, &gEfiFileInfoGuid, &Size, NULL); FileInfo = AllocatePool (Size); Status = File->GetInfo(File, &gEfiFileInfoGuid, &Size, FileInfo); if (EFI_ERROR(Status)) { return Status; } // Get the file size Size = FileInfo->FileSize; if (ImageSize) { *ImageSize = Size; } FreePool(FileInfo); Status = gBS->AllocatePages (Type, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); // Try to allocate in any pages if failed to allocate memory at the defined location if ((Status == EFI_OUT_OF_RESOURCES) && (Type != AllocateAnyPages)) { Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesCode, EFI_SIZE_TO_PAGES(Size), Image); } if (!EFI_ERROR(Status)) { Status = File->Read (File, &Size, (VOID*)(UINTN)(*Image)); } return Status; }
EFI_STATUS LoadFile(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* systab, CHAR16* filename, VOID** dataPtr, UINTN* size, EFI_DEVICE_PATH_PROTOCOL** dev_path) { EFI_GUID LoadedImageProtocolGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; EFI_GUID FileInfoGuid = EFI_FILE_INFO_ID; EFI_GUID FileSystemGuid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; EFI_STATUS res; EFI_BOOT_SERVICES* BS = systab->BootServices; //get image info EFI_LOADED_IMAGE_PROTOCOL* img_proto; res = BS->HandleProtocol(ImageHandle, &LoadedImageProtocolGuid, (void**) &img_proto); if (res) { ErrorPrint(L"Failed to get image protocol. (Error %d)\r\n", res); return EFI_LOAD_ERROR ; } EFI_HANDLE img_device_handle = img_proto->DeviceHandle; //Get filesystem protocol from device EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* fs_proto; res = BS->HandleProtocol(img_device_handle, &FileSystemGuid, (VOID**) &fs_proto); if (res) { ErrorPrint(L"Failed to get file system protocol. (Error %d)\r\n", res); return EFI_LOAD_ERROR ; } //open volume EFI_FILE_PROTOCOL* volume; res = fs_proto->OpenVolume(fs_proto, &volume); if (res) { ErrorPrint(L"Failed to open file volume. (Error %d)\r\n", res); return EFI_LOAD_ERROR ; } //open file EFI_FILE_PROTOCOL* file; res = volume->Open(volume, &file, filename, EFI_FILE_MODE_READ, 0); if (res) { //don't print error here //ErrorPrint(L"Failed to open file '%s'. (Error %d)\r\n", filename, res); return EFI_NOT_FOUND ; } //get file info, two try process EFI_FILE_INFO* file_info = NULL; UINTN file_info_size = 0; res = file->GetInfo(file, &FileInfoGuid, &file_info_size, NULL ); if (res != EFI_BUFFER_TOO_SMALL ) { ErrorPrint(L"Failed to stat file '%s'. (Error %d)\r\n", filename, res); return EFI_NOT_FOUND ; } res = BS->AllocatePool(EfiLoaderData, file_info_size, (void**) &file_info); if (res) { ErrorPrint(L"Failed to allocate file info memory. (Error %d)\r\n", res); return EFI_OUT_OF_RESOURCES ; } res = file->GetInfo(file, &FileInfoGuid, &file_info_size, (void*) file_info); if (res) { BS->FreePool(file_info); ErrorPrint(L"Failed to stat file '%s'. (Error %d)\r\n", filename, res); return EFI_NOT_FOUND ; } if (dev_path != NULL ) { *dev_path = FileDevicePath(img_device_handle, filename); } UINT64 file_size = file_info->FileSize; BS->FreePool(file_info); file_info = NULL; void* data = NULL; res = BS->AllocatePool(EfiLoaderData, file_size, (void**) &data); if (res) { ErrorPrint(L"Failed to allocate file data memory. (Error %d)\r\n", res); return EFI_OUT_OF_RESOURCES ; } //read the file res = file->Read(file, &file_size, (void*) data); if (res) { BS->FreePool(data); ErrorPrint(L"Failed to read file '%s'. (Error %d)\r\n", filename, res); return EFI_NOT_FOUND ; } //close the file file->Close(file); volume->Close(volume); //set the pointer and data size *dataPtr = data; *size = file_size; //return success return EFI_SUCCESS; }
// Set the file's size (NB "size", not "physical size"). If the change amounts // to an increase, simply do a write followed by a flush. // (This is a helper function for SetFileInfo.) STATIC EFI_STATUS SetFileSize ( IN BOOTMON_FS_INSTANCE *Instance, IN BOOTMON_FS_FILE *BootMonFsFile, IN UINTN NewSize ) { UINT64 StoredPosition; EFI_STATUS Status; EFI_FILE_PROTOCOL *File; CHAR8 Buffer; UINTN BufferSize; UINT32 OldSize; OldSize = BootMonFsFile->HwDescription.Region[0].Size; if (OldSize == NewSize) { return EFI_SUCCESS; } Buffer = 0; BufferSize = sizeof (Buffer); File = &BootMonFsFile->File; if (!(BootMonFsFile->OpenMode & EFI_FILE_MODE_WRITE)) { return EFI_ACCESS_DENIED; } if (NewSize <= OldSize) { OldSize = NewSize; } else { // Increasing a file's size is potentially complicated as it may require // moving the image description on media. The simplest way to do it is to // seek past the end of the file (which is valid in UEFI) and perform a // Write. // Save position Status = File->GetPosition (File, &StoredPosition); if (EFI_ERROR (Status)) { return Status; } Status = File->SetPosition (File, NewSize - 1); if (EFI_ERROR (Status)) { return Status; } Status = File->Write (File, &BufferSize, &Buffer); if (EFI_ERROR (Status)) { return Status; } // Restore saved position Status = File->SetPosition (File, NewSize - 1); if (EFI_ERROR (Status)) { return Status; } Status = File->Flush (File); if (EFI_ERROR (Status)) { return Status; } } return EFI_SUCCESS; }