/** @file\r
File explorer related functions.\r
\r
-Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials are licensed and made available under\r
-the terms and conditions of the BSD License that accompanies this distribution.\r
-The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php.\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
{\r
END_DEVICE_PATH_TYPE,\r
END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
- { \r
+ {\r
(UINT8) (END_DEVICE_PATH_LENGTH),\r
(UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
}\r
VOID *mLibEndOpCodeHandle = NULL;\r
EFI_IFR_GUID_LABEL *mLibStartLabel = NULL;\r
EFI_IFR_GUID_LABEL *mLibEndLabel = NULL;\r
+UINT16 mQuestionIdUpdate;\r
+CHAR16 mNewFileName[MAX_FILE_NAME_LEN];\r
+CHAR16 mNewFolderName[MAX_FOLDER_NAME_LEN];\r
+UINTN mNewFileQuestionId = NEW_FILE_QUESTION_ID_BASE;\r
+UINTN mNewFolderQuestionId = NEW_FOLDER_QUESTION_ID_BASE;\r
+\r
+/**\r
+ Create a new file or folder in current directory.\r
+\r
+ @param FileName Point to the fileNmae or folder.\r
+ @param CreateFile CreateFile== TRUE means create a new file.\r
+ CreateFile== FALSE means create a new Folder.\r
+\r
+**/\r
+EFI_STATUS\r
+LibCreateNewFile (\r
+ IN CHAR16 *FileName,\r
+ IN BOOLEAN CreateFile\r
+ );\r
\r
/**\r
This function allows a caller to extract the current configuration for one\r
{\r
EFI_STATUS Status;\r
BOOLEAN NeedExit;\r
+ CHAR16 *NewFileName;\r
+ CHAR16 *NewFolderName;\r
\r
NeedExit = TRUE;\r
- \r
+ NewFileName = NULL;\r
+ NewFolderName = NULL;\r
+\r
if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {\r
//\r
// Do nothing for other UEFI Action. Only do call back when data is changed.\r
if ((Value == NULL) || (ActionRequest == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
+\r
+ if (QuestionId == KEY_VALUE_CREATE_FILE_AND_EXIT) {\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+ if (!IsZeroBuffer (mNewFileName, sizeof (mNewFileName))) {\r
+ Status = LibCreateNewFile (mNewFileName,TRUE);\r
+ ZeroMem (mNewFileName,sizeof (mNewFileName));\r
+ }\r
+ }\r
+\r
+ if (QuestionId == KEY_VALUE_NO_CREATE_FILE_AND_EXIT) {\r
+ ZeroMem (mNewFileName,sizeof (mNewFileName));\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+ }\r
+\r
+ if (QuestionId == KEY_VALUE_CREATE_FOLDER_AND_EXIT) {\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+ if (!IsZeroBuffer (mNewFolderName, sizeof (mNewFolderName))) {\r
+ Status = LibCreateNewFile (mNewFolderName, FALSE);\r
+ ZeroMem (mNewFolderName,sizeof (mNewFolderName));\r
+ }\r
+ }\r
+\r
+ if (QuestionId == KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT) {\r
+ ZeroMem (mNewFolderName,sizeof (mNewFolderName));\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+ }\r
+\r
+ if (QuestionId == NEW_FILE_NAME_ID) {\r
+ NewFileName = HiiGetString (gFileExplorerPrivate.FeHiiHandle, Value->string, NULL);\r
+ if (NewFileName != NULL) {\r
+ StrCpyS (mNewFileName, MAX_FILE_NAME_LEN, NewFileName);\r
+ FreePool (NewFileName);\r
+ NewFileName = NULL;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ if (QuestionId == NEW_FOLDER_NAME_ID) {\r
+ NewFolderName = HiiGetString (gFileExplorerPrivate.FeHiiHandle, Value->string, NULL);\r
+ if (NewFolderName != NULL) {\r
+ StrCpyS (mNewFolderName, MAX_FOLDER_NAME_LEN, NewFolderName);\r
+ FreePool (NewFolderName);\r
+ NewFolderName = NULL;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
if (QuestionId >= FILE_OPTION_OFFSET) {\r
LibGetDevicePath(QuestionId);\r
\r
if (Value == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- \r
if (QuestionId >= FILE_OPTION_OFFSET) {\r
+ LibGetDevicePath(QuestionId);\r
Status = LibUpdateFileExplorer (QuestionId);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
\r
Buffer = NULL;\r
BufferSize = 0;\r
- \r
+\r
Status = FHand->GetInfo (\r
FHand,\r
InfoType,\r
\r
Size1 = StrSize (Str1);\r
Size2 = StrSize (Str2);\r
- \r
+\r
//\r
// Check overflow\r
//\r
if (((MAX_UINTN - Size1) < Size2) || ((MAX_UINTN - Size1 - Size2) < sizeof(CHAR16))) {\r
return NULL;\r
}\r
- \r
+\r
MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16);\r
Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));\r
ASSERT (Str != NULL);\r
\r
- TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); \r
+ TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));\r
ASSERT (TmpStr != NULL);\r
\r
StrCpyS (Str, MaxLen, Str1);\r
//\r
\r
//\r
- // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings \r
+ // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings\r
// that overlap.\r
//\r
StrCpyS (TmpStr, MaxLen, Ptr + 3);\r
- StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr);\r
+ StrCpyS (LastSlash, MaxLen - ((UINTN) LastSlash - (UINTN) Str) / sizeof (CHAR16), TmpStr);\r
Ptr = LastSlash;\r
} else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {\r
//\r
//\r
\r
//\r
- // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings \r
+ // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings\r
// that overlap.\r
//\r
StrCpyS (TmpStr, MaxLen, Ptr + 2);\r
- StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr);\r
+ StrCpyS (Ptr, MaxLen - ((UINTN) Ptr - (UINTN) Str) / sizeof (CHAR16), TmpStr);\r
Ptr = LastSlash;\r
} else if (*Ptr == '\\') {\r
LastSlash = Ptr;\r
}\r
\r
FreePool (TmpStr);\r
- \r
+\r
return Str;\r
}\r
\r
)\r
{\r
UINTN NoSimpleFsHandles;\r
- UINTN NoLoadFileHandles;\r
EFI_HANDLE *SimpleFsHandle;\r
- EFI_HANDLE *LoadFileHandle;\r
UINT16 *VolumeLabel;\r
UINTN Index;\r
EFI_STATUS Status;\r
EFI_FILE_SYSTEM_VOLUME_LABEL *Info;\r
\r
NoSimpleFsHandles = 0;\r
- NoLoadFileHandles = 0;\r
OptionNumber = 0;\r
\r
//\r
if (Info == NULL) {\r
VolumeLabel = L"NO FILE SYSTEM INFO";\r
} else {\r
- if (Info->VolumeLabel == NULL) {\r
- VolumeLabel = L"NULL VOLUME LABEL";\r
- } else {\r
- VolumeLabel = Info->VolumeLabel;\r
- if (*VolumeLabel == 0x0000) {\r
- VolumeLabel = L"NO VOLUME LABEL";\r
- }\r
+ VolumeLabel = Info->VolumeLabel;\r
+ if (*VolumeLabel == 0x0000) {\r
+ VolumeLabel = L"NO VOLUME LABEL";\r
}\r
}\r
MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
VolumeLabel,\r
MenuEntry->HelpString\r
);\r
- MenuEntry->DisplayStringToken = HiiSetString (\r
+ MenuEntry->DisplayStringToken = HiiSetString (\r
gFileExplorerPrivate.FeHiiHandle,\r
0,\r
MenuEntry->DisplayString,\r
FreePool (SimpleFsHandle);\r
}\r
\r
- //\r
- // Searching for handles that support Load File protocol\r
- //\r
- Status = gBS->LocateHandleBuffer (\r
- ByProtocol,\r
- &gEfiLoadFileProtocolGuid,\r
- NULL,\r
- &NoLoadFileHandles,\r
- &LoadFileHandle\r
- );\r
-\r
- if (!EFI_ERROR (Status)) {\r
- for (Index = 0; Index < NoLoadFileHandles; Index++) {\r
- MenuEntry = LibCreateMenuEntry ();\r
- if (NULL == MenuEntry) {\r
- FreePool (LoadFileHandle);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;\r
- FileContext->DeviceHandle = LoadFileHandle[Index];\r
- FileContext->IsRoot = TRUE;\r
-\r
- FileContext->DevicePath = DevicePathFromHandle (FileContext->DeviceHandle);\r
- FileContext->FileName = LibDevicePathToStr (FileContext->DevicePath);\r
-\r
- MenuEntry->HelpString = LibDevicePathToStr (FileContext->DevicePath);\r
- MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);\r
- ASSERT (MenuEntry->DisplayString != NULL);\r
- UnicodeSPrint (\r
- MenuEntry->DisplayString,\r
- MAX_CHAR,\r
- L"Load File [%s]",\r
- MenuEntry->HelpString\r
- );\r
- MenuEntry->DisplayStringToken = HiiSetString (\r
- gFileExplorerPrivate.FeHiiHandle,\r
- 0,\r
- MenuEntry->DisplayString,\r
- NULL\r
- );\r
-\r
- OptionNumber++;\r
- InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);\r
- }\r
- }\r
-\r
- if (NoLoadFileHandles != 0) {\r
- FreePool (LoadFileHandle);\r
- }\r
-\r
gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;\r
\r
return EFI_SUCCESS;\r
\r
/**\r
Find the file handle from the input menu info.\r
- \r
+\r
@param MenuEntry Input Menu info.\r
@param RetFileHandle Return the file handle for the input device path.\r
- \r
+\r
@retval EFI_SUCESS Find the file handle success.\r
@retval Other Find the file handle failure.\r
**/\r
EFI_STATUS\r
LibGetFileHandleFromMenu (\r
- IN MENU_ENTRY *MenuEntry, \r
+ IN MENU_ENTRY *MenuEntry,\r
OUT EFI_FILE_HANDLE *RetFileHandle\r
)\r
{\r
\r
/**\r
Find the file handle from the input device path info.\r
- \r
+\r
@param RootDirectory Device path info.\r
@param RetFileHandle Return the file handle for the input device path.\r
@param ParentFileName Parent file name.\r
@param DeviceHandle Driver handle for this partition.\r
- \r
+\r
@retval EFI_SUCESS Find the file handle success.\r
@retval Other Find the file handle failure.\r
**/\r
EFI_STATUS\r
LibGetFileHandleFromDevicePath (\r
- IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, \r
+ IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory,\r
OUT EFI_FILE_HANDLE *RetFileHandle,\r
OUT UINT16 **ParentFileName,\r
OUT EFI_HANDLE *DeviceHandle\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- \r
+\r
Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- \r
+\r
//\r
// Open the Volume to get the File System handle\r
//\r
*RetFileHandle = FileHandle;\r
return EFI_SUCCESS;\r
}\r
- \r
+\r
//\r
// Duplicate the device path to avoid the access to unaligned device path node.\r
// Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH\r
Status = EFI_OUT_OF_RESOURCES;\r
goto Done;\r
}\r
- \r
+\r
//\r
// Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the\r
// directory information and filename can be seperate. The goal is to inch\r
return Status;\r
}\r
\r
+/**\r
+ Create a new file or folder in current directory.\r
+\r
+ @param FileName Point to the fileNmae or folder name.\r
+ @param CreateFile CreateFile== TRUE means create a new file.\r
+ CreateFile== FALSE means create a new Folder.\r
+\r
+**/\r
+EFI_STATUS\r
+LibCreateNewFile (\r
+ IN CHAR16 *FileName,\r
+ IN BOOLEAN CreateFile\r
+ )\r
+{\r
+ EFI_FILE_HANDLE FileHandle;\r
+ EFI_FILE_HANDLE NewHandle;\r
+ EFI_HANDLE DeviceHandle;\r
+ EFI_STATUS Status;\r
+ CHAR16 *ParentName;\r
+ CHAR16 *FullFileName;\r
+\r
+ NewHandle = NULL;\r
+ FullFileName = NULL;\r
+\r
+ LibGetFileHandleFromDevicePath(gFileExplorerPrivate.RetDevicePath, &FileHandle, &ParentName, &DeviceHandle);\r
+ FullFileName = LibAppendFileName (ParentName, FileName);\r
+ if (FullFileName == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ if (CreateFile) {\r
+ Status = FileHandle->Open(\r
+ FileHandle,\r
+ &NewHandle,\r
+ FullFileName,\r
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FileHandle->Close (FileHandle);\r
+ return Status;\r
+ }\r
+ } else {\r
+ Status = FileHandle->Open(\r
+ FileHandle,\r
+ &NewHandle,\r
+ FullFileName,\r
+ EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,\r
+ EFI_FILE_DIRECTORY\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FileHandle->Close (FileHandle);\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ FileHandle->Close (FileHandle);\r
+\r
+ //\r
+ // Return the DevicePath of the new created file or folder.\r
+ //\r
+ gFileExplorerPrivate.RetDevicePath = FileDevicePath (DeviceHandle, FullFileName);\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
/**\r
Find files under current directory.\r
- \r
+\r
All files and sub-directories in current directory\r
will be stored in DirectoryMenu for future use.\r
\r
- @param FileHandle Parent file handle. \r
+ @param FileHandle Parent file handle.\r
@param FileName Parent file name.\r
@param DeviceHandle Driver handle for this partition.\r
\r
} else {\r
NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName);\r
}\r
- \r
+\r
NewMenuEntry->DisplayStringToken = HiiSetString (\r
gFileExplorerPrivate.FeHiiHandle,\r
0,\r
MENU_ENTRY *NewMenuEntry;\r
FILE_CONTEXT *NewFileContext;\r
MENU_OPTION *MenuOption;\r
+ BOOLEAN CreateNewFile;\r
\r
NewMenuEntry = NULL;\r
NewFileContext = NULL;\r
+ CreateNewFile = FALSE;\r
\r
LibRefreshUpdateData ();\r
MenuOption = gFileExplorerPrivate.FsOptionMenu;\r
\r
+ mQuestionIdUpdate += QUESTION_ID_UPDATE_STEP;\r
+\r
for (Index = 0; Index < MenuOption->MenuNumber; Index++) {\r
NewMenuEntry = LibGetMenuEntry (MenuOption, Index);\r
NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;\r
\r
+ if (!NewFileContext->IsRoot && !CreateNewFile) {\r
+ HiiCreateGotoOpCode (\r
+ mLibStartOpCodeHandle,\r
+ FORM_ADD_NEW_FILE_ID,\r
+ STRING_TOKEN (STR_NEW_FILE),\r
+ STRING_TOKEN (STR_NEW_FILE_HELP),\r
+ EFI_IFR_FLAG_CALLBACK,\r
+ (UINT16) (mNewFileQuestionId++)\r
+ );\r
+ HiiCreateGotoOpCode (\r
+ mLibStartOpCodeHandle,\r
+ FORM_ADD_NEW_FOLDER_ID,\r
+ STRING_TOKEN (STR_NEW_FOLDER),\r
+ STRING_TOKEN (STR_NEW_FOLDER_HELP),\r
+ EFI_IFR_FLAG_CALLBACK,\r
+ (UINT16) (mNewFolderQuestionId++)\r
+ );\r
+ HiiCreateTextOpCode(\r
+ mLibStartOpCodeHandle,\r
+ STRING_TOKEN (STR_NULL_STRING),\r
+ STRING_TOKEN (STR_NULL_STRING),\r
+ 0\r
+ );\r
+ CreateNewFile = TRUE;\r
+ }\r
+\r
if (!NewFileContext->IsDir) {\r
//\r
// Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.\r
//\r
HiiCreateActionOpCode (\r
mLibStartOpCodeHandle,\r
- (UINT16) (FILE_OPTION_OFFSET + Index),\r
+ (UINT16) (FILE_OPTION_OFFSET + Index + mQuestionIdUpdate),\r
NewMenuEntry->DisplayStringToken,\r
STRING_TOKEN (STR_NULL_STRING),\r
EFI_IFR_FLAG_CALLBACK,\r
NewMenuEntry->DisplayStringToken,\r
STRING_TOKEN (STR_NULL_STRING),\r
EFI_IFR_FLAG_CALLBACK,\r
- (UINT16) (FILE_OPTION_OFFSET + Index)\r
+ (UINT16) (FILE_OPTION_OFFSET + Index + mQuestionIdUpdate)\r
);\r
}\r
}\r
EFI_FILE_HANDLE FileHandle;\r
\r
Status = EFI_SUCCESS;\r
- FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);\r
+ FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;\r
NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);\r
NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;\r
\r
if (NewFileContext->IsDir) {\r
RemoveEntryList (&NewMenuEntry->Link);\r
LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);\r
- LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);\r
- Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);\r
+ Status = LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle);\r
if (!EFI_ERROR (Status)) {\r
- LibUpdateFileExplorePage ();\r
- } else {\r
- LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);\r
+ Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle);\r
+ if (!EFI_ERROR (Status)) {\r
+ LibUpdateFileExplorePage ();\r
+ } else {\r
+ LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);\r
+ }\r
}\r
LibDestroyMenuEntry (NewMenuEntry);\r
}\r
MENU_ENTRY *NewMenuEntry;\r
FILE_CONTEXT *NewFileContext;\r
\r
- FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);\r
+ FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate;\r
\r
NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask);\r
\r
}\r
\r
/**\r
- Choose a file in the specified directory. \r
+ Choose a file in the specified directory.\r
\r
If user input NULL for the RootDirectory, will choose file in the system.\r
\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ mQuestionIdUpdate = 0;\r
FileName = NULL;\r
\r
gFileExplorerPrivate.RetDevicePath = NULL;\r
//\r
Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2);\r
ASSERT_EFI_ERROR (Status);\r
- \r
+\r
InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);\r
\r
return EFI_SUCCESS;\r
NULL\r
);\r
ASSERT_EFI_ERROR (Status);\r
- \r
+\r
HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);\r
+ gFileExplorerPrivate.FeDriverHandle = NULL;\r
}\r
\r
FreePool (gHiiVendorDevicePath);\r