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