]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
ArmPkg/SemihostFs: Implement SetInfo() and handle seeking past the end of a file
[mirror_edk2.git] / ArmPkg / Filesystem / SemihostFs / Arm / SemihostFs.c
CommitLineData
2ef2b01e
A
1/** @file\r
2 Support a Semi Host file system over a debuggers JTAG\r
3\r
d6ebcab7 4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
d276ac10 5 Portions copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>\r
c63626b7 6\r
d6ebcab7 7 This program and the accompanying materials\r
2ef2b01e
A
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include <Uefi.h>\r
18\r
19#include <Guid/FileInfo.h>\r
20#include <Guid/FileSystemInfo.h>\r
09f2cf82 21#include <Guid/FileSystemVolumeLabelInfo.h>\r
2ef2b01e
A
22\r
23#include <Library/BaseLib.h>\r
3402aac7 24#include <Library/BaseMemoryLib.h>\r
2ef2b01e
A
25#include <Library/DebugLib.h>\r
26#include <Library/MemoryAllocationLib.h>\r
27#include <Library/SemihostLib.h>\r
28#include <Library/UefiBootServicesTableLib.h>\r
29#include <Library/UefiLib.h>\r
30\r
31#include <Protocol/DevicePath.h>\r
32#include <Protocol/SimpleFileSystem.h>\r
33\r
34#include "SemihostFs.h"\r
35\r
09f2cf82 36#define DEFAULT_SEMIHOST_FS_LABEL L"SemihostFs"\r
37\r
38STATIC CHAR16 *mSemihostFsLabel;\r
2ef2b01e
A
39\r
40EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs = {\r
41 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,\r
42 VolumeOpen\r
43};\r
44\r
45EFI_FILE gSemihostFsFile = {\r
46 EFI_FILE_PROTOCOL_REVISION,\r
47 FileOpen,\r
48 FileClose,\r
49 FileDelete,\r
50 FileRead,\r
51 FileWrite,\r
52 FileGetPosition,\r
53 FileSetPosition,\r
54 FileGetInfo,\r
55 FileSetInfo,\r
56 FileFlush\r
57};\r
58\r
59//\r
fdd12bd5 60// Device path for semi-hosting. It contains our autogened Caller ID GUID.\r
2ef2b01e
A
61//\r
62typedef struct {\r
63 VENDOR_DEVICE_PATH Guid;\r
64 EFI_DEVICE_PATH_PROTOCOL End;\r
65} SEMIHOST_DEVICE_PATH;\r
66\r
67SEMIHOST_DEVICE_PATH gDevicePath = {\r
68 {\r
b0fdce95 69 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { sizeof (VENDOR_DEVICE_PATH), 0 } },\r
2ef2b01e
A
70 EFI_CALLER_ID_GUID\r
71 },\r
b0fdce95 72 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } }\r
2ef2b01e
A
73};\r
74\r
75typedef struct {\r
09f2cf82 76 LIST_ENTRY Link;\r
77 UINT64 Signature;\r
78 EFI_FILE File;\r
79 CHAR8 *FileName;\r
80 UINT64 OpenMode;\r
81 UINT32 Position;\r
82 UINTN SemihostHandle;\r
83 BOOLEAN IsRoot;\r
84 EFI_FILE_INFO Info;\r
2ef2b01e
A
85} SEMIHOST_FCB;\r
86\r
87#define SEMIHOST_FCB_SIGNATURE SIGNATURE_32( 'S', 'H', 'F', 'C' )\r
88#define SEMIHOST_FCB_FROM_THIS(a) CR(a, SEMIHOST_FCB, File, SEMIHOST_FCB_SIGNATURE)\r
89#define SEMIHOST_FCB_FROM_LINK(a) CR(a, SEMIHOST_FCB, Link, SEMIHOST_FCB_SIGNATURE);\r
90\r
91EFI_HANDLE gInstallHandle = NULL;\r
92LIST_ENTRY gFileList = INITIALIZE_LIST_HEAD_VARIABLE (gFileList);\r
93\r
94SEMIHOST_FCB *\r
95AllocateFCB (\r
96 VOID\r
97 )\r
98{\r
99 SEMIHOST_FCB *Fcb = AllocateZeroPool (sizeof (SEMIHOST_FCB));\r
100\r
101 if (Fcb != NULL) {\r
102 CopyMem (&Fcb->File, &gSemihostFsFile, sizeof (gSemihostFsFile));\r
103 Fcb->Signature = SEMIHOST_FCB_SIGNATURE;\r
104 }\r
105\r
106 return Fcb;\r
107}\r
108\r
109VOID\r
110FreeFCB (\r
111 IN SEMIHOST_FCB *Fcb\r
112 )\r
113{\r
114 // Remove Fcb from gFileList.\r
115 RemoveEntryList (&Fcb->Link);\r
116\r
117 // To help debugging...\r
118 Fcb->Signature = 0;\r
119\r
120 FreePool (Fcb);\r
121}\r
122\r
123\r
124\r
125EFI_STATUS\r
126VolumeOpen (\r
127 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,\r
128 OUT EFI_FILE **Root\r
129 )\r
130{\r
131 SEMIHOST_FCB *RootFcb = NULL;\r
3402aac7 132\r
2ef2b01e
A
133 if (Root == NULL) {\r
134 return EFI_INVALID_PARAMETER;\r
135 }\r
136\r
137 RootFcb = AllocateFCB ();\r
138 if (RootFcb == NULL) {\r
139 return EFI_OUT_OF_RESOURCES;\r
140 }\r
3402aac7 141\r
2ef2b01e 142 RootFcb->IsRoot = TRUE;\r
09f2cf82 143 RootFcb->Info.Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;\r
2ef2b01e
A
144\r
145 InsertTailList (&gFileList, &RootFcb->Link);\r
146\r
147 *Root = &RootFcb->File;\r
148\r
149 return EFI_SUCCESS;\r
150}\r
151\r
fdd12bd5
RC
152/**\r
153 Open a file on the host system by means of the semihosting interface.\r
154\r
155 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
156 the file handle to source location.\r
157 @param[out] NewHandle A pointer to the location to return the opened\r
158 handle for the new file.\r
159 @param[in] FileName The Null-terminated string of the name of the file\r
160 to be opened.\r
161 @param[in] OpenMode The mode to open the file : Read or Read/Write or\r
162 Read/Write/Create\r
163 @param[in] Attributes Only valid for EFI_FILE_MODE_CREATE, in which case these\r
164 are the attribute bits for the newly created file. The\r
165 mnemonics of the attribute bits are : EFI_FILE_READ_ONLY,\r
166 EFI_FILE_HIDDEN, EFI_FILE_SYSTEM, EFI_FILE_RESERVED,\r
167 EFI_FILE_DIRECTORY and EFI_FILE_ARCHIVE.\r
168\r
169 @retval EFI_SUCCESS The file was open.\r
170 @retval EFI_NOT_FOUND The specified file could not be found.\r
171 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
172 @retval EFI_WRITE_PROTECTED Attempt to create a directory. This is not possible\r
173 with the semi-hosting interface.\r
174 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the file.\r
175 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
176\r
177**/\r
2ef2b01e
A
178EFI_STATUS\r
179FileOpen (\r
fdd12bd5
RC
180 IN EFI_FILE *This,\r
181 OUT EFI_FILE **NewHandle,\r
182 IN CHAR16 *FileName,\r
183 IN UINT64 OpenMode,\r
184 IN UINT64 Attributes\r
2ef2b01e
A
185 )\r
186{\r
fdd12bd5
RC
187 SEMIHOST_FCB *FileFcb;\r
188 RETURN_STATUS Return;\r
189 EFI_STATUS Status;\r
190 UINTN SemihostHandle;\r
191 CHAR8 *AsciiFileName;\r
192 UINT32 SemihostMode;\r
193 UINTN Length;\r
2ef2b01e
A
194\r
195 if ((FileName == NULL) || (NewHandle == NULL)) {\r
196 return EFI_INVALID_PARAMETER;\r
197 }\r
198\r
fdd12bd5
RC
199 if ( (OpenMode != EFI_FILE_MODE_READ) &&\r
200 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE)) &&\r
201 (OpenMode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE)) ) {\r
202 return EFI_INVALID_PARAMETER;\r
203 }\r
204\r
205 if ((OpenMode & EFI_FILE_MODE_CREATE) &&\r
206 (Attributes & EFI_FILE_DIRECTORY) ) {\r
207 return EFI_WRITE_PROTECTED;\r
09f2cf82 208 }\r
209\r
fdd12bd5 210 AsciiFileName = AllocatePool (StrLen (FileName) + 1);\r
2ef2b01e
A
211 if (AsciiFileName == NULL) {\r
212 return EFI_OUT_OF_RESOURCES;\r
213 }\r
ed2405a0 214 UnicodeStrToAsciiStr (FileName, AsciiFileName);\r
2ef2b01e 215\r
fdd12bd5 216 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory\r
1ea31716 217 if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||\r
218 (AsciiStrCmp (AsciiFileName, "/") == 0) ||\r
219 (AsciiStrCmp (AsciiFileName, "") == 0) ||\r
fdd12bd5 220 (AsciiStrCmp (AsciiFileName, ".") == 0) ) {\r
2ef2b01e 221 FreePool (AsciiFileName);\r
fdd12bd5
RC
222 return (VolumeOpen (&gSemihostFs, NewHandle));\r
223 }\r
224\r
225 //\r
226 // No control is done here concerning the file path. It is passed\r
227 // as it is to the host operating system through the semi-hosting\r
228 // interface. We first try to open the file in the read or update\r
229 // mode even if the file creation has been asked for. That way, if\r
230 // the file already exists, it is not truncated to zero length. In\r
231 // write mode (bit SEMIHOST_FILE_MODE_WRITE up), if the file already\r
232 // exists, it is reset to an empty file.\r
233 //\r
234 if (OpenMode == EFI_FILE_MODE_READ) {\r
235 SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;\r
2ef2b01e 236 } else {\r
fdd12bd5
RC
237 SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE;\r
238 }\r
239 Return = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);\r
2ef2b01e 240\r
fdd12bd5 241 if (RETURN_ERROR (Return)) {\r
2ef2b01e 242 if (OpenMode & EFI_FILE_MODE_CREATE) {\r
fdd12bd5
RC
243 //\r
244 // In the create if does not exist case, if the opening in update\r
245 // mode failed, create it and open it in update mode. The update\r
246 // mode allows for both read and write from and to the file.\r
247 //\r
248 Return = SemihostFileOpen (\r
249 AsciiFileName,\r
250 SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY | SEMIHOST_FILE_MODE_UPDATE,\r
251 &SemihostHandle\r
252 );\r
253 if (RETURN_ERROR (Return)) {\r
254 Status = EFI_DEVICE_ERROR;\r
255 goto Error;\r
256 }\r
257 } else {\r
258 Status = EFI_NOT_FOUND;\r
259 goto Error;\r
2ef2b01e 260 }\r
2ef2b01e
A
261 }\r
262\r
263 // Allocate a control block and fill it\r
264 FileFcb = AllocateFCB ();\r
265 if (FileFcb == NULL) {\r
fdd12bd5
RC
266 Status = EFI_OUT_OF_RESOURCES;\r
267 goto Error;\r
2ef2b01e
A
268 }\r
269\r
270 FileFcb->FileName = AsciiFileName;\r
271 FileFcb->SemihostHandle = SemihostHandle;\r
272 FileFcb->Position = 0;\r
fdd12bd5 273 FileFcb->IsRoot = 0;\r
09f2cf82 274 FileFcb->OpenMode = OpenMode;\r
275\r
fdd12bd5
RC
276 Return = SemihostFileLength (SemihostHandle, &Length);\r
277 if (RETURN_ERROR (Return)) {\r
278 Status = EFI_DEVICE_ERROR;\r
279 FreeFCB (FileFcb);\r
280 goto Error;\r
09f2cf82 281 }\r
2ef2b01e 282\r
fdd12bd5
RC
283 FileFcb->Info.FileSize = Length;\r
284 FileFcb->Info.PhysicalSize = Length;\r
285 FileFcb->Info.Attribute = (OpenMode & EFI_FILE_MODE_CREATE) ? Attributes : 0;\r
286\r
2ef2b01e
A
287 InsertTailList (&gFileList, &FileFcb->Link);\r
288\r
289 *NewHandle = &FileFcb->File;\r
290\r
fdd12bd5
RC
291 return EFI_SUCCESS;\r
292\r
293Error:\r
294\r
295 FreePool (AsciiFileName);\r
296\r
2ef2b01e
A
297 return Status;\r
298}\r
299\r
daefd574
RC
300/**\r
301 Worker function that truncate a file specified by its name to a given size.\r
302\r
303 @param[in] FileName The Null-terminated string of the name of the file to be opened.\r
304 @param[in] Size The target size for the file.\r
305\r
306 @retval EFI_SUCCESS The file was truncated.\r
307 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
308\r
309**/\r
310STATIC\r
311EFI_STATUS\r
312TruncateFile (\r
313 IN CHAR8 *FileName,\r
314 IN UINTN Size\r
315 )\r
316{\r
317 EFI_STATUS Status;\r
318 RETURN_STATUS Return;\r
319 UINTN FileHandle;\r
320 UINT8 *Buffer;\r
321 UINTN Remaining;\r
322 UINTN Read;\r
323 UINTN ToRead;\r
324\r
325 Status = EFI_DEVICE_ERROR;\r
326 FileHandle = 0;\r
327 Buffer = NULL;\r
328\r
329 Return = SemihostFileOpen (\r
330 FileName,\r
331 SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY,\r
332 &FileHandle\r
333 );\r
334 if (RETURN_ERROR (Return)) {\r
335 goto Error;\r
336 }\r
337\r
338 Buffer = AllocatePool (Size);\r
339 if (Buffer == NULL) {\r
340 Status = EFI_OUT_OF_RESOURCES;\r
341 goto Error;\r
342 }\r
343\r
344 Read = 0;\r
345 Remaining = Size;\r
346 while (Remaining > 0) {\r
347 ToRead = Remaining;\r
348 Return = SemihostFileRead (FileHandle, &ToRead, Buffer + Read);\r
349 if (RETURN_ERROR (Return)) {\r
350 goto Error;\r
351 }\r
352 Remaining -= ToRead;\r
353 Read += ToRead;\r
354 }\r
355\r
356 Return = SemihostFileClose (FileHandle);\r
357 FileHandle = 0;\r
358 if (RETURN_ERROR (Return)) {\r
359 goto Error;\r
360 }\r
361\r
362 Return = SemihostFileOpen (\r
363 FileName,\r
364 SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY,\r
365 &FileHandle\r
366 );\r
367 if (RETURN_ERROR (Return)) {\r
368 goto Error;\r
369 }\r
370\r
371 if (Size > 0) {\r
372 Return = SemihostFileWrite (FileHandle, &Size, Buffer);\r
373 if (RETURN_ERROR (Return)) {\r
374 goto Error;\r
375 }\r
376 }\r
377\r
378 Status = EFI_SUCCESS;\r
2ef2b01e 379\r
daefd574
RC
380Error:\r
381\r
382 if (FileHandle != 0) {\r
383 SemihostFileClose (FileHandle);\r
384 }\r
385 if (Buffer != NULL) {\r
386 FreePool (Buffer);\r
387 }\r
388\r
389 return (Status);\r
390\r
391}\r
392\r
393/**\r
394 Close a specified file handle.\r
395\r
396 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
397 handle to close.\r
398\r
399 @retval EFI_SUCCESS The file was closed.\r
400 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.\r
401\r
402**/\r
2ef2b01e
A
403EFI_STATUS\r
404FileClose (\r
daefd574 405 IN EFI_FILE *This\r
2ef2b01e
A
406 )\r
407{\r
daefd574 408 SEMIHOST_FCB *Fcb;\r
2ef2b01e 409\r
daefd574
RC
410 if (This == NULL) {\r
411 return EFI_INVALID_PARAMETER;\r
412 }\r
2ef2b01e 413\r
daefd574
RC
414 Fcb = SEMIHOST_FCB_FROM_THIS(This);\r
415\r
416 if (!Fcb->IsRoot) {\r
417 SemihostFileClose (Fcb->SemihostHandle);\r
418 //\r
419 // The file size might have been reduced from its actual\r
420 // size on the host file system with FileSetInfo(). In\r
421 // that case, the file has to be truncated.\r
422 //\r
423 if (Fcb->Info.FileSize < Fcb->Info.PhysicalSize) {\r
424 TruncateFile (Fcb->FileName, Fcb->Info.FileSize);\r
2ef2b01e 425 }\r
daefd574 426 FreePool (Fcb->FileName);\r
2ef2b01e 427 }\r
3402aac7 428\r
daefd574
RC
429 FreeFCB (Fcb);\r
430\r
431 return EFI_SUCCESS;\r
2ef2b01e
A
432}\r
433\r
daefd574
RC
434/**\r
435 Close and delete a file.\r
436\r
437 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is the file\r
438 handle to delete.\r
439\r
440 @retval EFI_SUCCESS The file was closed and deleted.\r
441 @retval EFI_WARN_DELETE_FAILURE The handle was closed, but the file was not deleted.\r
442 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.\r
443\r
444**/\r
2ef2b01e
A
445EFI_STATUS\r
446FileDelete (\r
daefd574 447 IN EFI_FILE *This\r
2ef2b01e
A
448 )\r
449{\r
daefd574
RC
450 SEMIHOST_FCB *Fcb;\r
451 RETURN_STATUS Return;\r
452 CHAR8 *FileName;\r
453 UINTN NameSize;\r
2ef2b01e 454\r
daefd574
RC
455 if (This == NULL) {\r
456 return EFI_INVALID_PARAMETER;\r
457 }\r
458\r
459 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
2ef2b01e 460\r
3bb46df2 461 if (!Fcb->IsRoot) {\r
462 // Get the filename from the Fcb\r
463 NameSize = AsciiStrLen (Fcb->FileName);\r
464 FileName = AllocatePool (NameSize + 1);\r
2ef2b01e 465\r
3bb46df2 466 AsciiStrCpy (FileName, Fcb->FileName);\r
2ef2b01e 467\r
3bb46df2 468 // Close the file if it's open. Disregard return status,\r
469 // since it might give an error if the file isn't open.\r
daefd574 470 This->Close (This);\r
3bb46df2 471\r
472 // Call the semihost interface to delete the file.\r
daefd574
RC
473 Return = SemihostFileRemove (FileName);\r
474 if (RETURN_ERROR (Return)) {\r
475 return EFI_WARN_DELETE_FAILURE;\r
09f2cf82 476 }\r
daefd574 477 return EFI_SUCCESS;\r
3bb46df2 478 } else {\r
daefd574 479 return EFI_WARN_DELETE_FAILURE;\r
3bb46df2 480 }\r
2ef2b01e
A
481}\r
482\r
daefd574
RC
483/**\r
484 Read data from an open file.\r
485\r
486 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
487 is the file handle to read data from.\r
488 @param[in out] BufferSize On input, the size of the Buffer. On output, the\r
489 amount of data returned in Buffer. In both cases,\r
490 the size is measured in bytes.\r
491 @param[out] Buffer The buffer into which the data is read.\r
492\r
493 @retval EFI_SUCCESS The data was read.\r
494 @retval EFI_DEVICE_ERROR On entry, the current file position is\r
495 beyond the end of the file, or the semi-hosting\r
496 interface reported an error while performing the\r
497 read operation.\r
498 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.\r
499\r
500**/\r
2ef2b01e
A
501EFI_STATUS\r
502FileRead (\r
daefd574
RC
503 IN EFI_FILE *This,\r
504 IN OUT UINTN *BufferSize,\r
505 OUT VOID *Buffer\r
2ef2b01e
A
506 )\r
507{\r
daefd574
RC
508 SEMIHOST_FCB *Fcb;\r
509 EFI_STATUS Status;\r
510 RETURN_STATUS Return;\r
2ef2b01e 511\r
daefd574
RC
512 if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) {\r
513 return EFI_INVALID_PARAMETER;\r
514 }\r
2ef2b01e 515\r
daefd574
RC
516 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
517\r
518 if (Fcb->IsRoot) {\r
519 // The semi-hosting interface does not allow to list files on the host machine.\r
2ef2b01e
A
520 Status = EFI_UNSUPPORTED;\r
521 } else {\r
daefd574
RC
522 Status = EFI_SUCCESS;\r
523 if (Fcb->Position >= Fcb->Info.FileSize) {\r
524 *BufferSize = 0;\r
525 if (Fcb->Position > Fcb->Info.FileSize) {\r
526 Status = EFI_DEVICE_ERROR;\r
527 }\r
528 } else {\r
529 Return = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);\r
530 if (RETURN_ERROR (Return)) {\r
531 Status = EFI_DEVICE_ERROR;\r
532 } else {\r
533 Fcb->Position += *BufferSize;\r
534 }\r
2ef2b01e
A
535 }\r
536 }\r
537\r
538 return Status;\r
539}\r
540\r
daefd574
RC
541/**\r
542 Worker function that extends the size of an open file.\r
543\r
544 The extension is filled with zeros.\r
545\r
546 @param[in] Fcb Internal description of the opened file\r
547 @param[in] Size The number of bytes, the file has to be extended.\r
548\r
549 @retval EFI_SUCCESS The file was extended.\r
550 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
551\r
552**/\r
553STATIC\r
554EFI_STATUS\r
555ExtendFile (\r
556 IN SEMIHOST_FCB *Fcb,\r
557 IN UINTN Size\r
558 )\r
559{\r
560 RETURN_STATUS Return;\r
561 UINTN Remaining;\r
562 CHAR8 WriteBuffer[128];\r
563 UINTN WriteNb;\r
564 UINTN WriteSize;\r
565\r
566 Return = SemihostFileSeek (Fcb->SemihostHandle, Fcb->Info.FileSize);\r
567 if (RETURN_ERROR (Return)) {\r
568 return EFI_DEVICE_ERROR;\r
569 }\r
570\r
571 Remaining = Size;\r
572 SetMem (WriteBuffer, 0, sizeof(WriteBuffer));\r
573 while (Remaining > 0) {\r
574 WriteNb = MIN (Remaining, sizeof(WriteBuffer));\r
575 WriteSize = WriteNb;\r
576 Return = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, WriteBuffer);\r
577 if (RETURN_ERROR (Return)) {\r
578 return EFI_DEVICE_ERROR;\r
579 }\r
580 Remaining -= WriteNb;\r
581 }\r
582\r
583 return EFI_SUCCESS;\r
584}\r
585\r
586/**\r
587 Write data to an open file.\r
588\r
589 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
590 is the file handle to write data to.\r
591 @param[in out] BufferSize On input, the size of the Buffer. On output, the\r
592 size of the data actually written. In both cases,\r
593 the size is measured in bytes.\r
594 @param[in] Buffer The buffer of data to write.\r
595\r
596 @retval EFI_SUCCESS The data was written.\r
597 @retval EFI_ACCESS_DENIED Attempt to write into a read only file or\r
598 in a file opened in read only mode.\r
599 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
600 @retval EFI_INVALID_PARAMETER At least one of the three input pointers is NULL.\r
601\r
602**/\r
2ef2b01e
A
603EFI_STATUS\r
604FileWrite (\r
daefd574 605 IN EFI_FILE *This,\r
2ef2b01e
A
606 IN OUT UINTN *BufferSize,\r
607 IN VOID *Buffer\r
608 )\r
609{\r
daefd574
RC
610 SEMIHOST_FCB *Fcb;\r
611 EFI_STATUS Status;\r
612 UINTN WriteSize;\r
613 RETURN_STATUS Return;\r
614 UINTN Length;\r
2ef2b01e 615\r
daefd574
RC
616 if ((This == NULL) || (BufferSize == NULL) || (Buffer == NULL)) {\r
617 return EFI_INVALID_PARAMETER;\r
618 }\r
619\r
620 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
2ef2b01e 621\r
09f2cf82 622 // We cannot write a read-only file\r
cc271ec3
OM
623 if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY)\r
624 || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) {\r
09f2cf82 625 return EFI_ACCESS_DENIED;\r
626 }\r
627\r
daefd574
RC
628 //\r
629 // If the position has been set past the end of the file, first grow the\r
630 // file from its current size "Fcb->Info.FileSize" to "Fcb->Position"\r
631 // size, filling the gap with zeros.\r
632 //\r
633 if (Fcb->Position > Fcb->Info.FileSize) {\r
634 Status = ExtendFile (Fcb, Fcb->Position - Fcb->Info.FileSize);\r
635 if (EFI_ERROR (Status)) {\r
636 return Status;\r
637 }\r
638 Fcb->Info.FileSize = Fcb->Position;\r
639 }\r
2ef2b01e 640\r
daefd574
RC
641 WriteSize = *BufferSize;\r
642 Return = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);\r
643 if (RETURN_ERROR (Return)) {\r
644 return EFI_DEVICE_ERROR;\r
2ef2b01e 645 }\r
3402aac7 646\r
daefd574
RC
647 Fcb->Position += *BufferSize;\r
648 if (Fcb->Position > Fcb->Info.FileSize) {\r
649 Fcb->Info.FileSize = Fcb->Position;\r
650 }\r
651\r
652 Return = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
653 if (RETURN_ERROR (Return)) {\r
654 return EFI_DEVICE_ERROR;\r
655 }\r
656 Fcb->Info.PhysicalSize = Length;\r
657\r
658 return EFI_SUCCESS;\r
2ef2b01e
A
659}\r
660\r
daefd574
RC
661/**\r
662 Return a file's current position.\r
663\r
664 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
665 the file handle to get the current position on.\r
666 @param[out] Position The address to return the file's current position value.\r
667\r
668 @retval EFI_SUCCESS The position was returned.\r
669 @retval EFI_INVALID_PARAMETER The parameter "This" or "Position" is NULL.\r
670\r
671**/\r
2ef2b01e
A
672EFI_STATUS\r
673FileGetPosition (\r
daefd574 674 IN EFI_FILE *This,\r
2ef2b01e
A
675 OUT UINT64 *Position\r
676 )\r
677{\r
daefd574 678 SEMIHOST_FCB *Fcb;\r
3402aac7 679\r
daefd574 680 if ((This == NULL) || (Position == NULL)) {\r
2ef2b01e
A
681 return EFI_INVALID_PARAMETER;\r
682 }\r
683\r
daefd574 684 Fcb = SEMIHOST_FCB_FROM_THIS(This);\r
2ef2b01e
A
685\r
686 *Position = Fcb->Position;\r
687\r
688 return EFI_SUCCESS;\r
689}\r
690\r
daefd574
RC
691/**\r
692 Set a file's current position.\r
693\r
694 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that is\r
695 the file handle to set the requested position on.\r
696 @param[in] Position The byte position from the start of the file to set.\r
697\r
698 @retval EFI_SUCCESS The position was set.\r
699 @retval EFI_DEVICE_ERROR The semi-hosting positionning operation failed.\r
700 @retval EFI_UNSUPPORTED The seek request for nonzero is not valid on open\r
701 directories.\r
702 @retval EFI_INVALID_PARAMETER The parameter "This" is NULL.\r
703\r
704**/\r
2ef2b01e
A
705EFI_STATUS\r
706FileSetPosition (\r
daefd574 707 IN EFI_FILE *This,\r
2ef2b01e
A
708 IN UINT64 Position\r
709 )\r
710{\r
daefd574
RC
711 SEMIHOST_FCB *Fcb;\r
712 RETURN_STATUS Return;\r
2ef2b01e 713\r
daefd574
RC
714 if (This == NULL) {\r
715 return EFI_INVALID_PARAMETER;\r
716 }\r
2ef2b01e 717\r
daefd574 718 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
2ef2b01e 719\r
daefd574
RC
720 if (Fcb->IsRoot) {\r
721 if (Position != 0) {\r
722 return EFI_UNSUPPORTED;\r
723 }\r
724 }\r
725 else {\r
726 //\r
727 // UEFI Spec section 12.5:\r
728 // "Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to\r
729 // be set to the end of the file."\r
730 //\r
731 if (Position == 0xFFFFFFFFFFFFFFFF) {\r
732 Position = Fcb->Info.FileSize;\r
733 }\r
734 Return = SemihostFileSeek (Fcb->SemihostHandle, MIN (Position, Fcb->Info.FileSize));\r
735 if (RETURN_ERROR (Return)) {\r
736 return EFI_DEVICE_ERROR;\r
3bb46df2 737 }\r
2ef2b01e
A
738 }\r
739\r
daefd574
RC
740 Fcb->Position = Position;\r
741\r
742 return EFI_SUCCESS;\r
2ef2b01e
A
743}\r
744\r
daefd574
RC
745/**\r
746 Return information about a file.\r
747\r
748 @param[in] Fcb A pointer to the description of an open file.\r
749 @param[in out] BufferSize The size, in bytes, of Buffer.\r
750 @param[out] Buffer A pointer to the data buffer to return. Not NULL if\r
751 "*BufferSize" is greater than 0.\r
752\r
753 @retval EFI_SUCCESS The information was returned.\r
754 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.\r
755 BufferSize has been updated with the size needed to\r
756 complete the request.\r
757**/\r
2ef2b01e
A
758STATIC\r
759EFI_STATUS\r
760GetFileInfo (\r
761 IN SEMIHOST_FCB *Fcb,\r
daefd574
RC
762 IN OUT UINTN *BufferSize,\r
763 OUT VOID *Buffer\r
2ef2b01e
A
764 )\r
765{\r
766 EFI_FILE_INFO *Info = NULL;\r
767 UINTN NameSize = 0;\r
768 UINTN ResultSize;\r
769 UINTN Index;\r
2ef2b01e
A
770\r
771 if (Fcb->IsRoot == TRUE) {\r
772 ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);\r
773 } else {\r
774 NameSize = AsciiStrLen (Fcb->FileName) + 1;\r
775 ResultSize = SIZE_OF_EFI_FILE_INFO + NameSize * sizeof (CHAR16);\r
776 }\r
777\r
778 if (*BufferSize < ResultSize) {\r
779 *BufferSize = ResultSize;\r
780 return EFI_BUFFER_TOO_SMALL;\r
781 }\r
782\r
783 Info = Buffer;\r
784\r
09f2cf82 785 // Copy the current file info\r
786 CopyMem (Info, &Fcb->Info, SIZE_OF_EFI_FILE_INFO);\r
2ef2b01e
A
787\r
788 // Fill in the structure\r
789 Info->Size = ResultSize;\r
790\r
791 if (Fcb->IsRoot == TRUE) {\r
2ef2b01e
A
792 Info->FileName[0] = L'\0';\r
793 } else {\r
2ef2b01e 794 for (Index = 0; Index < NameSize; Index++) {\r
3402aac7 795 Info->FileName[Index] = Fcb->FileName[Index];\r
2ef2b01e
A
796 }\r
797 }\r
798\r
3402aac7 799 *BufferSize = ResultSize;\r
2ef2b01e
A
800\r
801 return EFI_SUCCESS;\r
802}\r
803\r
daefd574
RC
804/**\r
805 Return information about a file system.\r
806\r
807 @param[in] Fcb A pointer to the description of an open file\r
808 which belongs to the file system, the information\r
809 is requested for.\r
810 @param[in out] BufferSize The size, in bytes, of Buffer.\r
811 @param[out] Buffer A pointer to the data buffer to return. Not NULL if\r
812 "*BufferSize" is greater than 0.\r
813\r
814 @retval EFI_SUCCESS The information was returned.\r
815 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.\r
816 BufferSize has been updated with the size needed to\r
817 complete the request.\r
818\r
819**/\r
2ef2b01e
A
820STATIC\r
821EFI_STATUS\r
822GetFilesystemInfo (\r
823 IN SEMIHOST_FCB *Fcb,\r
824 IN OUT UINTN *BufferSize,\r
825 OUT VOID *Buffer\r
826 )\r
827{\r
daefd574
RC
828 EFI_FILE_SYSTEM_INFO *Info;\r
829 EFI_STATUS Status;\r
830 UINTN ResultSize;\r
831\r
832 ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (mSemihostFsLabel);\r
3402aac7 833\r
09f2cf82 834 if (*BufferSize >= ResultSize) {\r
2ef2b01e
A
835 ZeroMem (Buffer, ResultSize);\r
836 Status = EFI_SUCCESS;\r
3402aac7 837\r
2ef2b01e
A
838 Info = Buffer;\r
839\r
840 Info->Size = ResultSize;\r
841 Info->ReadOnly = FALSE;\r
842 Info->VolumeSize = 0;\r
843 Info->FreeSpace = 0;\r
844 Info->BlockSize = 0;\r
845\r
09f2cf82 846 StrCpy (Info->VolumeLabel, mSemihostFsLabel);\r
2ef2b01e
A
847 } else {\r
848 Status = EFI_BUFFER_TOO_SMALL;\r
849 }\r
850\r
3402aac7 851 *BufferSize = ResultSize;\r
2ef2b01e
A
852 return Status;\r
853}\r
854\r
daefd574
RC
855/**\r
856 Return information about a file or a file system.\r
857\r
858 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
859 is the file handle the requested information is for.\r
860 @param[in] InformationType The type identifier for the information being requested :\r
861 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or\r
862 EFI_FILE_SYSTEM_VOLUME_LABEL_ID\r
863 @param[in out] BufferSize The size, in bytes, of Buffer.\r
864 @param[out] Buffer A pointer to the data buffer to return. The type of the\r
865 data inside the buffer is indicated by InformationType.\r
866\r
867 @retval EFI_SUCCESS The information was returned.\r
868 @retval EFI_UNSUPPORTED The InformationType is not known.\r
869 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to return the information.\r
870 BufferSize has been updated with the size needed to\r
871 complete the request.\r
872 @retval EFI_INVALID_PARAMETER The parameter "This" or "InformationType" or "BufferSize"\r
873 is NULL or "Buffer" is NULL and "*Buffersize" is greater\r
874 than 0.\r
875\r
876**/\r
2ef2b01e
A
877EFI_STATUS\r
878FileGetInfo (\r
daefd574
RC
879 IN EFI_FILE *This,\r
880 IN EFI_GUID *InformationType,\r
881 IN OUT UINTN *BufferSize,\r
882 OUT VOID *Buffer\r
2ef2b01e
A
883 )\r
884{\r
09f2cf82 885 SEMIHOST_FCB *Fcb;\r
886 EFI_STATUS Status;\r
887 UINTN ResultSize;\r
3402aac7 888\r
daefd574
RC
889 if ((This == NULL) ||\r
890 (InformationType == NULL) ||\r
891 (BufferSize == NULL) ||\r
892 ((Buffer == NULL) && (*BufferSize > 0)) ) {\r
893 return EFI_INVALID_PARAMETER;\r
894 }\r
895\r
896 Fcb = SEMIHOST_FCB_FROM_THIS(This);\r
3402aac7 897\r
daefd574 898 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
09f2cf82 899 Status = GetFilesystemInfo (Fcb, BufferSize, Buffer);\r
daefd574 900 } else if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
09f2cf82 901 Status = GetFileInfo (Fcb, BufferSize, Buffer);\r
daefd574 902 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
09f2cf82 903 ResultSize = StrSize (mSemihostFsLabel);\r
904\r
905 if (*BufferSize >= ResultSize) {\r
906 StrCpy (Buffer, mSemihostFsLabel);\r
907 Status = EFI_SUCCESS;\r
908 } else {\r
909 Status = EFI_BUFFER_TOO_SMALL;\r
910 }\r
911\r
912 *BufferSize = ResultSize;\r
913 } else {\r
914 Status = EFI_UNSUPPORTED;\r
2ef2b01e 915 }\r
09f2cf82 916\r
2ef2b01e
A
917 return Status;\r
918}\r
919\r
daefd574
RC
920/**\r
921 Set information about a file.\r
922\r
923 @param[in] Fcb A pointer to the description of the open file.\r
924 @param[in] Info A pointer to the file information to write.\r
925\r
926 @retval EFI_SUCCESS The information was set.\r
927 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file\r
928 to a file that is already present.\r
929 @retval EFI_ACCESS_DENIED An attempt is being made to change the\r
930 EFI_FILE_DIRECTORY Attribute.\r
931 @retval EFI_ACCESS_DENIED The file is a read-only file or has been\r
932 opened in read-only mode and an attempt is\r
933 being made to modify a field other than\r
934 Attribute.\r
935 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a\r
936 read-only attribute.\r
937 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
938 @retval EFI_OUT_OF_RESOURCES A allocation needed to process the request failed.\r
939\r
940**/\r
941STATIC\r
942EFI_STATUS\r
943SetFileInfo (\r
944 IN SEMIHOST_FCB *Fcb,\r
945 IN EFI_FILE_INFO *Info\r
946 )\r
947{\r
948 EFI_STATUS Status;\r
949 RETURN_STATUS Return;\r
950 BOOLEAN FileSizeIsDifferent;\r
951 BOOLEAN FileNameIsDifferent;\r
952 BOOLEAN ReadOnlyIsDifferent;\r
953 CHAR8 *AsciiFileName;\r
954 UINTN FileSize;\r
955 UINTN Length;\r
956 UINTN SemihostHandle;\r
957\r
958 //\r
959 // A directory can not be changed to a file and a file can\r
960 // not be changed to a directory.\r
961 //\r
962 if (((Info->Attribute & EFI_FILE_DIRECTORY) != 0) != Fcb->IsRoot) {\r
963 return EFI_ACCESS_DENIED;\r
964 }\r
965\r
966 AsciiFileName = AllocatePool (StrLen (Info->FileName) + 1);\r
967 if (AsciiFileName == NULL) {\r
968 return EFI_OUT_OF_RESOURCES;\r
969 }\r
970 UnicodeStrToAsciiStr (Info->FileName, AsciiFileName);\r
971\r
972 FileSizeIsDifferent = (Info->FileSize != Fcb->Info.FileSize);\r
973 FileNameIsDifferent = (AsciiStrCmp (AsciiFileName, Fcb->FileName) != 0);\r
974 ReadOnlyIsDifferent = CompareMem (\r
975 &Info->CreateTime,\r
976 &Fcb->Info.CreateTime,\r
977 3 * sizeof (EFI_TIME)\r
978 ) != 0;\r
979\r
980 //\r
981 // For a read-only file or a file opened in read-only mode, only\r
982 // the Attribute field can be modified. As the root directory is\r
983 // read-only (i.e. VolumeOpen()), this protects the root directory\r
984 // description.\r
985 //\r
986 if ((Fcb->OpenMode == EFI_FILE_MODE_READ) ||\r
987 (Fcb->Info.Attribute & EFI_FILE_READ_ONLY) ) {\r
988 if (FileSizeIsDifferent || FileNameIsDifferent || ReadOnlyIsDifferent) {\r
989 Status = EFI_ACCESS_DENIED;\r
990 goto Error;\r
991 }\r
992 }\r
993\r
994 if (ReadOnlyIsDifferent) {\r
995 Status = EFI_WRITE_PROTECTED;\r
996 goto Error;\r
997 }\r
998\r
999 Status = EFI_DEVICE_ERROR;\r
1000\r
1001 if (FileSizeIsDifferent) {\r
1002 FileSize = Info->FileSize;\r
1003 if (Fcb->Info.FileSize < FileSize) {\r
1004 Status = ExtendFile (Fcb, FileSize - Fcb->Info.FileSize);\r
1005 if (EFI_ERROR (Status)) {\r
1006 goto Error;\r
1007 }\r
1008 //\r
1009 // The read/write position from the host file system point of view\r
1010 // is at the end of the file. If the position from this module\r
1011 // point of view is smaller than the new file size, then\r
1012 // ask the host file system to move to that position.\r
1013 //\r
1014 if (Fcb->Position < FileSize) {\r
1015 FileSetPosition (&Fcb->File, Fcb->Position);\r
1016 }\r
1017 }\r
1018 Fcb->Info.FileSize = FileSize;\r
1019\r
1020 Return = SemihostFileLength (Fcb->SemihostHandle, &Length);\r
1021 if (RETURN_ERROR (Return)) {\r
1022 goto Error;\r
1023 }\r
1024 Fcb->Info.PhysicalSize = Length;\r
1025 }\r
1026\r
1027 //\r
1028 // Note down in RAM the Attribute field but we can not ask\r
1029 // for its modification to the host file system as the\r
1030 // semi-host interface does not provide this feature.\r
1031 //\r
1032 Fcb->Info.Attribute = Info->Attribute;\r
1033\r
1034 if (FileNameIsDifferent) {\r
1035 Return = SemihostFileOpen (\r
1036 AsciiFileName,\r
1037 SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY,\r
1038 &SemihostHandle\r
1039 );\r
1040 if (!RETURN_ERROR (Return)) {\r
1041 SemihostFileClose (SemihostHandle);\r
1042 Status = EFI_ACCESS_DENIED;\r
1043 goto Error;\r
1044 }\r
1045\r
1046 Return = SemihostFileRename (Fcb->FileName, AsciiFileName);\r
1047 if (RETURN_ERROR (Return)) {\r
1048 goto Error;\r
1049 }\r
1050 FreePool (Fcb->FileName);\r
1051 Fcb->FileName = AsciiFileName;\r
1052 AsciiFileName = NULL;\r
1053 }\r
1054\r
1055 Status = EFI_SUCCESS;\r
1056\r
1057Error:\r
1058 if (AsciiFileName != NULL) {\r
1059 FreePool (AsciiFileName);\r
1060 }\r
1061\r
1062 return Status;\r
1063}\r
1064\r
1065/**\r
1066 Set information about a file or a file system.\r
1067\r
1068 @param[in] This A pointer to the EFI_FILE_PROTOCOL instance that\r
1069 is the file handle the information is for.\r
1070 @param[in] InformationType The type identifier for the information being set :\r
1071 EFI_FILE_INFO_ID or EFI_FILE_SYSTEM_INFO_ID or\r
1072 EFI_FILE_SYSTEM_VOLUME_LABEL_ID\r
1073 @param[in] BufferSize The size, in bytes, of Buffer.\r
1074 @param[in] Buffer A pointer to the data buffer to write. The type of the\r
1075 data inside the buffer is indicated by InformationType.\r
1076\r
1077 @retval EFI_SUCCESS The information was set.\r
1078 @retval EFI_UNSUPPORTED The InformationType is not known.\r
1079 @retval EFI_DEVICE_ERROR The last issued semi-hosting operation failed.\r
1080 @retval EFI_ACCESS_DENIED An attempt is being made to change the\r
1081 EFI_FILE_DIRECTORY Attribute.\r
1082 @retval EFI_ACCESS_DENIED InformationType is EFI_FILE_INFO_ID and\r
1083 the file is a read-only file or has been\r
1084 opened in read-only mode and an attempt is\r
1085 being made to modify a field other than\r
1086 Attribute.\r
1087 @retval EFI_ACCESS_DENIED An attempt is made to change the name of a file\r
1088 to a file that is already present.\r
1089 @retval EFI_WRITE_PROTECTED An attempt is being made to modify a\r
1090 read-only attribute.\r
1091 @retval EFI_BAD_BUFFER_SIZE The size of the buffer is lower than that indicated by\r
1092 the data inside the buffer.\r
1093 @retval EFI_OUT_OF_RESOURCES An allocation needed to process the request failed.\r
1094 @retval EFI_INVALID_PARAMETER At least one of the parameters is invalid.\r
1095\r
1096**/\r
2ef2b01e
A
1097EFI_STATUS\r
1098FileSetInfo (\r
daefd574
RC
1099 IN EFI_FILE *This,\r
1100 IN EFI_GUID *InformationType,\r
1101 IN UINTN BufferSize,\r
1102 IN VOID *Buffer\r
2ef2b01e
A
1103 )\r
1104{\r
daefd574
RC
1105 SEMIHOST_FCB *Fcb;\r
1106 EFI_FILE_INFO *Info;\r
1107 EFI_FILE_SYSTEM_INFO *SystemInfo;\r
1108 CHAR16 *VolumeLabel;\r
09f2cf82 1109\r
daefd574 1110 if ((This == NULL) || (InformationType == NULL) || (Buffer == NULL)) {\r
09f2cf82 1111 return EFI_INVALID_PARAMETER;\r
1112 }\r
1113\r
daefd574
RC
1114 Fcb = SEMIHOST_FCB_FROM_THIS (This);\r
1115\r
1116 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
1117 Info = Buffer;\r
1118 if (Info->Size < (SIZE_OF_EFI_FILE_INFO + StrSize (Info->FileName))) {\r
1119 return EFI_INVALID_PARAMETER;\r
1120 }\r
1121 if (BufferSize < Info->Size) {\r
1122 return EFI_BAD_BUFFER_SIZE;\r
1123 }\r
1124 return SetFileInfo (Fcb, Info);\r
1125 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
1126 SystemInfo = Buffer;\r
1127 if (SystemInfo->Size <\r
1128 (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (SystemInfo->VolumeLabel))) {\r
1129 return EFI_INVALID_PARAMETER;\r
1130 }\r
1131 if (BufferSize < SystemInfo->Size) {\r
1132 return EFI_BAD_BUFFER_SIZE;\r
1133 }\r
1134 Buffer = SystemInfo->VolumeLabel;\r
09f2cf82 1135\r
09f2cf82 1136 if (StrSize (Buffer) > 0) {\r
daefd574
RC
1137 VolumeLabel = AllocateCopyPool (StrSize (Buffer), Buffer);\r
1138 if (VolumeLabel != NULL) {\r
1139 FreePool (mSemihostFsLabel);\r
1140 mSemihostFsLabel = VolumeLabel;\r
1141 return EFI_SUCCESS;\r
1142 } else {\r
1143 return EFI_OUT_OF_RESOURCES;\r
1144 }\r
1145 } else {\r
1146 return EFI_INVALID_PARAMETER;\r
09f2cf82 1147 }\r
daefd574
RC
1148 } else if (!CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {\r
1149 return EFI_UNSUPPORTED;\r
1150 } else {\r
1151 return EFI_UNSUPPORTED;\r
09f2cf82 1152 }\r
2ef2b01e
A
1153}\r
1154\r
1155EFI_STATUS\r
1156FileFlush (\r
1157 IN EFI_FILE *File\r
1158 )\r
1159{\r
09f2cf82 1160 SEMIHOST_FCB *Fcb;\r
1161\r
1162 Fcb = SEMIHOST_FCB_FROM_THIS(File);\r
1163\r
1164 if (Fcb->IsRoot) {\r
1165 return EFI_SUCCESS;\r
1166 } else {\r
cc271ec3
OM
1167 if ((Fcb->Info.Attribute & EFI_FILE_READ_ONLY)\r
1168 || !(Fcb->OpenMode & EFI_FILE_MODE_WRITE)) {\r
09f2cf82 1169 return EFI_ACCESS_DENIED;\r
1170 } else {\r
1171 return EFI_SUCCESS;\r
1172 }\r
1173 }\r
2ef2b01e
A
1174}\r
1175\r
1176EFI_STATUS\r
1177SemihostFsEntryPoint (\r
1178 IN EFI_HANDLE ImageHandle,\r
1179 IN EFI_SYSTEM_TABLE *SystemTable\r
1180 )\r
1181{\r
09f2cf82 1182 EFI_STATUS Status;\r
1183\r
1184 Status = EFI_NOT_FOUND;\r
2ef2b01e
A
1185\r
1186 if (SemihostConnectionSupported ()) {\r
09f2cf82 1187 mSemihostFsLabel = AllocateCopyPool (StrSize (DEFAULT_SEMIHOST_FS_LABEL), DEFAULT_SEMIHOST_FS_LABEL);\r
1188 if (mSemihostFsLabel == NULL) {\r
1189 return EFI_OUT_OF_RESOURCES;\r
1190 }\r
1191\r
2ef2b01e 1192 Status = gBS->InstallMultipleProtocolInterfaces (\r
3402aac7
RC
1193 &gInstallHandle,\r
1194 &gEfiSimpleFileSystemProtocolGuid, &gSemihostFs,\r
2ef2b01e
A
1195 &gEfiDevicePathProtocolGuid, &gDevicePath,\r
1196 NULL\r
1197 );\r
09f2cf82 1198\r
1199 if (EFI_ERROR(Status)) {\r
1200 FreePool (mSemihostFsLabel);\r
1201 }\r
2ef2b01e 1202 }\r
3402aac7 1203\r
2ef2b01e
A
1204 return Status;\r
1205}\r