TianoCore EDK2 master
Loading...
Searching...
No Matches
SimpleFsOpen.c
Go to the documentation of this file.
1
9#include <Library/BaseLib.h> // AsciiStrCmp()
10#include <Library/MemoryAllocationLib.h> // AllocatePool()
11
12#include "VirtioFsDxe.h"
13
41 IN OUT VIRTIO_FS *VirtioFs,
42 OUT EFI_FILE_PROTOCOL **NewHandle,
43 IN BOOLEAN OpenForWriting
44 )
45{
46 EFI_STATUS Status;
47 VIRTIO_FS_FILE *NewVirtioFsFile;
48
49 //
50 // VirtioFsOpenVolume() opens the root directory for read-only access. If the
51 // current request is to open the root directory for read-write access, so
52 // that EFI_FILE_PROTOCOL.Flush() or EFI_FILE_PROTOCOL.SetInfo()+timestamps
53 // can be used on the root directory later, then we have to check for write
54 // permission first.
55 //
56 if (OpenForWriting) {
59
60 Status = VirtioFsFuseGetAttr (
61 VirtioFs,
62 VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID,
63 &FuseAttr
64 );
65 if (EFI_ERROR (Status)) {
66 return Status;
67 }
68
69 Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
70 if (EFI_ERROR (Status)) {
71 return Status;
72 }
73
74 if ((FileInfo.Attribute & EFI_FILE_READ_ONLY) != 0) {
75 return EFI_ACCESS_DENIED;
76 }
77 }
78
79 Status = VirtioFsOpenVolume (&VirtioFs->SimpleFs, NewHandle);
80 if (EFI_ERROR (Status)) {
81 return Status;
82 }
83
84 NewVirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (*NewHandle);
85 NewVirtioFsFile->IsOpenForWriting = OpenForWriting;
86 return EFI_SUCCESS;
87}
88
137STATIC
140 IN OUT VIRTIO_FS *VirtioFs,
141 IN UINT64 DirNodeId,
142 IN CHAR8 *Name,
143 IN BOOLEAN OpenForWriting,
144 OUT UINT64 *NodeId,
145 OUT UINT64 *FuseHandle,
146 OUT BOOLEAN *NodeIsDirectory
147 )
148{
149 EFI_STATUS Status;
150 UINT64 ResolvedNodeId;
153 BOOLEAN IsDirectory;
154 UINT64 NewFuseHandle;
155
156 Status = VirtioFsFuseLookup (
157 VirtioFs,
158 DirNodeId,
159 Name,
160 &ResolvedNodeId,
161 &FuseAttr
162 );
163 if (EFI_ERROR (Status)) {
164 return Status;
165 }
166
167 Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
168 if (EFI_ERROR (Status)) {
169 goto ForgetResolvedNodeId;
170 }
171
172 if (OpenForWriting && ((FileInfo.Attribute & EFI_FILE_READ_ONLY) != 0)) {
173 Status = EFI_ACCESS_DENIED;
174 goto ForgetResolvedNodeId;
175 }
176
177 IsDirectory = (BOOLEAN)((FileInfo.Attribute & EFI_FILE_DIRECTORY) != 0);
178 if (IsDirectory) {
179 //
180 // If OpenForWriting is TRUE here, that's not passed to
181 // VirtioFsFuseOpenDir(); it does not affect the FUSE_OPENDIR request we
182 // send. OpenForWriting=TRUE will only permit attempts to delete, rename,
183 // flush (sync), and touch the directory.
184 //
185 Status = VirtioFsFuseOpenDir (VirtioFs, ResolvedNodeId, &NewFuseHandle);
186 } else {
187 Status = VirtioFsFuseOpen (
188 VirtioFs,
189 ResolvedNodeId,
190 OpenForWriting,
191 &NewFuseHandle
192 );
193 }
194
195 if (EFI_ERROR (Status)) {
196 goto ForgetResolvedNodeId;
197 }
198
199 *NodeId = ResolvedNodeId;
200 *FuseHandle = NewFuseHandle;
201 *NodeIsDirectory = IsDirectory;
202 return EFI_SUCCESS;
203
204ForgetResolvedNodeId:
205 VirtioFsFuseForget (VirtioFs, ResolvedNodeId);
206 return (Status == EFI_NOT_FOUND) ? EFI_DEVICE_ERROR : Status;
207}
208
232STATIC
235 IN OUT VIRTIO_FS *VirtioFs,
236 IN UINT64 DirNodeId,
237 IN CHAR8 *Name,
238 OUT UINT64 *NodeId,
239 OUT UINT64 *FuseHandle
240 )
241{
242 EFI_STATUS Status;
243 UINT64 NewChildDirNodeId;
244 UINT64 NewFuseHandle;
245
246 Status = VirtioFsFuseMkDir (VirtioFs, DirNodeId, Name, &NewChildDirNodeId);
247 if (EFI_ERROR (Status)) {
248 return Status;
249 }
250
251 Status = VirtioFsFuseOpenDir (VirtioFs, NewChildDirNodeId, &NewFuseHandle);
252 if (EFI_ERROR (Status)) {
253 goto RemoveNewChildDir;
254 }
255
256 *NodeId = NewChildDirNodeId;
257 *FuseHandle = NewFuseHandle;
258 return EFI_SUCCESS;
259
260RemoveNewChildDir:
261 VirtioFsFuseRemoveFileOrDir (VirtioFs, DirNodeId, Name, TRUE /* IsDir */);
262 VirtioFsFuseForget (VirtioFs, NewChildDirNodeId);
263 return Status;
264}
265
289STATIC
292 IN OUT VIRTIO_FS *VirtioFs,
293 IN UINT64 DirNodeId,
294 IN CHAR8 *Name,
295 OUT UINT64 *NodeId,
296 OUT UINT64 *FuseHandle
297 )
298{
300 VirtioFs,
301 DirNodeId,
302 Name,
303 NodeId,
304 FuseHandle
305 );
306}
307
309EFIAPI
310VirtioFsSimpleFileOpen (
311 IN EFI_FILE_PROTOCOL *This,
312 OUT EFI_FILE_PROTOCOL **NewHandle,
313 IN CHAR16 *FileName,
314 IN UINT64 OpenMode,
315 IN UINT64 Attributes
316 )
317{
318 VIRTIO_FS_FILE *VirtioFsFile;
319 VIRTIO_FS *VirtioFs;
320 BOOLEAN OpenForWriting;
321 BOOLEAN PermitCreation;
322 BOOLEAN CreateDirectoryIfCreating;
323 VIRTIO_FS_FILE *NewVirtioFsFile;
324 EFI_STATUS Status;
325 CHAR8 *NewCanonicalPath;
326 BOOLEAN RootEscape;
327 UINT64 DirNodeId;
328 CHAR8 *LastComponent;
329 UINT64 NewNodeId;
330 UINT64 NewFuseHandle;
331 BOOLEAN NewNodeIsDirectory;
332
333 VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);
334 VirtioFs = VirtioFsFile->OwnerFs;
335
336 //
337 // Validate OpenMode.
338 //
339 switch (OpenMode) {
340 case EFI_FILE_MODE_READ:
341 OpenForWriting = FALSE;
342 PermitCreation = FALSE;
343 break;
344 case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE:
345 OpenForWriting = TRUE;
346 PermitCreation = FALSE;
347 break;
348 case EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE:
349 OpenForWriting = TRUE;
350 PermitCreation = TRUE;
351 break;
352 default:
353 return EFI_INVALID_PARAMETER;
354 }
355
356 //
357 // Set CreateDirectoryIfCreating to suppress incorrect compiler/analyzer
358 // warnings.
359 //
360 CreateDirectoryIfCreating = FALSE;
361
362 //
363 // Validate the Attributes requested for the case when the file ends up being
364 // created, provided creation is permitted.
365 //
366 if (PermitCreation) {
367 if ((Attributes & ~EFI_FILE_VALID_ATTR) != 0) {
368 //
369 // Unknown attribute requested.
370 //
371 return EFI_INVALID_PARAMETER;
372 }
373
374 ASSERT (OpenForWriting);
375 if ((Attributes & EFI_FILE_READ_ONLY) != 0) {
376 DEBUG ((
377 DEBUG_ERROR,
378 ("%a: Label=\"%s\" CanonicalPathname=\"%a\" FileName=\"%s\" "
379 "OpenMode=0x%Lx Attributes=0x%Lx: nonsensical request to possibly "
380 "create a file marked read-only, for read-write access\n"),
381 __func__,
382 VirtioFs->Label,
383 VirtioFsFile->CanonicalPathname,
384 FileName,
385 OpenMode,
386 Attributes
387 ));
388 return EFI_INVALID_PARAMETER;
389 }
390
391 CreateDirectoryIfCreating = (BOOLEAN)((Attributes &
392 EFI_FILE_DIRECTORY) != 0);
393 }
394
395 //
396 // Referring to a file relative to a regular file makes no sense (or at least
397 // it cannot be implemented consistently with how a file is referred to
398 // relative to a directory). See USWG Mantis ticket #2367.
399 //
400 if (!VirtioFsFile->IsDirectory) {
401 BOOLEAN BugCompat;
402
403 //
404 // Tolerate this bug in the caller if FileName is absolute. If FileName is
405 // absolute, then VirtioFsAppendPath() below will disregard
406 // VirtioFsFile->CanonicalPathname.
407 //
408 BugCompat = (FileName[0] == L'\\');
409
410 DEBUG ((
411 BugCompat ? DEBUG_WARN : DEBUG_ERROR,
412 ("%a: Label=\"%s\" CanonicalPathname=\"%a\" FileName=\"%s\": "
413 "nonsensical request to open a file or directory relative to a regular "
414 "file\n"),
415 __func__,
416 VirtioFs->Label,
417 VirtioFsFile->CanonicalPathname,
418 FileName
419 ));
420 if (!BugCompat) {
421 return EFI_INVALID_PARAMETER;
422 }
423 }
424
425 //
426 // Allocate the new VIRTIO_FS_FILE object.
427 //
428 NewVirtioFsFile = AllocatePool (sizeof *NewVirtioFsFile);
429 if (NewVirtioFsFile == NULL) {
430 return EFI_OUT_OF_RESOURCES;
431 }
432
433 //
434 // Create the canonical pathname at which the desired file is expected to
435 // exist.
436 //
437 Status = VirtioFsAppendPath (
438 VirtioFsFile->CanonicalPathname,
439 FileName,
440 &NewCanonicalPath,
441 &RootEscape
442 );
443 if (EFI_ERROR (Status)) {
444 goto FreeNewVirtioFsFile;
445 }
446
447 if (RootEscape) {
448 Status = EFI_ACCESS_DENIED;
449 goto FreeNewCanonicalPath;
450 }
451
452 //
453 // If the desired file is the root directory, just open the volume one more
454 // time, without looking up anything.
455 //
456 if (AsciiStrCmp (NewCanonicalPath, "/") == 0) {
457 FreePool (NewCanonicalPath);
458 FreePool (NewVirtioFsFile);
459 return OpenRootDirectory (VirtioFs, NewHandle, OpenForWriting);
460 }
461
462 //
463 // Split the new canonical pathname into most specific parent directory
464 // (given by DirNodeId) and last pathname component (i.e., immediate child
465 // within that parent directory).
466 //
468 VirtioFs,
469 NewCanonicalPath,
470 &DirNodeId,
471 &LastComponent
472 );
473 if (EFI_ERROR (Status)) {
474 goto FreeNewCanonicalPath;
475 }
476
477 //
478 // Set NewNodeIsDirectory to suppress incorrect compiler/analyzer warnings.
479 //
480 NewNodeIsDirectory = FALSE;
481
482 //
483 // Try to open LastComponent directly under DirNodeId, as an existent regular
484 // file or directory.
485 //
487 VirtioFs,
488 DirNodeId,
489 LastComponent,
490 OpenForWriting,
491 &NewNodeId,
492 &NewFuseHandle,
493 &NewNodeIsDirectory
494 );
495 //
496 // If LastComponent could not be found under DirNodeId, but the request
497 // allows us to create a new entry, attempt creating the requested regular
498 // file or directory.
499 //
500 if ((Status == EFI_NOT_FOUND) && PermitCreation) {
501 ASSERT (OpenForWriting);
502 if (CreateDirectoryIfCreating) {
503 Status = CreateDirectory (
504 VirtioFs,
505 DirNodeId,
506 LastComponent,
507 &NewNodeId,
508 &NewFuseHandle
509 );
510 } else {
511 Status = CreateRegularFile (
512 VirtioFs,
513 DirNodeId,
514 LastComponent,
515 &NewNodeId,
516 &NewFuseHandle
517 );
518 }
519
520 NewNodeIsDirectory = CreateDirectoryIfCreating;
521 }
522
523 //
524 // Regardless of the branch taken, we're done with DirNodeId.
525 //
526 if (DirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {
527 VirtioFsFuseForget (VirtioFs, DirNodeId);
528 }
529
530 if (EFI_ERROR (Status)) {
531 goto FreeNewCanonicalPath;
532 }
533
534 //
535 // Populate the new VIRTIO_FS_FILE object.
536 //
537 NewVirtioFsFile->Signature = VIRTIO_FS_FILE_SIG;
538 NewVirtioFsFile->SimpleFile.Revision = EFI_FILE_PROTOCOL_REVISION;
539 NewVirtioFsFile->SimpleFile.Open = VirtioFsSimpleFileOpen;
540 NewVirtioFsFile->SimpleFile.Close = VirtioFsSimpleFileClose;
541 NewVirtioFsFile->SimpleFile.Delete = VirtioFsSimpleFileDelete;
542 NewVirtioFsFile->SimpleFile.Read = VirtioFsSimpleFileRead;
543 NewVirtioFsFile->SimpleFile.Write = VirtioFsSimpleFileWrite;
544 NewVirtioFsFile->SimpleFile.GetPosition = VirtioFsSimpleFileGetPosition;
545 NewVirtioFsFile->SimpleFile.SetPosition = VirtioFsSimpleFileSetPosition;
546 NewVirtioFsFile->SimpleFile.GetInfo = VirtioFsSimpleFileGetInfo;
547 NewVirtioFsFile->SimpleFile.SetInfo = VirtioFsSimpleFileSetInfo;
548 NewVirtioFsFile->SimpleFile.Flush = VirtioFsSimpleFileFlush;
549 NewVirtioFsFile->IsDirectory = NewNodeIsDirectory;
550 NewVirtioFsFile->IsOpenForWriting = OpenForWriting;
551 NewVirtioFsFile->OwnerFs = VirtioFs;
552 NewVirtioFsFile->CanonicalPathname = NewCanonicalPath;
553 NewVirtioFsFile->FilePosition = 0;
554 NewVirtioFsFile->NodeId = NewNodeId;
555 NewVirtioFsFile->FuseHandle = NewFuseHandle;
556 NewVirtioFsFile->FileInfoArray = NULL;
557 NewVirtioFsFile->SingleFileInfoSize = 0;
558 NewVirtioFsFile->NumFileInfo = 0;
559 NewVirtioFsFile->NextFileInfo = 0;
560
561 //
562 // One more file is now open for the filesystem.
563 //
564 InsertTailList (&VirtioFs->OpenFiles, &NewVirtioFsFile->OpenFilesEntry);
565
566 *NewHandle = &NewVirtioFsFile->SimpleFile;
567 return EFI_SUCCESS;
568
569FreeNewCanonicalPath:
570 FreePool (NewCanonicalPath);
571
572FreeNewVirtioFsFile:
573 FreePool (NewVirtioFsFile);
574
575 return Status;
576}
INTN EFIAPI AsciiStrCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString)
Definition: String.c:716
LIST_ENTRY *EFIAPI InsertTailList(IN OUT LIST_ENTRY *ListHead, IN OUT LIST_ENTRY *Entry)
Definition: LinkedList.c:259
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS VirtioFsFuseForget(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 NodeId)
Definition: FuseForget.c:36
EFI_STATUS VirtioFsFuseGetAttr(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 NodeId, OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr)
Definition: FuseGetAttr.c:39
EFI_STATUS VirtioFsFuseLookup(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 DirNodeId, IN CHAR8 *Name, OUT UINT64 *NodeId, OUT VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr)
Definition: FuseLookup.c:54
EFI_STATUS VirtioFsFuseMkDir(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 ParentNodeId, IN CHAR8 *Name, OUT UINT64 *NodeId)
Definition: FuseMkDir.c:43
EFI_STATUS VirtioFsFuseOpen(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 NodeId, IN BOOLEAN ReadWrite, OUT UINT64 *FuseHandle)
Definition: FuseOpen.c:40
EFI_STATUS VirtioFsFuseOpenDir(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 NodeId, OUT UINT64 *FuseHandle)
Definition: FuseOpenDir.c:38
EFI_STATUS VirtioFsFuseOpenOrCreate(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 ParentNodeId, IN CHAR8 *Name, OUT UINT64 *NodeId, OUT UINT64 *FuseHandle)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
EFI_FILE_INFO * FileInfo(IN EFI_FILE_HANDLE FHand)
STATIC EFI_STATUS OpenRootDirectory(IN OUT VIRTIO_FS *VirtioFs, OUT EFI_FILE_PROTOCOL **NewHandle, IN BOOLEAN OpenForWriting)
Definition: SimpleFsOpen.c:40
STATIC EFI_STATUS CreateDirectory(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 DirNodeId, IN CHAR8 *Name, OUT UINT64 *NodeId, OUT UINT64 *FuseHandle)
Definition: SimpleFsOpen.c:234
STATIC EFI_STATUS CreateRegularFile(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 DirNodeId, IN CHAR8 *Name, OUT UINT64 *NodeId, OUT UINT64 *FuseHandle)
Definition: SimpleFsOpen.c:291
STATIC EFI_STATUS OpenExistentFileOrDirectory(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 DirNodeId, IN CHAR8 *Name, IN BOOLEAN OpenForWriting, OUT UINT64 *NodeId, OUT UINT64 *FuseHandle, OUT BOOLEAN *NodeIsDirectory)
Definition: SimpleFsOpen.c:139
EFI_STATUS EFIAPI VirtioFsOpenVolume(IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **Root)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_STATUS VirtioFsLookupMostSpecificParentDir(IN OUT VIRTIO_FS *VirtioFs, IN OUT CHAR8 *Path, OUT UINT64 *DirNodeId, OUT CHAR8 **LastComponent)
Definition: Helpers.c:1701
EFI_STATUS VirtioFsAppendPath(IN CHAR8 *LhsPath8, IN CHAR16 *RhsPath16, OUT CHAR8 **ResultPath8, OUT BOOLEAN *RootEscape)
Definition: Helpers.c:1404
EFI_STATUS VirtioFsFuseAttrToEfiFileInfo(IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr, OUT EFI_FILE_INFO *FileInfo)
Definition: Helpers.c:2090
UINT64 Attribute
Definition: FileInfo.h:47