MdeModulePkg/CapsuleApp: Add CapsuleApp application.
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / AppSupport.c
1 /** @file
2 A shell application that triggers capsule update process.
3
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include <Uefi.h>
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/MemoryAllocationLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/UefiRuntimeServicesTableLib.h>
22 #include <Library/UefiLib.h>
23 #include <Library/PrintLib.h>
24 #include <Protocol/LoadedImage.h>
25 #include <Protocol/SimpleFileSystem.h>
26 #include <Protocol/ShellParameters.h>
27 #include <Guid/FileInfo.h>
28 #include <Guid/Gpt.h>
29
30 #define MAX_ARG_NUM 11
31
32 UINTN Argc;
33 CHAR16 **Argv;
34
35 /**
36
37 This function parse application ARG.
38
39 @return Status
40 **/
41 EFI_STATUS
42 GetArg (
43 VOID
44 )
45 {
46 EFI_STATUS Status;
47 EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
48
49 Status = gBS->HandleProtocol (
50 gImageHandle,
51 &gEfiShellParametersProtocolGuid,
52 (VOID**)&ShellParameters
53 );
54 if (EFI_ERROR(Status)) {
55 return Status;
56 }
57
58 Argc = ShellParameters->Argc;
59 Argv = ShellParameters->Argv;
60 return EFI_SUCCESS;
61 }
62
63 /**
64 Return File System Volume containing this shell application.
65
66 @return File System Volume containing this shell application.
67 **/
68 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *
69 GetMyVol (
70 VOID
71 )
72 {
73 EFI_STATUS Status;
74 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
75 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
76
77 Status = gBS->HandleProtocol (
78 gImageHandle,
79 &gEfiLoadedImageProtocolGuid,
80 (VOID **)&LoadedImage
81 );
82 ASSERT_EFI_ERROR (Status);
83
84 Status = gBS->HandleProtocol (
85 LoadedImage->DeviceHandle,
86 &gEfiSimpleFileSystemProtocolGuid,
87 (VOID **)&Vol
88 );
89 if (!EFI_ERROR (Status)) {
90 return Vol;
91 }
92
93 return NULL;
94 }
95
96 /**
97 Read a file from this volume.
98
99 @param[in] Vol File System Volume
100 @param[in] FileName The file to be read.
101 @param[out] BufferSize The file buffer size
102 @param[out] Buffer The file buffer
103
104 @retval EFI_SUCCESS Read file successfully
105 @retval EFI_NOT_FOUND File not found
106 **/
107 EFI_STATUS
108 ReadFileFromVol (
109 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol,
110 IN CHAR16 *FileName,
111 OUT UINTN *BufferSize,
112 OUT VOID **Buffer
113 )
114 {
115 EFI_STATUS Status;
116 EFI_FILE_HANDLE RootDir;
117 EFI_FILE_HANDLE Handle;
118 UINTN FileInfoSize;
119 EFI_FILE_INFO *FileInfo;
120 UINTN TempBufferSize;
121 VOID *TempBuffer;
122
123 //
124 // Open the root directory
125 //
126 Status = Vol->OpenVolume (Vol, &RootDir);
127 if (EFI_ERROR (Status)) {
128 return Status;
129 }
130
131 //
132 // Open the file
133 //
134 Status = RootDir->Open (
135 RootDir,
136 &Handle,
137 FileName,
138 EFI_FILE_MODE_READ,
139 0
140 );
141 if (EFI_ERROR (Status)) {
142 RootDir->Close (RootDir);
143 return Status;
144 }
145
146 RootDir->Close (RootDir);
147
148 //
149 // Get the file information
150 //
151 FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
152
153 FileInfo = AllocateZeroPool (FileInfoSize);
154 if (FileInfo == NULL) {
155 Handle->Close (Handle);
156 return Status;
157 }
158
159 Status = Handle->GetInfo (
160 Handle,
161 &gEfiFileInfoGuid,
162 &FileInfoSize,
163 FileInfo
164 );
165 if (EFI_ERROR (Status)) {
166 Handle->Close (Handle);
167 gBS->FreePool (FileInfo);
168 return Status;
169 }
170
171 //
172 // Allocate buffer for the file data. The last CHAR16 is for L'\0'
173 //
174 TempBufferSize = (UINTN) FileInfo->FileSize + sizeof(CHAR16);
175 TempBuffer = AllocateZeroPool (TempBufferSize);
176 if (TempBuffer == NULL) {
177 Handle->Close (Handle);
178 gBS->FreePool (FileInfo);
179 return Status;
180 }
181
182 gBS->FreePool (FileInfo);
183
184 //
185 // Read the file data to the buffer
186 //
187 Status = Handle->Read (
188 Handle,
189 &TempBufferSize,
190 TempBuffer
191 );
192 if (EFI_ERROR (Status)) {
193 Handle->Close (Handle);
194 gBS->FreePool (TempBuffer);
195 return Status;
196 }
197
198 Handle->Close (Handle);
199
200 *BufferSize = TempBufferSize;
201 *Buffer = TempBuffer;
202 return EFI_SUCCESS;
203 }
204
205 /**
206 Read a file.
207 If ScanFs is FLASE, it will use this Vol as default Fs.
208 If ScanFs is TRUE, it will scan all FS and check the file.
209 If there is only one file match the name, it will be read.
210 If there is more than one file match the name, it will return Error.
211
212 @param[in] ThisVol File System Volume
213 @param[in] FileName The file to be read.
214 @param[out] BufferSize The file buffer size
215 @param[out] Buffer The file buffer
216 @param[in] ScanFs Need Scan all FS
217
218 @retval EFI_SUCCESS Read file successfully
219 @retval EFI_NOT_FOUND File not found
220 @retval EFI_NO_MAPPING There is duplicated files found
221 **/
222 EFI_STATUS
223 ReadFileToBufferEx (
224 IN OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **ThisVol,
225 IN CHAR16 *FileName,
226 OUT UINTN *BufferSize,
227 OUT VOID **Buffer,
228 IN BOOLEAN ScanFs
229 )
230 {
231 EFI_STATUS Status;
232 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
233 UINTN TempBufferSize;
234 VOID *TempBuffer;
235 UINTN NoHandles;
236 EFI_HANDLE *HandleBuffer;
237 UINTN Index;
238
239 //
240 // Check parameters
241 //
242 if ((FileName == NULL) || (Buffer == NULL) || (ThisVol == NULL)) {
243 return EFI_INVALID_PARAMETER;
244 }
245
246 //
247 // not scan fs
248 //
249 if (!ScanFs) {
250 if (*ThisVol == NULL) {
251 *ThisVol = GetMyVol ();
252 if (*ThisVol == NULL) {
253 return EFI_INVALID_PARAMETER;
254 }
255 }
256 //
257 // Read file directly from Vol
258 //
259 return ReadFileFromVol (*ThisVol, FileName, BufferSize, Buffer);
260 }
261
262 //
263 // need scan fs
264 //
265
266 //
267 // Get all Vol handle
268 //
269 Status = gBS->LocateHandleBuffer (
270 ByProtocol,
271 &gEfiSimpleFileSystemProtocolGuid,
272 NULL,
273 &NoHandles,
274 &HandleBuffer
275 );
276 if (EFI_ERROR (Status) && (NoHandles == 0)) {
277 return EFI_NOT_FOUND;
278 }
279
280 //
281 // Walk through each Vol
282 //
283 *ThisVol = NULL;
284 *BufferSize = 0;
285 *Buffer = NULL;
286 for (Index = 0; Index < NoHandles; Index++) {
287 Status = gBS->HandleProtocol (
288 HandleBuffer[Index],
289 &gEfiSimpleFileSystemProtocolGuid,
290 (VOID **)&Vol
291 );
292 if (EFI_ERROR(Status)) {
293 continue;
294 }
295
296 Status = ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuffer);
297 if (!EFI_ERROR (Status)) {
298 //
299 // Read file OK, check duplication
300 //
301 if (*ThisVol != NULL) {
302 //
303 // Find the duplicated file
304 //
305 gBS->FreePool (TempBuffer);
306 gBS->FreePool (*Buffer);
307 Print (L"Duplicated FileName found!\n");
308 return EFI_NO_MAPPING;
309 } else {
310 //
311 // Record value
312 //
313 *ThisVol = Vol;
314 *BufferSize = TempBufferSize;
315 *Buffer = TempBuffer;
316 }
317 }
318 }
319
320 //
321 // Scan Fs done
322 //
323 if (*ThisVol == NULL) {
324 return EFI_NOT_FOUND;
325 }
326
327 //
328 // Done
329 //
330 return EFI_SUCCESS;
331 }
332
333 /**
334 Read a file.
335
336 @param[in] FileName The file to be read.
337 @param[out] BufferSize The file buffer size
338 @param[out] Buffer The file buffer
339
340 @retval EFI_SUCCESS Read file successfully
341 @retval EFI_NOT_FOUND File not found
342 **/
343 EFI_STATUS
344 ReadFileToBuffer (
345 IN CHAR16 *FileName,
346 OUT UINTN *BufferSize,
347 OUT VOID **Buffer
348 )
349 {
350 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
351 Vol = NULL;
352 return ReadFileToBufferEx(&Vol, FileName, BufferSize, Buffer, FALSE);
353 }
354
355 /**
356 Write a file.
357
358 @param[in] FileName The file to be written.
359 @param[in] BufferSize The file buffer size
360 @param[in] Buffer The file buffer
361
362 @retval EFI_SUCCESS Write file successfully
363 **/
364 EFI_STATUS
365 WriteFileFromBuffer (
366 IN CHAR16 *FileName,
367 IN UINTN BufferSize,
368 IN VOID *Buffer
369 )
370 {
371 EFI_STATUS Status;
372 EFI_FILE_HANDLE RootDir;
373 EFI_FILE_HANDLE Handle;
374 UINTN TempBufferSize;
375 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
376
377 Vol = GetMyVol();
378 if (Vol == NULL) {
379 return EFI_NOT_FOUND;
380 }
381
382 //
383 // Open the root directory
384 //
385 Status = Vol->OpenVolume (Vol, &RootDir);
386 if (EFI_ERROR (Status)) {
387 return Status;
388 }
389
390 //
391 // Open the file
392 //
393 Status = RootDir->Open (
394 RootDir,
395 &Handle,
396 FileName,
397 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
398 0
399 );
400 if (EFI_ERROR (Status)) {
401 RootDir->Close (RootDir);
402 return Status;
403 }
404
405 //
406 // Delete file
407 //
408 Status = Handle->Delete(Handle);
409 if (EFI_ERROR(Status)) {
410 return Status;
411 }
412
413 //
414 // Open the file again
415 //
416 Status = RootDir->Open (
417 RootDir,
418 &Handle,
419 FileName,
420 EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,
421 0
422 );
423 if (EFI_ERROR (Status)) {
424 RootDir->Close (RootDir);
425 return Status;
426 }
427
428 RootDir->Close (RootDir);
429
430 //
431 // Write the file data from the buffer
432 //
433 TempBufferSize = BufferSize;
434 Status = Handle->Write (
435 Handle,
436 &TempBufferSize,
437 Buffer
438 );
439 if (EFI_ERROR (Status)) {
440 Handle->Close (Handle);
441 return Status;
442 }
443
444 Handle->Close (Handle);
445
446 return EFI_SUCCESS;
447 }
448