1 /** @file
2 Main file for attrib shell level 2 function.
3
4 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
5 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
6 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2018, Dell Technologies. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10 **/
11
12 #include "UefiShellLevel2CommandsLib.h"
13
14 /**
15 Function will replace drive identifier with CWD.
16
17 If FullPath begining with ':' is invalid path, then ASSERT.
18 If FullPath not include dirve identifier , then do nothing.
19 If FullPath likes "fs0:\xx" or "fs0:/xx" , then do nothing.
20 If FullPath likes "fs0:xxx" or "fs0:", the drive replaced by CWD.
21
22 @param[in, out] FullPath The pointer to the string containing the path.
23 @param[in] Cwd Current directory.
24
25 @retval EFI_SUCCESS Success.
26 @retval EFI_OUT_OF_SOURCES A memory allocation failed.
27 **/
28 EFI_STATUS
ReplaceDriveWithCwd(IN OUT CHAR16 ** FullPath,IN CONST CHAR16 * Cwd)29 ReplaceDriveWithCwd (
30 IN OUT CHAR16 **FullPath,
31 IN CONST CHAR16 *Cwd
32 )
33 {
34 CHAR16 *Splitter;
35 CHAR16 *TempBuffer;
36 UINTN TotalSize;
37
38 Splitter = NULL;
39 TempBuffer = NULL;
40 TotalSize = 0;
41
42 if (FullPath == NULL || *FullPath == NULL) {
43 return EFI_SUCCESS;
44 }
45
46 Splitter = StrStr (*FullPath, L":");
47 ASSERT(Splitter != *FullPath);
48
49 if (Splitter != NULL && *(Splitter + 1) != L'\\' && *(Splitter + 1) != L'/') {
50 TotalSize = StrSize (Cwd) + StrSize (Splitter + 1);
51 TempBuffer = AllocateZeroPool (TotalSize);
52 if (TempBuffer == NULL) {
53 return EFI_OUT_OF_RESOURCES;
54 }
55
56 StrCpyS (TempBuffer, TotalSize / sizeof(CHAR16), Cwd);
57 StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), L"\\");
58 StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), Splitter + 1);
59
60 FreePool(*FullPath);
61 *FullPath = TempBuffer;
62 }
63
64 return EFI_SUCCESS;
65 }
66
67 /**
68 function to determine if FullPath is under current filesystem.
69
70 @param[in] FullPath The target location to determine.
71 @param[in] Cwd Current directory.
72
73 @retval TRUE The FullPath is in the current filesystem.
74 @retval FALSE The FullPaht isn't in the current filesystem.
75 **/
76 BOOLEAN
IsCurrentFileSystem(IN CONST CHAR16 * FullPath,IN CONST CHAR16 * Cwd)77 IsCurrentFileSystem (
78 IN CONST CHAR16 *FullPath,
79 IN CONST CHAR16 *Cwd
80 )
81 {
82 CHAR16 *Splitter1;
83 CHAR16 *Splitter2;
84
85 Splitter1 = NULL;
86 Splitter2 = NULL;
87
88 ASSERT(FullPath != NULL);
89
90 Splitter1 = StrStr (FullPath, L":");
91 if (Splitter1 == NULL) {
92 return TRUE;
93 }
94
95 Splitter2 = StrStr (Cwd, L":");
96
97 if (((UINTN) Splitter1 - (UINTN) FullPath) != ((UINTN) Splitter2 - (UINTN) Cwd)) {
98 return FALSE;
99 } else {
100 if (StrniCmp (FullPath, Cwd, ((UINTN) Splitter1 - (UINTN) FullPath) / sizeof (CHAR16)) == 0) {
101 return TRUE;
102 } else {
103 return FALSE;
104 }
105 }
106 }
107
108 /**
109 Extract drive string and path string from FullPath.
110
111 The caller must be free Drive and Path.
112
113 @param[in] FullPath A path to be extracted.
114 @param[out] Drive Buffer to save drive identifier.
115 @param[out] Path Buffer to save path.
116
117 @retval EFI_SUCCESS Success.
118 @retval EFI_OUT_OF_RESOUCES A memory allocation failed.
119 **/
120 EFI_STATUS
ExtractDriveAndPath(IN CONST CHAR16 * FullPath,OUT CHAR16 ** Drive,OUT CHAR16 ** Path)121 ExtractDriveAndPath (
122 IN CONST CHAR16 *FullPath,
123 OUT CHAR16 **Drive,
124 OUT CHAR16 **Path
125 )
126 {
127 CHAR16 *Splitter;
128
129 ASSERT (FullPath != NULL);
130
131 Splitter = StrStr (FullPath, L":");
132
133 if (Splitter == NULL) {
134 *Drive = NULL;
135 *Path = AllocateCopyPool (StrSize (FullPath), FullPath);
136 if (*Path == NULL) {
137 return EFI_OUT_OF_RESOURCES;
138 }
139 } else {
140 if (*(Splitter + 1) == CHAR_NULL) {
141 *Drive = AllocateCopyPool (StrSize (FullPath), FullPath);
142 *Path = NULL;
143 if (*Drive == NULL) {
144 return EFI_OUT_OF_RESOURCES;
145 }
146 } else {
147 *Drive = AllocateCopyPool ((Splitter - FullPath + 2) * sizeof(CHAR16), FullPath);
148 if (*Drive == NULL) {
149 return EFI_OUT_OF_RESOURCES;
150 }
151 (*Drive)[Splitter - FullPath + 1] = CHAR_NULL;
152
153 *Path = AllocateCopyPool (StrSize (Splitter + 1), Splitter + 1);
154 if (*Path == NULL) {
155 FreePool (*Drive);
156 return EFI_OUT_OF_RESOURCES;
157 }
158 }
159 }
160
161 return EFI_SUCCESS;
162 }
163
164 /**
165 Function for 'cd' command.
166
167 @param[in] ImageHandle Handle to the Image (NULL if Internal).
168 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
169 **/
170 SHELL_STATUS
171 EFIAPI
ShellCommandRunCd(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)172 ShellCommandRunCd (
173 IN EFI_HANDLE ImageHandle,
174 IN EFI_SYSTEM_TABLE *SystemTable
175 )
176 {
177 EFI_STATUS Status;
178 LIST_ENTRY *Package;
179 CONST CHAR16 *Cwd;
180 CHAR16 *Path;
181 CHAR16 *Drive;
182 CHAR16 *ProblemParam;
183 SHELL_STATUS ShellStatus;
184 CONST CHAR16 *Param1;
185 CHAR16 *Param1Copy;
186 CHAR16 *Walker;
187 CHAR16 *Splitter;
188 CHAR16 *TempBuffer;
189 UINTN TotalSize;
190
191 ProblemParam = NULL;
192 ShellStatus = SHELL_SUCCESS;
193 Cwd = NULL;
194 Path = NULL;
195 Drive = NULL;
196 Splitter = NULL;
197 TempBuffer = NULL;
198 TotalSize = 0;
199
200 Status = CommandInit();
201 ASSERT_EFI_ERROR(Status);
202
203 //
204 // initialize the shell lib (we must be in non-auto-init...)
205 //
206 Status = ShellInitialize();
207 ASSERT_EFI_ERROR(Status);
208
209 //
210 // parse the command line
211 //
212 Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
213 if (EFI_ERROR(Status)) {
214 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
215 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cd", ProblemParam);
216 FreePool(ProblemParam);
217 ShellStatus = SHELL_INVALID_PARAMETER;
218 } else {
219 ASSERT(FALSE);
220 }
221 }
222
223 //
224 // check for "-?"
225 //
226 if (ShellCommandLineGetFlag(Package, L"-?")) {
227 ASSERT(FALSE);
228 } else if (ShellCommandLineGetRawValue(Package, 2) != NULL) {
229 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"cd");
230 ShellStatus = SHELL_INVALID_PARAMETER;
231 } else {
232 //
233 // remember that param 0 is the command name
234 // If there are 0 value parameters, then print the current directory
235 // else If there are 2 value parameters, then print the error message
236 // else If there is 1 value paramerer , then change the directory
237 //
238 Cwd = ShellGetCurrentDir (NULL);
239 if (Cwd == NULL) {
240 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd");
241 ShellStatus = SHELL_NOT_FOUND;
242 } else {
243 Param1 = ShellCommandLineGetRawValue (Package, 1);
244 if (Param1 == NULL) {
245 //
246 // display the current directory
247 //
248 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_CD_PRINT), gShellLevel2HiiHandle, Cwd);
249 } else {
250 Param1Copy = CatSPrint (NULL, L"%s", Param1, NULL);
251 for (Walker = Param1Copy; Walker != NULL && *Walker != CHAR_NULL; Walker++) {
252 if (*Walker == L'\"') {
253 CopyMem (Walker, Walker + 1, StrSize(Walker) - sizeof(Walker[0]));
254 }
255 }
256
257 if (Param1Copy != NULL && IsCurrentFileSystem (Param1Copy, Cwd)) {
258 Status = ReplaceDriveWithCwd (&Param1Copy,Cwd);
259 } else {
260 //
261 // Can't use cd command to change filesystem.
262 //
263 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");
264 Status = EFI_NOT_FOUND;
265 }
266
267 if (!EFI_ERROR(Status) && Param1Copy != NULL) {
268 Splitter = StrStr (Cwd, L":");
269 if (Param1Copy[0] == L'\\') {
270 //
271 // Absolute Path on current drive letter.
272 //
273 TotalSize = ((Splitter - Cwd + 1) * sizeof(CHAR16)) + StrSize(Param1Copy);
274 TempBuffer = AllocateZeroPool (TotalSize);
275 if (TempBuffer == NULL) {
276 Status = EFI_OUT_OF_RESOURCES;
277 } else {
278 StrnCpyS (TempBuffer, TotalSize / sizeof(CHAR16), Cwd, (Splitter - Cwd + 1));
279 StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), Param1Copy);
280
281 FreePool (Param1Copy);
282 Param1Copy = TempBuffer;
283 TempBuffer = NULL;
284 }
285 } else {
286 if (StrStr (Param1Copy,L":") == NULL) {
287 TotalSize = StrSize (Cwd) + StrSize (Param1Copy);
288 TempBuffer = AllocateZeroPool (TotalSize);
289 if (TempBuffer == NULL) {
290 Status = EFI_OUT_OF_RESOURCES;
291 } else {
292 StrCpyS (TempBuffer, TotalSize / sizeof (CHAR16), Cwd);
293 StrCatS (TempBuffer, TotalSize / sizeof (CHAR16), L"\\");
294 StrCatS (TempBuffer, TotalSize / sizeof (CHAR16), Param1Copy);
295
296 FreePool (Param1Copy);
297 Param1Copy = TempBuffer;
298 TempBuffer = NULL;
299 }
300 }
301 }
302 }
303
304 if (!EFI_ERROR(Status)) {
305 Param1Copy = PathCleanUpDirectories (Param1Copy);
306 Status = ExtractDriveAndPath (Param1Copy, &Drive, &Path);
307 }
308
309 if (!EFI_ERROR (Status) && Drive != NULL && Path != NULL) {
310 if (EFI_ERROR(ShellIsDirectory (Param1Copy))) {
311 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cd", Param1Copy);
312 ShellStatus = SHELL_NOT_FOUND;
313 } else {
314 Status = gEfiShellProtocol->SetCurDir (Drive, Path + 1);
315 if (EFI_ERROR (Status)) {
316 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN(STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cd", Param1Copy);
317 ShellStatus = SHELL_NOT_FOUND;
318 }
319 }
320 }
321
322 if (Drive != NULL) {
323 FreePool (Drive);
324 }
325
326 if (Path != NULL) {
327 FreePool (Path);
328 }
329
330 FreePool (Param1Copy);
331 }
332 }
333 }
334
335 //
336 // free the command line package
337 //
338 ShellCommandLineFreeVarList (Package);
339
340 //
341 // return the status
342 //
343 return (ShellStatus);
344 }
345
346