ShellPkg: Add checking for memory allocation and pointer returns from functions.
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / UefiShellLevel2CommandsLib.c
1 /** @file\r
2   Main file for NULL named library for level 2 shell command functions.\r
3 \r
4   these functions are:\r
5   attrib,\r
6   cd,\r
7   cp,\r
8   date*,\r
9   time*,\r
10   load,\r
11   ls,\r
12   map,\r
13   mkdir,\r
14   mv,\r
15   parse,\r
16   rm,\r
17   reset,\r
18   set,\r
19   timezone*,\r
20   vol\r
21 \r
22   * functions are non-interactive only\r
23 \r
24 \r
25   Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
26   This program and the accompanying materials\r
27   are licensed and made available under the terms and conditions of the BSD License\r
28   which accompanies this distribution.  The full text of the license may be found at\r
29   http://opensource.org/licenses/bsd-license.php\r
30 \r
31   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
32   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
33 \r
34 **/\r
35 #include "UefiShellLevel2CommandsLib.h"\r
36 \r
37 CONST CHAR16 mFileName[] = L"ShellCommands";\r
38 EFI_HANDLE gShellLevel2HiiHandle = NULL;\r
39 \r
40 /**\r
41   Get the filename to get help text from if not using HII.\r
42 \r
43   @retval The filename.\r
44 **/\r
45 CONST CHAR16*\r
46 EFIAPI\r
47 ShellCommandGetManFileNameLevel2 (\r
48   VOID\r
49   )\r
50 {\r
51   return (mFileName);\r
52 }\r
53 \r
54 /**\r
55   Constructor for the Shell Level 2 Commands library.\r
56 \r
57   Install the handlers for level 2 UEFI Shell 2.0 commands.\r
58 \r
59   @param ImageHandle    the image handle of the process\r
60   @param SystemTable    the EFI System Table pointer\r
61 \r
62   @retval EFI_SUCCESS        the shell command handlers were installed sucessfully\r
63   @retval EFI_UNSUPPORTED    the shell level required was not found.\r
64 **/\r
65 EFI_STATUS\r
66 EFIAPI\r
67 ShellLevel2CommandsLibConstructor (\r
68   IN EFI_HANDLE        ImageHandle,\r
69   IN EFI_SYSTEM_TABLE  *SystemTable\r
70   )\r
71 {\r
72   //\r
73   // if shell level is less than 2 do nothing\r
74   //\r
75   if (PcdGet8(PcdShellSupportLevel) < 2) {\r
76     return (EFI_SUCCESS);\r
77   }\r
78 \r
79   gShellLevel2HiiHandle = HiiAddPackages (&gShellLevel2HiiGuid, gImageHandle, UefiShellLevel2CommandsLibStrings, NULL);\r
80   if (gShellLevel2HiiHandle == NULL) {\r
81     return (EFI_DEVICE_ERROR);\r
82   }\r
83 \r
84   //\r
85   // install our shell command handlers that are always installed\r
86   //\r
87   ShellCommandRegisterCommandName(L"attrib",   ShellCommandRunAttrib  , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_ATTRIB) );\r
88   ShellCommandRegisterCommandName(L"cd",       ShellCommandRunCd      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CD)     );\r
89   ShellCommandRegisterCommandName(L"cp",       ShellCommandRunCp      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_CP)     );\r
90   ShellCommandRegisterCommandName(L"load",     ShellCommandRunLoad    , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LOAD)   );\r
91   ShellCommandRegisterCommandName(L"map",      ShellCommandRunMap     , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MAP)    );\r
92   ShellCommandRegisterCommandName(L"mkdir",    ShellCommandRunMkDir   , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MKDIR)  );\r
93   ShellCommandRegisterCommandName(L"mv",       ShellCommandRunMv      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_MV)     );\r
94   ShellCommandRegisterCommandName(L"parse",    ShellCommandRunParse   , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_PARSE)  );\r
95   ShellCommandRegisterCommandName(L"reset",    ShellCommandRunReset   , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RESET)  );\r
96   ShellCommandRegisterCommandName(L"set",      ShellCommandRunSet     , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_SET)    );\r
97   ShellCommandRegisterCommandName(L"ls",       ShellCommandRunLs      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_LS)     );\r
98   ShellCommandRegisterCommandName(L"rm",       ShellCommandRunRm      , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_RM)     );\r
99   ShellCommandRegisterCommandName(L"vol",      ShellCommandRunVol     , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_VOL)    );\r
100 \r
101   //\r
102   // support for permenant (built in) aliases\r
103   //\r
104   ShellCommandRegisterAlias(L"rm", L"del");\r
105   ShellCommandRegisterAlias(L"ls", L"dir");\r
106   ShellCommandRegisterAlias(L"cp", L"copy");\r
107   ShellCommandRegisterAlias(L"mkdir", L"md");\r
108   ShellCommandRegisterAlias(L"cd ..", L"cd..");\r
109   ShellCommandRegisterAlias(L"cd \\", L"cd\\");\r
110   ShellCommandRegisterAlias(L"ren", L"mv");\r
111   //\r
112   // These are installed in level 2 or 3...\r
113   //\r
114   if (PcdGet8(PcdShellSupportLevel) == 2 || PcdGet8(PcdShellSupportLevel) == 3) {\r
115     ShellCommandRegisterCommandName(L"date",     ShellCommandRunDate    , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE)   );\r
116     ShellCommandRegisterCommandName(L"time",     ShellCommandRunTime    , ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME)   );\r
117     ShellCommandRegisterCommandName(L"timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, PcdGet8(PcdShellSupportLevel), L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE));\r
118   } else {\r
119     DEBUG_CODE_BEGIN();\r
120     //\r
121     // we want to be able to test these so install them under a different name in debug mode...\r
122     //\r
123     ShellCommandRegisterCommandName(L"l2date",     ShellCommandRunDate    , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_DATE)   );\r
124     ShellCommandRegisterCommandName(L"l2time",     ShellCommandRunTime    , ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIME)   );\r
125     ShellCommandRegisterCommandName(L"l2timezone", ShellCommandRunTimeZone, ShellCommandGetManFileNameLevel2, 2, L"", TRUE, gShellLevel2HiiHandle, STRING_TOKEN(STR_GET_HELP_TIMEZONE));\r
126     DEBUG_CODE_END();\r
127   }\r
128 \r
129   return (EFI_SUCCESS);\r
130 }\r
131 \r
132 /**\r
133   Destructor for the library.  free any resources.\r
134 \r
135   @param ImageHandle    The image handle of the process.\r
136   @param SystemTable    The EFI System Table pointer.\r
137 \r
138   @retval EFI_SUCCESS   Always returned.\r
139 **/\r
140 EFI_STATUS\r
141 EFIAPI\r
142 ShellLevel2CommandsLibDestructor (\r
143   IN EFI_HANDLE        ImageHandle,\r
144   IN EFI_SYSTEM_TABLE  *SystemTable\r
145   )\r
146 {\r
147   if (gShellLevel2HiiHandle != NULL) {\r
148     HiiRemovePackages(gShellLevel2HiiHandle);\r
149   }\r
150   return (EFI_SUCCESS);\r
151 }\r
152 \r
153 /**\r
154   returns a fully qualified directory (contains a map drive at the begining)\r
155   path from a unknown directory path.\r
156 \r
157   If Path is already fully qualified this will return a duplicat otherwise this\r
158   will use get the current directory and use that to build the fully qualified\r
159   version.\r
160 \r
161   if the return value is not NULL it must be caller freed.\r
162 \r
163   @param[in] Path         The unknown Path Value\r
164 \r
165   @retval NULL            A memory allocation failed\r
166   @retval NULL            a fully qualified path could not be discovered.\r
167   @retval other           pointer to a fuly qualified path.\r
168 **/\r
169 CHAR16*\r
170 EFIAPI\r
171 GetFullyQualifiedPath(\r
172   IN CONST CHAR16* Path\r
173   )\r
174 {\r
175   CHAR16        *PathToReturn;\r
176   UINTN         Size;\r
177   CONST CHAR16  *CurDir;\r
178 \r
179   PathToReturn  = NULL;\r
180   Size          = 0;\r
181 \r
182   ASSERT((PathToReturn == NULL && Size == 0) || (PathToReturn != NULL));\r
183   //\r
184   // convert a local path to an absolute path\r
185   //\r
186   if (StrStr(Path, L":") == NULL) {\r
187     CurDir = gEfiShellProtocol->GetCurDir(NULL);\r
188     StrnCatGrow(&PathToReturn, &Size, CurDir, 0);\r
189     if (*Path == L'\\') {\r
190       Path++;\r
191     }\r
192   }\r
193   StrnCatGrow(&PathToReturn, &Size, Path, 0);\r
194 \r
195   PathCleanUpDirectories(PathToReturn);\r
196 \r
197   while (PathToReturn[StrLen(PathToReturn)-1] == L'*') {\r
198     PathToReturn[StrLen(PathToReturn)-1] = CHAR_NULL;\r
199   }\r
200 \r
201   return (PathToReturn);\r
202 }\r
203 \r
204 /**\r
205   Function to verify all intermediate directories in the path.\r
206 \r
207   @param[in] Path       The pointer to the path to fix.\r
208 \r
209   @retval EFI_SUCCESS   The operation was successful.\r
210 **/\r
211 EFI_STATUS\r
212 EFIAPI\r
213 VerifyIntermediateDirectories (\r
214   IN CONST CHAR16 *Path\r
215   )\r
216 {\r
217   EFI_STATUS      Status;\r
218   CHAR16          *PathCopy;\r
219   CHAR16          *TempSpot;\r
220   SHELL_FILE_HANDLE          FileHandle;\r
221 \r
222   ASSERT(Path != NULL);\r
223 \r
224   Status      = EFI_SUCCESS;\r
225   PathCopy    = NULL;\r
226   PathCopy    = StrnCatGrow(&PathCopy, NULL, Path, 0);\r
227   FileHandle  = NULL;\r
228 \r
229   if (PathCopy == NULL) {\r
230     return (EFI_OUT_OF_RESOURCES);\r
231   }\r
232 \r
233   for (TempSpot = &PathCopy[StrLen(PathCopy)-1] ; *TempSpot != CHAR_NULL && *TempSpot != L'\\' ; TempSpot = &PathCopy[StrLen(PathCopy)-1]){\r
234     *TempSpot = CHAR_NULL;\r
235   }\r
236   if (*TempSpot == L'\\') {\r
237     *TempSpot = CHAR_NULL;\r
238   }\r
239 \r
240   if (PathCopy != NULL && *PathCopy != CHAR_NULL) {\r
241     Status = VerifyIntermediateDirectories(PathCopy);\r
242 \r
243     if (PathCopy[StrLen(PathCopy)-1] != L':') {\r
244       if (!EFI_ERROR(Status)) {\r
245         Status = ShellOpenFileByName(PathCopy, &FileHandle, EFI_FILE_MODE_READ, 0);\r
246         if (FileHandle != NULL) {\r
247           ShellCloseFile(&FileHandle);\r
248         }\r
249       }\r
250     }\r
251   }\r
252 \r
253   SHELL_FREE_NON_NULL(PathCopy);\r
254 \r
255   return (Status);\r
256 }\r
257 \r
258 /**\r
259   Be lazy and borrow from baselib.\r
260 \r
261   @param[in] Char   The character to convert to upper case.\r
262 \r
263   @return Char as an upper case character.\r
264 **/\r
265 CHAR16\r
266 EFIAPI\r
267 InternalCharToUpper (\r
268   IN CONST CHAR16                    Char\r
269   );\r
270 \r
271 /**\r
272   String comparison without regard to case for a limited number of characters.\r
273 \r
274   @param[in] Source   The first item to compare.\r
275   @param[in] Target   The second item to compare.\r
276   @param[in] Count    How many characters to compare.\r
277 \r
278   @retval NULL Source and Target are identical strings without regard to case.\r
279   @return The location in Source where there is a difference.\r
280 **/\r
281 CONST CHAR16*\r
282 EFIAPI\r
283 StrniCmp(\r
284   IN CONST CHAR16 *Source,\r
285   IN CONST CHAR16 *Target,\r
286   IN CONST UINTN  Count\r
287   )\r
288 {\r
289   UINTN   LoopCount;\r
290   CHAR16  Char1;\r
291   CHAR16  Char2;\r
292 \r
293   ASSERT(Source != NULL);\r
294   ASSERT(Target != NULL);\r
295 \r
296   for (LoopCount = 0 ; LoopCount < Count ; LoopCount++) {\r
297     Char1 = InternalCharToUpper(Source[LoopCount]);\r
298     Char2 = InternalCharToUpper(Target[LoopCount]);\r
299     if (Char1 != Char2) {\r
300       return (&Source[LoopCount]);\r
301     }\r
302   }\r
303   return (NULL);\r
304 }\r
305 \r