OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
VirtualDir.c
Go to the documentation of this file.
1
15#include <Uefi.h>
16
17#include <Library/BaseLib.h>
18#include <Library/BaseMemoryLib.h>
19#include <Library/BaseOverflowLib.h>
20#include <Library/DebugLib.h>
21#include <Library/MemoryAllocationLib.h>
22#include <Library/UefiBootServicesTableLib.h>
23#include <Library/UefiRuntimeServicesTableLib.h>
24#include <Library/OcFileLib.h>
26
27#include <Guid/FileInfo.h>
28
29#include "VirtualFsInternal.h"
30
31STATIC
32EFI_STATUS
33EFIAPI
35 IN EFI_FILE_PROTOCOL *This,
36 OUT EFI_FILE_PROTOCOL **NewHandle,
37 IN CHAR16 *FileName,
38 IN UINT64 OpenMode,
39 IN UINT64 Attributes
40 )
41{
42 EFI_STATUS Status;
43 VIRTUAL_DIR_DATA *Data;
44
45 if ((This == NULL) || (NewHandle == NULL) || (FileName == NULL)) {
46 return EFI_INVALID_PARAMETER;
47 }
48
49 Data = VIRTUAL_DIR_FROM_PROTOCOL (This);
50
51 if (Data->UnderlyingProtocol != NULL) {
52 Status = Data->UnderlyingProtocol->Open (
54 NewHandle,
55 FileName,
56 OpenMode,
57 Attributes
58 );
59 if (!EFI_ERROR (Status)) {
60 return CreateRealFile (*NewHandle, NULL, TRUE, NewHandle);
61 }
62
63 return Status;
64 }
65
66 //
67 // Cannot currently handle any virtualized files in directory.
68 //
69 return EFI_NOT_FOUND;
70}
71
72STATIC
73EFI_STATUS
74EFIAPI
76 IN EFI_FILE_PROTOCOL *This
77 )
78{
79 EFI_STATUS Status;
80 VIRTUAL_DIR_DATA *Data;
81
82 if (This == NULL) {
83 return EFI_INVALID_PARAMETER;
84 }
85
86 Data = VIRTUAL_DIR_FROM_PROTOCOL (This);
87
88 if (Data->UnderlyingProtocol != NULL) {
89 Status = Data->UnderlyingProtocol->Close (
91 );
92 if (EFI_ERROR (Status)) {
93 return Status;
94 }
95 }
96
97 VirtualDirFree (This);
98
99 return EFI_SUCCESS;
100}
101
102STATIC
103EFI_STATUS
104EFIAPI
106 IN EFI_FILE_PROTOCOL *This
107 )
108{
109 EFI_STATUS Status;
110
111 Status = VirtualDirClose (This);
112 if (EFI_ERROR (Status)) {
113 return Status;
114 }
115
116 //
117 // Virtual directories cannot be deleted.
118 //
119 return EFI_WARN_DELETE_FAILURE;
120}
121
122STATIC
123EFI_STATUS
124EFIAPI
126 IN EFI_FILE_PROTOCOL *This,
127 IN OUT UINTN *BufferSize,
128 OUT VOID *Buffer
129 )
130{
131 EFI_STATUS Status;
132 VIRTUAL_DIR_DATA *Data;
133 LIST_ENTRY *DirEntryLink;
134 VIRTUAL_DIR_ENTRY *DirEntry;
135 UINTN ReadSize;
136 UINTN FileStrSize;
137
138 if ( (This == NULL)
139 || (BufferSize == NULL))
140 {
141 return EFI_INVALID_PARAMETER;
142 }
143
144 Data = VIRTUAL_DIR_FROM_PROTOCOL (This);
145
146 //
147 // If our entry position is zero, try to read underlying protocol first.
148 //
149 ReadSize = *BufferSize;
150 if ((Data->CurrentEntry == NULL) && (Data->UnderlyingProtocol != NULL)) {
151 Status = Data->UnderlyingProtocol->Read (
152 Data->UnderlyingProtocol,
153 BufferSize,
154 Buffer
155 );
156
157 if (EFI_ERROR (Status) || (*BufferSize != 0)) {
158 return Status;
159 }
160 }
161
162 //
163 // Ensure we have any entries at all.
164 //
165 if (IsListEmpty (&Data->Entries)) {
166 *BufferSize = 0;
167 return EFI_SUCCESS;
168 }
169
170 //
171 // End of directory.
172 //
173 if ((Data->CurrentEntry != NULL) && IsNodeAtEnd (&Data->Entries, Data->CurrentEntry)) {
174 Data->CurrentEntry = NULL;
175
176 *BufferSize = 0;
177 return EFI_SUCCESS;
178 }
179
180 *BufferSize = ReadSize;
181 DirEntryLink = Data->CurrentEntry != NULL ? GetNextNode (&Data->Entries, Data->CurrentEntry) : GetFirstNode (&Data->Entries);
182
183 //
184 // Get next file info structure.
185 //
186 DirEntry = GET_VIRTUAL_DIR_ENTRY_FROM_LINK (DirEntryLink);
187 if (DirEntry->FileInfo->Size < SIZE_OF_EFI_FILE_INFO) {
188 return EFI_DEVICE_ERROR;
189 }
190
191 //
192 // Ensure entry size matches string length.
193 //
194 FileStrSize = StrSize (DirEntry->FileInfo->FileName);
195 if (BaseOverflowAddUN (SIZE_OF_EFI_FILE_INFO, FileStrSize, &ReadSize) || (ReadSize != DirEntry->FileInfo->Size)) {
196 return EFI_DEVICE_ERROR;
197 }
198
199 if (*BufferSize < ReadSize) {
200 *BufferSize = ReadSize;
201 return EFI_BUFFER_TOO_SMALL;
202 }
203
204 if (Buffer == NULL) {
205 return EFI_INVALID_PARAMETER;
206 }
207
208 //
209 // Copy entry to buffer and advance to next entry.
210 //
211 CopyMem (Buffer, DirEntry->FileInfo, ReadSize);
212 *BufferSize = ReadSize;
213
214 Data->CurrentEntry = DirEntryLink;
215 return EFI_SUCCESS;
216}
217
218STATIC
219EFI_STATUS
220EFIAPI
222 IN EFI_FILE_PROTOCOL *This,
223 IN OUT UINTN *BufferSize,
224 IN VOID *Buffer
225 )
226{
227 //
228 // Directories are not writeable.
229 //
230 return EFI_UNSUPPORTED;
231}
232
233STATIC
234EFI_STATUS
235EFIAPI
237 IN EFI_FILE_PROTOCOL *This,
238 IN UINT64 Position
239 )
240{
241 EFI_STATUS Status;
242 VIRTUAL_DIR_DATA *Data;
243
244 if (This == NULL) {
245 return EFI_INVALID_PARAMETER;
246 }
247
248 Data = VIRTUAL_DIR_FROM_PROTOCOL (This);
249
250 //
251 // Non-zero requests are not supported for directories.
252 //
253 if (Position > 0) {
254 return EFI_UNSUPPORTED;
255 }
256
257 Status = EFI_SUCCESS;
258 if (Data->UnderlyingProtocol != NULL) {
259 Status = Data->UnderlyingProtocol->SetPosition (
260 Data->UnderlyingProtocol,
261 0
262 );
263 }
264
265 if (!EFI_ERROR (Status)) {
266 Data->CurrentEntry = NULL;
267 }
268
269 return Status;
270}
271
272STATIC
273EFI_STATUS
274EFIAPI
276 IN EFI_FILE_PROTOCOL *This,
277 OUT UINT64 *Position
278 )
279{
280 //
281 // Not valid for directories.
282 //
283 return EFI_UNSUPPORTED;
284}
285
286STATIC
287EFI_STATUS
288EFIAPI
290 IN EFI_FILE_PROTOCOL *This,
291 IN EFI_GUID *InformationType,
292 IN OUT UINTN *BufferSize,
293 OUT VOID *Buffer
294 )
295{
296 VIRTUAL_DIR_DATA *Data;
297 UINTN InfoSize;
298 UINTN NameSize;
299 EFI_FILE_INFO *FileInfo;
300 BOOLEAN Fits;
301
302 if ( (This == NULL)
303 || (InformationType == NULL)
304 || (BufferSize == NULL))
305 {
306 return EFI_INVALID_PARAMETER;
307 }
308
309 Data = VIRTUAL_DIR_FROM_PROTOCOL (This);
310
311 //
312 // Get underlying protocol info.
313 //
314 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
316 sizeof (FileInfo->FileName) == sizeof (CHAR16),
317 "Header changed, flexible array member is now supported"
318 );
319
320 NameSize = StrSize (Data->FileName);
321 InfoSize = SIZE_OF_EFI_FILE_INFO + NameSize;
322 Fits = *BufferSize >= InfoSize;
323 *BufferSize = InfoSize;
324
325 if (!Fits) {
326 return EFI_BUFFER_TOO_SMALL;
327 }
328
329 if (Buffer == NULL) {
330 return EFI_INVALID_PARAMETER;
331 }
332
333 FileInfo = (EFI_FILE_INFO *)Buffer;
334
335 ZeroMem (FileInfo, InfoSize - NameSize);
336 FileInfo->Size = InfoSize;
337
338 CopyMem (&FileInfo->CreateTime, &Data->ModificationTime, sizeof (FileInfo->ModificationTime));
339 CopyMem (&FileInfo->LastAccessTime, &Data->ModificationTime, sizeof (FileInfo->ModificationTime));
340 CopyMem (&FileInfo->ModificationTime, &Data->ModificationTime, sizeof (FileInfo->ModificationTime));
341
342 //
343 // Return zeroes for timestamps.
344 //
345 FileInfo->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
346 CopyMem (&FileInfo->FileName[0], Data->FileName, NameSize);
347
348 return EFI_SUCCESS;
349 }
350
351 return EFI_UNSUPPORTED;
352}
353
354STATIC
355EFI_STATUS
356EFIAPI
358 IN EFI_FILE_PROTOCOL *This,
359 IN EFI_GUID *InformationType,
360 IN UINTN BufferSize,
361 IN VOID *Buffer
362 )
363{
364 //
365 // Virtual directories are not writeable, this applies to info.
366 //
367 return EFI_WRITE_PROTECTED;
368}
369
370STATIC
371EFI_STATUS
372EFIAPI
374 IN EFI_FILE_PROTOCOL *This
375 )
376{
377 //
378 // Virtual directories are not writeable.
379 //
380 return EFI_WRITE_PROTECTED;
381}
382
383STATIC
384EFI_STATUS
385EFIAPI
387 IN EFI_FILE_PROTOCOL *This,
388 OUT EFI_FILE_PROTOCOL **NewHandle,
389 IN CHAR16 *FileName,
390 IN UINT64 OpenMode,
391 IN UINT64 Attributes,
392 IN OUT EFI_FILE_IO_TOKEN *Token
393 )
394{
395 EFI_STATUS Status;
396
397 //
398 // Ignore asynchronous interface for now.
399 //
400 // WARN: Unlike Open for OpenEx UEFI 2.7A explicitly dicates EFI_NO_MEDIA for
401 // "The specified file could not be found on the device." error case.
402 // We do not care for simplicity.
403 //
404 Status = VirtualDirOpen (
405 This,
406 NewHandle,
407 FileName,
408 OpenMode,
409 Attributes
410 );
411
412 if (!EFI_ERROR (Status) && (Token->Event != NULL)) {
413 Token->Status = EFI_SUCCESS;
414 gBS->SignalEvent (Token->Event);
415 }
416
417 return Status;
418}
419
420STATIC
421EFI_STATUS
422EFIAPI
424 IN EFI_FILE_PROTOCOL *This,
425 IN OUT EFI_FILE_IO_TOKEN *Token
426 )
427{
428 EFI_STATUS Status;
429
430 if ( (This == NULL)
431 || (Token == NULL))
432 {
433 return EFI_INVALID_PARAMETER;
434 }
435
436 Status = VirtualDirRead (This, Token->Buffer, &Token->BufferSize);
437
438 if (!EFI_ERROR (Status) && (Token->Event != NULL)) {
439 Token->Status = EFI_SUCCESS;
440 gBS->SignalEvent (Token->Event);
441 }
442
443 return Status;
444}
445
446STATIC
447EFI_STATUS
448EFIAPI
450 IN EFI_FILE_PROTOCOL *This,
451 IN OUT EFI_FILE_IO_TOKEN *Token
452 )
453{
454 //
455 // Directories are not writeable.
456 //
457 return EFI_UNSUPPORTED;
458}
459
460STATIC
461EFI_STATUS
462EFIAPI
464 IN EFI_FILE_PROTOCOL *This,
465 IN OUT EFI_FILE_IO_TOKEN *Token
466 )
467{
468 //
469 // Virtual directories are not writeable.
470 //
471 return EFI_WRITE_PROTECTED;
472}
473
474STATIC
475CONST
476EFI_FILE_PROTOCOL
478 .Revision = EFI_FILE_PROTOCOL_REVISION2,
479 .Open = VirtualDirOpen,
480 .Close = VirtualDirClose,
481 .Delete = VirtualDirDelete,
482 .Read = VirtualDirRead,
483 .Write = VirtualDirWrite,
484 .GetPosition = VirtualDirGetPosition,
485 .SetPosition = VirtualDirSetPosition,
486 .GetInfo = VirtualDirGetInfo,
487 .SetInfo = VirtualDirSetInfo,
488 .Flush = VirtualDirFlush,
489 .OpenEx = VirtualDirOpenEx,
490 .ReadEx = VirtualDirReadEx,
491 .WriteEx = VirtualDirWriteEx,
492 .FlushEx = VirtualDirFlushEx
493};
494
495EFI_STATUS
497 IN CHAR16 *FileName,
498 IN CONST EFI_TIME *ModificationTime OPTIONAL,
499 IN EFI_FILE_PROTOCOL *UnderlyingFile OPTIONAL,
500 OUT EFI_FILE_PROTOCOL **File
501 )
502{
503 VIRTUAL_DIR_DATA *Data;
504
505 ASSERT (FileName != NULL);
506 ASSERT (File != NULL);
507
508 Data = AllocatePool (sizeof (VIRTUAL_DIR_DATA));
509
510 if (Data == NULL) {
511 return EFI_OUT_OF_RESOURCES;
512 }
513
515 Data->FileName = FileName;
516 Data->CurrentEntry = NULL;
517 Data->UnderlyingProtocol = UnderlyingFile;
518 InitializeListHead (&Data->Entries);
519 CopyMem (&Data->Protocol, &mVirtualDirProtocolTemplate, sizeof (Data->Protocol));
520 if (ModificationTime != NULL) {
521 CopyMem (&Data->ModificationTime, ModificationTime, sizeof (*ModificationTime));
522 } else {
523 ZeroMem (&Data->ModificationTime, sizeof (*ModificationTime));
524 }
525
526 *File = &Data->Protocol;
527 return EFI_SUCCESS;
528}
529
530EFI_STATUS
532 IN CONST CHAR16 *FileName,
533 IN CONST EFI_TIME *ModificationTime OPTIONAL,
534 IN EFI_FILE_PROTOCOL *UnderlyingFile OPTIONAL,
535 OUT EFI_FILE_PROTOCOL **File
536 )
537{
538 EFI_STATUS Status;
539 CHAR16 *FileNameCopy;
540
541 ASSERT (FileName != NULL);
542 ASSERT (File != NULL);
543
544 FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);
545 if (FileNameCopy == NULL) {
546 DEBUG ((DEBUG_WARN, "OCVFS: Failed to allocate directory name (%a) copy\n", FileName));
547 return EFI_OUT_OF_RESOURCES;
548 }
549
550 Status = VirtualDirCreateOverlay (FileNameCopy, ModificationTime, UnderlyingFile, File);
551 if (EFI_ERROR (Status)) {
552 DEBUG ((DEBUG_WARN, "OCVFS: Failed to virtualise directory (%a)\n", FileName));
553 FreePool (FileNameCopy);
554 return EFI_OUT_OF_RESOURCES;
555 }
556
557 return Status;
558}
559
560EFI_STATUS
562 IN EFI_FILE_PROTOCOL *This,
563 IN EFI_FILE_INFO *FileInfo
564 )
565{
566 VIRTUAL_DIR_DATA *Data;
567 VIRTUAL_DIR_ENTRY *NewEntry;
568
569 ASSERT (This != NULL);
570 ASSERT (FileInfo != NULL);
571
572 Data = VIRTUAL_DIR_FROM_PROTOCOL (This);
573
574 NewEntry = AllocateZeroPool (sizeof (*NewEntry));
575 if (NewEntry == NULL) {
576 return EFI_OUT_OF_RESOURCES;
577 }
578
580 NewEntry->FileInfo = FileInfo;
581
582 InsertTailList (&Data->Entries, &NewEntry->Link);
583 return EFI_SUCCESS;
584}
585
586VOID
588 IN EFI_FILE_PROTOCOL *This
589 )
590{
591 VIRTUAL_DIR_DATA *Data;
592 LIST_ENTRY *DirEntryLink;
593 VIRTUAL_DIR_ENTRY *DirEntry;
594
595 ASSERT (This != NULL);
596
597 Data = VIRTUAL_DIR_FROM_PROTOCOL (This);
598
599 while (!IsListEmpty (&Data->Entries)) {
600 DirEntryLink = GetFirstNode (&Data->Entries);
601 DirEntry = GET_VIRTUAL_DIR_ENTRY_FROM_LINK (DirEntryLink);
602 RemoveEntryList (DirEntryLink);
603
604 if (DirEntry->FileInfo != NULL) {
605 FreePool (DirEntry->FileInfo);
606 }
607
608 FreePool (DirEntry);
609 }
610
611 FreePool (Data->FileName);
612 FreePool (Data);
613}
STATIC_ASSERT(BYTES_PER_PIXEL==sizeof(UINT32), "Non 4-byte pixels are unsupported!")
EFI_BOOT_SERVICES * gBS
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
EFI_STATUS CreateRealFile(IN EFI_FILE_PROTOCOL *OriginalFile OPTIONAL, IN EFI_FILE_OPEN OpenCallback OPTIONAL, IN BOOLEAN CloseOnFailure, OUT EFI_FILE_PROTOCOL **File)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_GUID gEfiFileInfoGuid
EFI_STATUS VirtualDirAddEntry(IN EFI_FILE_PROTOCOL *This, IN EFI_FILE_INFO *FileInfo)
Definition VirtualDir.c:561
EFI_STATUS VirtualDirCreateOverlay(IN CHAR16 *FileName, IN CONST EFI_TIME *ModificationTime OPTIONAL, IN EFI_FILE_PROTOCOL *UnderlyingFile OPTIONAL, OUT EFI_FILE_PROTOCOL **File)
Definition VirtualDir.c:496
STATIC EFI_STATUS EFIAPI VirtualDirSetInfo(IN EFI_FILE_PROTOCOL *This, IN EFI_GUID *InformationType, IN UINTN BufferSize, IN VOID *Buffer)
Definition VirtualDir.c:357
STATIC EFI_STATUS EFIAPI VirtualDirFlush(IN EFI_FILE_PROTOCOL *This)
Definition VirtualDir.c:373
STATIC EFI_STATUS EFIAPI VirtualDirOpenEx(IN EFI_FILE_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes, IN OUT EFI_FILE_IO_TOKEN *Token)
Definition VirtualDir.c:386
STATIC EFI_STATUS EFIAPI VirtualDirWriteEx(IN EFI_FILE_PROTOCOL *This, IN OUT EFI_FILE_IO_TOKEN *Token)
Definition VirtualDir.c:449
STATIC EFI_STATUS EFIAPI VirtualDirGetPosition(IN EFI_FILE_PROTOCOL *This, OUT UINT64 *Position)
Definition VirtualDir.c:275
STATIC EFI_STATUS EFIAPI VirtualDirReadEx(IN EFI_FILE_PROTOCOL *This, IN OUT EFI_FILE_IO_TOKEN *Token)
Definition VirtualDir.c:423
STATIC EFI_STATUS EFIAPI VirtualDirSetPosition(IN EFI_FILE_PROTOCOL *This, IN UINT64 Position)
Definition VirtualDir.c:236
STATIC EFI_STATUS EFIAPI VirtualDirWrite(IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, IN VOID *Buffer)
Definition VirtualDir.c:221
EFI_STATUS VirtualDirCreateOverlayFileNameCopy(IN CONST CHAR16 *FileName, IN CONST EFI_TIME *ModificationTime OPTIONAL, IN EFI_FILE_PROTOCOL *UnderlyingFile OPTIONAL, OUT EFI_FILE_PROTOCOL **File)
Definition VirtualDir.c:531
VOID VirtualDirFree(IN EFI_FILE_PROTOCOL *This)
Definition VirtualDir.c:587
STATIC CONST EFI_FILE_PROTOCOL mVirtualDirProtocolTemplate
Definition VirtualDir.c:477
STATIC EFI_STATUS EFIAPI VirtualDirOpen(IN EFI_FILE_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes)
Definition VirtualDir.c:34
STATIC EFI_STATUS EFIAPI VirtualDirGetInfo(IN EFI_FILE_PROTOCOL *This, IN EFI_GUID *InformationType, IN OUT UINTN *BufferSize, OUT VOID *Buffer)
Definition VirtualDir.c:289
STATIC EFI_STATUS EFIAPI VirtualDirClose(IN EFI_FILE_PROTOCOL *This)
Definition VirtualDir.c:75
STATIC EFI_STATUS EFIAPI VirtualDirRead(IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer)
Definition VirtualDir.c:125
STATIC EFI_STATUS EFIAPI VirtualDirFlushEx(IN EFI_FILE_PROTOCOL *This, IN OUT EFI_FILE_IO_TOKEN *Token)
Definition VirtualDir.c:463
STATIC EFI_STATUS EFIAPI VirtualDirDelete(IN EFI_FILE_PROTOCOL *This)
Definition VirtualDir.c:105
#define VIRTUAL_DIR_DATA_SIGNATURE
#define GET_VIRTUAL_DIR_ENTRY_FROM_LINK(This)
#define VIRTUAL_DIR_ENTRY_SIGNATURE
#define VIRTUAL_DIR_FROM_PROTOCOL(This)
#define ASSERT(x)
Definition coder.h:55
EFI_FILE_PROTOCOL Protocol
LIST_ENTRY * CurrentEntry
EFI_FILE_PROTOCOL * UnderlyingProtocol
EFI_FILE_INFO * FileInfo