]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/FileExplorerLib/FileExplorer.c
MdeModulePkg: Refine type cast for pointer subtraction
[mirror_edk2.git] / MdeModulePkg / Library / FileExplorerLib / FileExplorer.c
index 9714dbcf5d24d52bc77a54d1999690052f57a7bd..9182751ad75bdaaee0f01a10bd132fc0bf4bc43b 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
 File explorer related functions.\r
 \r
-Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2004 - 2017, 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
@@ -72,6 +72,25 @@ VOID                *mLibStartOpCodeHandle = NULL;
 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
@@ -174,9 +193,13 @@ LibCallback (
 {\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
@@ -188,7 +211,55 @@ LibCallback (
     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
@@ -207,8 +278,8 @@ LibCallback (
     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
@@ -302,7 +373,9 @@ LibDestroyMenuEntry (
   FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;\r
 \r
   if (!FileContext->IsRoot) {\r
-    FreePool (FileContext->DevicePath);\r
+    if (FileContext->DevicePath != NULL) {\r
+      FreePool (FileContext->DevicePath);\r
+    }\r
   } else {\r
     if (FileContext->FileHandle != NULL) {\r
       FileContext->FileHandle->Close (FileContext->FileHandle);\r
@@ -315,7 +388,9 @@ LibDestroyMenuEntry (
 \r
   FreePool (FileContext);\r
 \r
-  FreePool (MenuEntry->DisplayString);\r
+  if (MenuEntry->DisplayString != NULL) {\r
+    FreePool (MenuEntry->DisplayString);\r
+  }\r
   if (MenuEntry->HelpString != NULL) {\r
     FreePool (MenuEntry->HelpString);\r
   }\r
@@ -580,6 +655,7 @@ LibIsSupportedFileType (
   }\r
 \r
   TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType);\r
+  ASSERT(TmpStr != NULL);\r
   LibToLowerString(TmpStr);\r
 \r
   IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE);\r
@@ -615,6 +691,14 @@ LibAppendFileName (
 \r
   Size1 = StrSize (Str1);\r
   Size2 = StrSize (Str2);\r
+  \r
+  //\r
+  // Check overflow\r
+  //\r
+  if (((MAX_UINTN - Size1) < Size2) || ((MAX_UINTN - Size1 - Size2) < sizeof(CHAR16))) {\r
+    return NULL;\r
+  }\r
+  \r
   MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16);\r
   Str   = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16));\r
   ASSERT (Str != NULL);\r
@@ -644,7 +728,7 @@ LibAppendFileName (
       // 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
@@ -656,7 +740,7 @@ LibAppendFileName (
       // 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
@@ -686,9 +770,7 @@ LibFindFileSystem (
   )\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
@@ -698,7 +780,6 @@ LibFindFileSystem (
   EFI_FILE_SYSTEM_VOLUME_LABEL *Info;\r
 \r
   NoSimpleFsHandles = 0;\r
-  NoLoadFileHandles = 0;\r
   OptionNumber      = 0;\r
 \r
   //\r
@@ -770,7 +851,9 @@ LibFindFileSystem (
                                              MenuEntry->DisplayString,\r
                                              NULL\r
                                              );\r
-      FreePool (Info);\r
+\r
+      if (Info != NULL)\r
+        FreePool (Info);\r
 \r
       OptionNumber++;\r
       InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link);\r
@@ -781,57 +864,6 @@ LibFindFileSystem (
     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
@@ -956,6 +988,7 @@ LibGetFileHandleFromDevicePath (
     // the file system support below to be skipped.\r
     //\r
     Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
   }\r
         \r
   //\r
@@ -985,6 +1018,11 @@ LibGetFileHandleFromDevicePath (
       *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);\r
     } else {\r
       TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName);\r
+      if (TempPath == NULL) {\r
+        LastHandle->Close (LastHandle);\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
       FreePool (*ParentFileName);\r
       *ParentFileName = TempPath;\r
     }\r
@@ -1017,6 +1055,72 @@ Done:
   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
@@ -1060,12 +1164,14 @@ LibFindFiles (
   // Pass 1 to get Directories\r
   // Pass 2 to get files that are EFI images\r
   //\r
+  Status = EFI_SUCCESS;\r
   for (Pass = 1; Pass <= 2; Pass++) {\r
     FileHandle->SetPosition (FileHandle, 0);\r
     for (;;) {\r
       BufferSize  = DirBufferSize;\r
       Status      = FileHandle->Read (FileHandle, &BufferSize, DirInfo);\r
       if (EFI_ERROR (Status) || BufferSize == 0) {\r
+        Status = EFI_SUCCESS;\r
         break;\r
       }\r
 \r
@@ -1088,12 +1194,18 @@ LibFindFiles (
 \r
       NewMenuEntry = LibCreateMenuEntry ();\r
       if (NULL == NewMenuEntry) {\r
-        return EFI_OUT_OF_RESOURCES;\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
       }\r
 \r
       NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext;\r
       NewFileContext->DeviceHandle = DeviceHandle;\r
       NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName);\r
+      if  (NewFileContext->FileName == NULL) {\r
+        LibDestroyMenuEntry (NewMenuEntry);\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
       NewFileContext->FileHandle = FileHandle;\r
       NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName);\r
       NewMenuEntry->HelpString = NULL;\r
@@ -1128,9 +1240,11 @@ LibFindFiles (
 \r
   gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber;\r
 \r
+Done:\r
+\r
   FreePool (DirInfo);\r
 \r
-  return EFI_SUCCESS;\r
+  return Status;\r
 }\r
 \r
 /**\r
@@ -1199,24 +1313,54 @@ LibUpdateFileExplorePage (
   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
@@ -1232,7 +1376,7 @@ LibUpdateFileExplorePage (
         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
@@ -1267,7 +1411,7 @@ LibUpdateFileExplorer (
   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
@@ -1302,7 +1446,7 @@ LibGetDevicePath (
   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
@@ -1351,12 +1495,14 @@ ChooseFile (
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  mQuestionIdUpdate = 0;\r
   FileName = NULL;\r
 \r
   gFileExplorerPrivate.RetDevicePath = NULL;\r
   gFileExplorerPrivate.ChooseHandler = ChooseHandler;\r
   if (FileType != NULL) {\r
     gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType);\r
+    ASSERT(gFileExplorerPrivate.FileType != NULL);\r
     LibToLowerString(gFileExplorerPrivate.FileType);\r
   } else {\r
     gFileExplorerPrivate.FileType = NULL;\r