1 /** @file
2   Main file for vol shell level 2 function.
3 
4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "UefiShellLevel2CommandsLib.h"
11 #include <Guid/FileSystemInfo.h>
12 #include <Guid/FileSystemVolumeLabelInfo.h>
13 
14 /**
15   Print the info or change the volume info.
16 
17   @param[in] Path           String with starting path.
18   @param[in] Delete         TRUE to delete the volume label. FALSE otherwise.
19   @param[in] Name           New name to set to the volume label.
20 
21   @retval SHELL_SUCCESS     The operation was sucessful.
22 **/
23 SHELL_STATUS
HandleVol(IN CONST CHAR16 * Path,IN CONST BOOLEAN Delete,IN CONST CHAR16 * Name OPTIONAL)24 HandleVol(
25   IN CONST CHAR16  *Path,
26   IN CONST BOOLEAN Delete,
27   IN CONST CHAR16  *Name OPTIONAL
28   )
29 {
30   EFI_STATUS            Status;
31   SHELL_STATUS          ShellStatus;
32   EFI_FILE_SYSTEM_INFO  *SysInfo;
33   UINTN                 SysInfoSize;
34   SHELL_FILE_HANDLE     ShellFileHandle;
35   EFI_FILE_PROTOCOL     *EfiFpHandle;
36   UINTN                 Size1;
37   UINTN                 Size2;
38 
39   ShellStatus   = SHELL_SUCCESS;
40 
41   if (
42       Name != NULL && (
43       StrStr(Name, L"%") != NULL ||
44       StrStr(Name, L"^") != NULL ||
45       StrStr(Name, L"*") != NULL ||
46       StrStr(Name, L"+") != NULL ||
47       StrStr(Name, L"=") != NULL ||
48       StrStr(Name, L"[") != NULL ||
49       StrStr(Name, L"]") != NULL ||
50       StrStr(Name, L"|") != NULL ||
51       StrStr(Name, L":") != NULL ||
52       StrStr(Name, L";") != NULL ||
53       StrStr(Name, L"\"") != NULL ||
54       StrStr(Name, L"<") != NULL ||
55       StrStr(Name, L">") != NULL ||
56       StrStr(Name, L"?") != NULL ||
57       StrStr(Name, L"/") != NULL ||
58       StrStr(Name, L" ") != NULL )
59       ){
60     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"vol", Name);
61     return (SHELL_INVALID_PARAMETER);
62   }
63 
64   Status = gEfiShellProtocol->OpenFileByName(
65     Path,
66     &ShellFileHandle,
67     Name != NULL?EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE:EFI_FILE_MODE_READ);
68 
69   if (EFI_ERROR(Status) || ShellFileHandle == NULL) {
70     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel2HiiHandle, L"vol", Path);
71     return (SHELL_ACCESS_DENIED);
72   }
73 
74   //
75   // Get the Volume Info from ShellFileHandle
76   //
77   SysInfo     = NULL;
78   SysInfoSize = 0;
79   EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle);
80   Status = EfiFpHandle->GetInfo(
81     EfiFpHandle,
82     &gEfiFileSystemInfoGuid,
83     &SysInfoSize,
84     SysInfo);
85 
86   if (Status == EFI_BUFFER_TOO_SMALL) {
87     SysInfo = AllocateZeroPool(SysInfoSize);
88     Status = EfiFpHandle->GetInfo(
89       EfiFpHandle,
90       &gEfiFileSystemInfoGuid,
91       &SysInfoSize,
92       SysInfo);
93   }
94 
95   ASSERT(SysInfo != NULL);
96 
97   if (Delete) {
98     *((CHAR16 *) SysInfo->VolumeLabel) = CHAR_NULL;
99     SysInfo->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize(SysInfo->VolumeLabel);
100     Status = EfiFpHandle->SetInfo(
101       EfiFpHandle,
102       &gEfiFileSystemInfoGuid,
103       (UINTN)SysInfo->Size,
104       SysInfo);
105   } else if (Name != NULL) {
106     Size1 = StrSize(Name);
107     Size2 = StrSize(SysInfo->VolumeLabel);
108     if (Size1 > Size2) {
109       SysInfo = ReallocatePool((UINTN)SysInfo->Size, (UINTN)SysInfo->Size + Size1 - Size2, SysInfo);
110       if (SysInfo == NULL) {
111         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"vol");
112         ShellStatus = SHELL_OUT_OF_RESOURCES;
113       }
114     }
115     if (SysInfo != NULL) {
116       StrCpyS ( (CHAR16 *) SysInfo->VolumeLabel,
117                   (Size1>Size2? Size1/sizeof(CHAR16) : Size2/sizeof(CHAR16)),
118                   Name
119                   );
120       SysInfo->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + Size1;
121       Status = EfiFpHandle->SetInfo(
122         EfiFpHandle,
123         &gEfiFileSystemInfoGuid,
124         (UINTN)SysInfo->Size,
125         SysInfo);
126     }
127   }
128 
129   FreePool(SysInfo);
130 
131   if (Delete || Name != NULL) {
132     if (EFI_ERROR(Status)) {
133       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_AD), gShellLevel2HiiHandle, L"vol", Path);
134       ShellStatus = SHELL_ACCESS_DENIED;
135     }
136   }
137 
138   SysInfoSize = 0;
139   SysInfo = NULL;
140 
141   Status = EfiFpHandle->GetInfo(
142     EfiFpHandle,
143     &gEfiFileSystemInfoGuid,
144     &SysInfoSize,
145     SysInfo);
146 
147   if (Status == EFI_BUFFER_TOO_SMALL) {
148     SysInfo = AllocateZeroPool(SysInfoSize);
149     Status = EfiFpHandle->GetInfo(
150       EfiFpHandle,
151       &gEfiFileSystemInfoGuid,
152       &SysInfoSize,
153       SysInfo);
154   }
155 
156   gEfiShellProtocol->CloseFile(ShellFileHandle);
157 
158   ASSERT(SysInfo != NULL);
159 
160   if (SysInfo != NULL) {
161     //
162     // print VolumeInfo table
163     //
164     ShellPrintHiiEx (
165       0,
166       gST->ConOut->Mode->CursorRow,
167       NULL,
168       STRING_TOKEN (STR_VOL_VOLINFO),
169       gShellLevel2HiiHandle,
170       SysInfo->VolumeLabel,
171       SysInfo->ReadOnly?L"r":L"rw",
172       SysInfo->VolumeSize,
173       SysInfo->FreeSpace,
174       SysInfo->BlockSize
175      );
176     SHELL_FREE_NON_NULL(SysInfo);
177   }
178 
179   return (ShellStatus);
180 }
181 
182 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
183   {L"-d", TypeFlag},
184   {L"-n", TypeValue},
185   {NULL, TypeMax}
186   };
187 
188 /**
189   Function for 'Vol' command.
190 
191   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
192   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
193 **/
194 SHELL_STATUS
195 EFIAPI
ShellCommandRunVol(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)196 ShellCommandRunVol (
197   IN EFI_HANDLE        ImageHandle,
198   IN EFI_SYSTEM_TABLE  *SystemTable
199   )
200 {
201   EFI_STATUS    Status;
202   LIST_ENTRY    *Package;
203   CHAR16        *ProblemParam;
204   SHELL_STATUS  ShellStatus;
205   CONST CHAR16  *PathName;
206   CONST CHAR16  *CurDir;
207   BOOLEAN       DeleteMode;
208   CHAR16        *FullPath;
209   CHAR16        *TempSpot;
210   UINTN         Length;
211   CONST CHAR16  *NewName;
212 
213   Length              = 0;
214   ProblemParam        = NULL;
215   ShellStatus         = SHELL_SUCCESS;
216   PathName            = NULL;
217   CurDir              = NULL;
218   FullPath            = NULL;
219 
220   //
221   // initialize the shell lib (we must be in non-auto-init...)
222   //
223   Status = ShellInitialize();
224   ASSERT_EFI_ERROR(Status);
225 
226   //
227   // Fix local copies of the protocol pointers
228   //
229   Status = CommandInit();
230   ASSERT_EFI_ERROR(Status);
231 
232   //
233   // parse the command line
234   //
235   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
236   if (EFI_ERROR(Status)) {
237     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
238       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"vol", ProblemParam);
239       FreePool(ProblemParam);
240       ShellStatus = SHELL_INVALID_PARAMETER;
241     } else {
242       ASSERT(FALSE);
243     }
244   } else {
245     //
246     // check for "-?"
247     //
248     if (ShellCommandLineGetFlag(Package, L"-?")) {
249       ASSERT(FALSE);
250     }
251 
252     if (ShellCommandLineGetCount(Package) > 2) {
253       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"vol");
254       ShellStatus = SHELL_INVALID_PARAMETER;
255     } else {
256       PathName = ShellCommandLineGetRawValue(Package, 1);
257       if (PathName == NULL) {
258         CurDir = gEfiShellProtocol->GetCurDir(NULL);
259         if (CurDir == NULL) {
260           ShellStatus = SHELL_NOT_FOUND;
261           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"vol");
262         } else {
263           PathName = CurDir;
264         }
265       }
266       if (PathName != NULL) {
267         TempSpot = StrStr(PathName, L":");
268         if (TempSpot != NULL) {
269           *TempSpot = CHAR_NULL;
270         }
271         TempSpot = StrStr(PathName, L"\\");
272         if (TempSpot != NULL) {
273           *TempSpot = CHAR_NULL;
274         }
275         StrnCatGrow(&FullPath, &Length, PathName, 0);
276         StrnCatGrow(&FullPath, &Length, L":\\", 0);
277         DeleteMode = ShellCommandLineGetFlag(Package, L"-d");
278         NewName    = ShellCommandLineGetValue(Package, L"-n");
279         if (DeleteMode && ShellCommandLineGetFlag(Package, L"-n")) {
280           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_CONFLICT), gShellLevel2HiiHandle, L"vol", L"-d", L"-n");
281           ShellStatus = SHELL_INVALID_PARAMETER;
282         } else if (ShellCommandLineGetFlag(Package, L"-n") && NewName == NULL) {
283           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellLevel2HiiHandle, L"vol", L"-n");
284           ShellStatus = SHELL_INVALID_PARAMETER;
285         } else if (NewName != NULL && StrLen(NewName) > 11) {
286           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellLevel2HiiHandle, L"vol", NewName, L"-n");
287           ShellStatus = SHELL_INVALID_PARAMETER;
288         } else if (ShellStatus == SHELL_SUCCESS) {
289           ShellStatus = HandleVol(
290             FullPath,
291             DeleteMode,
292             NewName
293            );
294         }
295       }
296     }
297   }
298 
299   SHELL_FREE_NON_NULL(FullPath);
300 
301   //
302   // free the command line package
303   //
304   ShellCommandLineFreeVarList (Package);
305 
306   return (ShellStatus);
307 }
308