mirror of
https://github.com/tianocore/edk2
synced 2026-08-27 00:23:19 -04:00
Merge f4edc038f2 into fb2ac429de
This commit is contained in:
commit
6e9371a9c2
4 changed files with 251 additions and 1 deletions
|
|
@ -86,6 +86,18 @@ LibCreateNewFile (
|
||||||
IN BOOLEAN CreateFile
|
IN BOOLEAN CreateFile
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Navigate to the parent of the directory currently displayed.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The parent location was displayed successfully.
|
||||||
|
@retval other errors Error occurred when opening or parsing the parent.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
LibGoUpOneLevel (
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This function allows a caller to extract the current configuration for one
|
This function allows a caller to extract the current configuration for one
|
||||||
or more named elements from the target driver.
|
or more named elements from the target driver.
|
||||||
|
|
@ -273,7 +285,12 @@ LibCallback (
|
||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (QuestionId >= FILE_OPTION_OFFSET) {
|
if (QuestionId == KEY_VALUE_UP_ONE_LEVEL) {
|
||||||
|
Status = LibGoUpOneLevel ();
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
} else if (QuestionId >= FILE_OPTION_OFFSET) {
|
||||||
LibGetDevicePath (QuestionId);
|
LibGetDevicePath (QuestionId);
|
||||||
Status = LibUpdateFileExplorer (QuestionId);
|
Status = LibUpdateFileExplorer (QuestionId);
|
||||||
if (EFI_ERROR (Status)) {
|
if (EFI_ERROR (Status)) {
|
||||||
|
|
@ -528,6 +545,55 @@ LibStrDuplicate (
|
||||||
return Dest;
|
return Dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return the parent directory of an absolute file path.
|
||||||
|
|
||||||
|
The parent of a top level path (e.g. "\" or "\Name") is the volume root "\".
|
||||||
|
|
||||||
|
@param Path The absolute path whose parent is requested.
|
||||||
|
|
||||||
|
@return A newly allocated string holding the parent path, or NULL on failure.
|
||||||
|
Caller is responsible to free the returned string.
|
||||||
|
|
||||||
|
**/
|
||||||
|
CHAR16 *
|
||||||
|
LibGetParentPath (
|
||||||
|
IN CHAR16 *Path
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CHAR16 *Parent;
|
||||||
|
UINTN Index;
|
||||||
|
UINTN LastSlash;
|
||||||
|
|
||||||
|
if (Path == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LastSlash = 0;
|
||||||
|
for (Index = 0; Path[Index] != L'\0'; Index++) {
|
||||||
|
if (Path[Index] == L'\\') {
|
||||||
|
LastSlash = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Only a leading backslash was found (root or a top level entry): parent is "\".
|
||||||
|
//
|
||||||
|
if (LastSlash == 0) {
|
||||||
|
return LibStrDuplicate (L"\\");
|
||||||
|
}
|
||||||
|
|
||||||
|
Parent = AllocateZeroPool ((LastSlash + 1) * sizeof (CHAR16));
|
||||||
|
if (Parent == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyMem (Parent, Path, LastSlash * sizeof (CHAR16));
|
||||||
|
Parent[LastSlash] = L'\0';
|
||||||
|
|
||||||
|
return Parent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
||||||
Function gets the file information from an open file descriptor, and stores it
|
Function gets the file information from an open file descriptor, and stores it
|
||||||
|
|
@ -782,6 +848,17 @@ LibFindFileSystem (
|
||||||
NoSimpleFsHandles = 0;
|
NoSimpleFsHandles = 0;
|
||||||
OptionNumber = 0;
|
OptionNumber = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Showing the volume list: no directory is active, so no "Up" entry is offered.
|
||||||
|
//
|
||||||
|
if (gFileExplorerPrivate.CurDirPath != NULL) {
|
||||||
|
FreePool (gFileExplorerPrivate.CurDirPath);
|
||||||
|
gFileExplorerPrivate.CurDirPath = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gFileExplorerPrivate.CurDirHandle = NULL;
|
||||||
|
gFileExplorerPrivate.CurDeviceHandle = NULL;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Locate Handles that support Simple File System protocol
|
// Locate Handles that support Simple File System protocol
|
||||||
//
|
//
|
||||||
|
|
@ -1155,6 +1232,18 @@ LibFindFiles (
|
||||||
|
|
||||||
OptionNumber = 0;
|
OptionNumber = 0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remember the directory being displayed so a synthetic "Up one level" entry
|
||||||
|
// can navigate back to its parent (or the volume list at a volume root).
|
||||||
|
//
|
||||||
|
if (gFileExplorerPrivate.CurDirPath != NULL) {
|
||||||
|
FreePool (gFileExplorerPrivate.CurDirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
gFileExplorerPrivate.CurDirPath = LibStrDuplicate (FileName);
|
||||||
|
gFileExplorerPrivate.CurDirHandle = FileHandle;
|
||||||
|
gFileExplorerPrivate.CurDeviceHandle = DeviceHandle;
|
||||||
|
|
||||||
DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
|
DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
|
||||||
DirInfo = AllocateZeroPool (DirBufferSize);
|
DirInfo = AllocateZeroPool (DirBufferSize);
|
||||||
if (DirInfo == NULL) {
|
if (DirInfo == NULL) {
|
||||||
|
|
@ -1195,6 +1284,15 @@ LibFindFiles (
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((StrCmp (DirInfo->FileName, L".") == 0) || (StrCmp (DirInfo->FileName, L"..") == 0)) {
|
||||||
|
//
|
||||||
|
// Skip the on-disk "." and ".." entries (present on FAT sub-directories but
|
||||||
|
// not on the volume root or on other file systems). Parent navigation is
|
||||||
|
// provided uniformly by the synthetic "Up one level" entry instead.
|
||||||
|
//
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
NewMenuEntry = LibCreateMenuEntry ();
|
NewMenuEntry = LibCreateMenuEntry ();
|
||||||
if (NULL == NewMenuEntry) {
|
if (NULL == NewMenuEntry) {
|
||||||
Status = EFI_OUT_OF_RESOURCES;
|
Status = EFI_OUT_OF_RESOURCES;
|
||||||
|
|
@ -1329,6 +1427,22 @@ LibUpdateFileExplorePage (
|
||||||
|
|
||||||
mQuestionIdUpdate += QUESTION_ID_UPDATE_STEP;
|
mQuestionIdUpdate += QUESTION_ID_UPDATE_STEP;
|
||||||
|
|
||||||
|
//
|
||||||
|
// When a directory is being displayed, offer a synthetic "Up one level" entry
|
||||||
|
// so the user can return to the parent directory (or the volume list at a
|
||||||
|
// volume root) without having to exit the file explorer entirely.
|
||||||
|
//
|
||||||
|
if (gFileExplorerPrivate.CurDirPath != NULL) {
|
||||||
|
HiiCreateGotoOpCode (
|
||||||
|
mLibStartOpCodeHandle,
|
||||||
|
FORM_FILE_EXPLORER_ID,
|
||||||
|
STRING_TOKEN (STR_UP_ONE_LEVEL),
|
||||||
|
STRING_TOKEN (STR_UP_ONE_LEVEL_HELP),
|
||||||
|
EFI_IFR_FLAG_CALLBACK,
|
||||||
|
KEY_VALUE_UP_ONE_LEVEL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
|
for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
|
||||||
NewMenuEntry = LibGetMenuEntry (MenuOption, Index);
|
NewMenuEntry = LibGetMenuEntry (MenuOption, Index);
|
||||||
NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
|
NewFileContext = (FILE_CONTEXT *)NewMenuEntry->VariableContext;
|
||||||
|
|
@ -1439,6 +1553,107 @@ LibUpdateFileExplorer (
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Navigate to the parent of the directory currently displayed.
|
||||||
|
|
||||||
|
When the volume root is displayed, the volume (file system) list is shown
|
||||||
|
instead. Does nothing when the volume list is already displayed.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The parent location was displayed successfully.
|
||||||
|
@retval other errors Error occurred when opening or parsing the parent.
|
||||||
|
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
LibGoUpOneLevel (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
CHAR16 *ParentPath;
|
||||||
|
EFI_FILE_HANDLE RootHandle;
|
||||||
|
EFI_FILE_HANDLE ParentHandle;
|
||||||
|
EFI_HANDLE DeviceHandle;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Already at the volume list: nothing above it.
|
||||||
|
//
|
||||||
|
if (gFileExplorerPrivate.CurDirPath == NULL) {
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// At a volume root: go back to the volume (file system) list.
|
||||||
|
//
|
||||||
|
if (StrCmp (gFileExplorerPrivate.CurDirPath, L"\\") == 0) {
|
||||||
|
if (gFileExplorerPrivate.CurDirHandle != NULL) {
|
||||||
|
gFileExplorerPrivate.CurDirHandle->Close (gFileExplorerPrivate.CurDirHandle);
|
||||||
|
gFileExplorerPrivate.CurDirHandle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
|
||||||
|
Status = LibFindFileSystem ();
|
||||||
|
if (!EFI_ERROR (Status)) {
|
||||||
|
LibUpdateFileExplorePage ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// In a sub-directory: open and display its parent.
|
||||||
|
//
|
||||||
|
DeviceHandle = gFileExplorerPrivate.CurDeviceHandle;
|
||||||
|
ParentPath = LibGetParentPath (gFileExplorerPrivate.CurDirPath);
|
||||||
|
if (ParentPath == NULL) {
|
||||||
|
return EFI_OUT_OF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
RootHandle = LibOpenRoot (DeviceHandle);
|
||||||
|
if (RootHandle == NULL) {
|
||||||
|
FreePool (ParentPath);
|
||||||
|
return EFI_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrCmp (ParentPath, L"\\") == 0) {
|
||||||
|
ParentHandle = RootHandle;
|
||||||
|
} else {
|
||||||
|
Status = RootHandle->Open (
|
||||||
|
RootHandle,
|
||||||
|
&ParentHandle,
|
||||||
|
ParentPath,
|
||||||
|
EFI_FILE_READ_ONLY,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
RootHandle->Close (RootHandle);
|
||||||
|
if (EFI_ERROR (Status)) {
|
||||||
|
FreePool (ParentPath);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release the directory being left before its handle reference is overwritten.
|
||||||
|
//
|
||||||
|
if (gFileExplorerPrivate.CurDirHandle != NULL) {
|
||||||
|
gFileExplorerPrivate.CurDirHandle->Close (gFileExplorerPrivate.CurDirHandle);
|
||||||
|
gFileExplorerPrivate.CurDirHandle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
|
||||||
|
|
||||||
|
Status = LibFindFiles (ParentHandle, ParentPath, DeviceHandle);
|
||||||
|
if (!EFI_ERROR (Status)) {
|
||||||
|
LibUpdateFileExplorePage ();
|
||||||
|
} else {
|
||||||
|
LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
|
||||||
|
ParentHandle->Close (ParentHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
FreePool (ParentPath);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get the device path info saved in the menu structure.
|
Get the device path info saved in the menu structure.
|
||||||
|
|
||||||
|
|
@ -1557,6 +1772,22 @@ Done:
|
||||||
|
|
||||||
LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
|
LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release the directory currently displayed. Its handle is shared by the (now
|
||||||
|
// freed) child entries, which are non-root and therefore never close it.
|
||||||
|
//
|
||||||
|
if (gFileExplorerPrivate.CurDirHandle != NULL) {
|
||||||
|
gFileExplorerPrivate.CurDirHandle->Close (gFileExplorerPrivate.CurDirHandle);
|
||||||
|
gFileExplorerPrivate.CurDirHandle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gFileExplorerPrivate.CurDirPath != NULL) {
|
||||||
|
FreePool (gFileExplorerPrivate.CurDirPath);
|
||||||
|
gFileExplorerPrivate.CurDirPath = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gFileExplorerPrivate.CurDeviceHandle = NULL;
|
||||||
|
|
||||||
if (FileName != NULL) {
|
if (FileName != NULL) {
|
||||||
FreePool (FileName);
|
FreePool (FileName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,15 @@ typedef struct {
|
||||||
CHAR16 *FileType;
|
CHAR16 *FileType;
|
||||||
CHOOSE_HANDLER ChooseHandler;
|
CHOOSE_HANDLER ChooseHandler;
|
||||||
EFI_DEVICE_PATH_PROTOCOL *RetDevicePath;
|
EFI_DEVICE_PATH_PROTOCOL *RetDevicePath;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Location currently displayed, used to synthesize an "Up one level" entry.
|
||||||
|
// When CurDirPath is NULL the volume (file system) list is being shown and no
|
||||||
|
// "Up" entry is offered.
|
||||||
|
//
|
||||||
|
EFI_HANDLE CurDeviceHandle;
|
||||||
|
EFI_FILE_HANDLE CurDirHandle;
|
||||||
|
CHAR16 *CurDirPath;
|
||||||
} FILE_EXPLORER_CALLBACK_DATA;
|
} FILE_EXPLORER_CALLBACK_DATA;
|
||||||
|
|
||||||
#define FILE_EXPLORER_PRIVATE_FROM_THIS(a) CR (a, FILE_EXPLORER_CALLBACK_DATA, FeConfigAccess, FILE_EXPLORER_CALLBACK_DATA_SIGNATURE)
|
#define FILE_EXPLORER_PRIVATE_FROM_THIS(a) CR (a, FILE_EXPLORER_CALLBACK_DATA, FeConfigAccess, FILE_EXPLORER_CALLBACK_DATA_SIGNATURE)
|
||||||
|
|
|
||||||
|
|
@ -53,3 +53,7 @@
|
||||||
#language fr-FR "Create Folder and Exit"
|
#language fr-FR "Create Folder and Exit"
|
||||||
#string STR_NO_CREATE_FOLDER_AND_EXIT #language en-US "Discard Create and Exit"
|
#string STR_NO_CREATE_FOLDER_AND_EXIT #language en-US "Discard Create and Exit"
|
||||||
#language fr-FR "Discard Create and Exit"
|
#language fr-FR "Discard Create and Exit"
|
||||||
|
#string STR_UP_ONE_LEVEL #language en-US "<.. Up one level>"
|
||||||
|
#language fr-FR "<.. Up one level>"
|
||||||
|
#string STR_UP_ONE_LEVEL_HELP #language en-US "Return to the parent directory, or to the volume list when at the root of a volume"
|
||||||
|
#language fr-FR "Return to the parent directory, or to the volume list when at the root of a volume"
|
||||||
|
|
|
||||||
|
|
@ -22,5 +22,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||||
#define NEW_FOLDER_NAME_ID 0x3001
|
#define NEW_FOLDER_NAME_ID 0x3001
|
||||||
#define KEY_VALUE_CREATE_FOLDER_AND_EXIT 0x3002
|
#define KEY_VALUE_CREATE_FOLDER_AND_EXIT 0x3002
|
||||||
#define KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT 0x3003
|
#define KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT 0x3003
|
||||||
|
//
|
||||||
|
// Reserved question id used by the synthetic "Up one level" entry. It must stay
|
||||||
|
// below NEW_FILE_QUESTION_ID_BASE (0x5000) so the incrementing new-file/new-folder
|
||||||
|
// and FILE_OPTION_OFFSET (0x8000) question ids can never collide with it.
|
||||||
|
//
|
||||||
|
#define KEY_VALUE_UP_ONE_LEVEL 0x4000
|
||||||
|
|
||||||
#define LABEL_END 0xffff
|
#define LABEL_END 0xffff
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue