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