TianoCore EDK2 master
Loading...
Searching...
No Matches
SimpleFsSetInfo.c
Go to the documentation of this file.
1
9#include <Guid/FileSystemInfo.h> // gEfiFileSystemInfoGuid
10#include <Guid/FileSystemVolumeLabelInfo.h> // gEfiFileSystemVolumeLabelInfo...
11#include <Library/BaseLib.h> // StrCmp()
12#include <Library/BaseMemoryLib.h> // CompareGuid()
13#include <Library/MemoryAllocationLib.h> // FreePool()
14
15#include "VirtioFsDxe.h"
16
59 IN UINTN SizeByProtocolCaller,
60 IN UINTN MinimumStructSize,
61 IN BOOLEAN IsSizeByInfoPresent,
62 IN VOID *Buffer
63 )
64{
65 UINTN NameFieldByteOffset;
66 UINTN NameFieldBytes;
67 UINTN NameFieldChar16s;
68 CHAR16 *NameField;
69
70 //
71 // Make sure the internal function asking for validation passes in sane
72 // values.
73 //
74 ASSERT (MinimumStructSize >= sizeof (CHAR16));
75 NameFieldByteOffset = MinimumStructSize - sizeof (CHAR16);
76
77 if (IsSizeByInfoPresent) {
78 ASSERT (MinimumStructSize >= sizeof (UINT64) + sizeof (CHAR16));
79 ASSERT (NameFieldByteOffset >= sizeof (UINT64));
80 }
81
82 //
83 // Check whether the protocol caller provided enough bytes for the minimum
84 // size of this info structure.
85 //
86 if (SizeByProtocolCaller < MinimumStructSize) {
87 return EFI_BAD_BUFFER_SIZE;
88 }
89
90 //
91 // If the info structure starts with a UINT64 Size field, check if that
92 // agrees with the protocol caller-provided size.
93 //
94 if (IsSizeByInfoPresent) {
95 UINT64 *SizeByInfo;
96
97 SizeByInfo = Buffer;
98 if (*SizeByInfo != SizeByProtocolCaller) {
99 return EFI_INVALID_PARAMETER;
100 }
101 }
102
103 //
104 // The CHAR16 Name field at the end of the structure must have an even number
105 // of bytes.
106 //
107 // The subtraction below cannot underflow, and yields at least
108 // sizeof(CHAR16).
109 //
110 ASSERT (SizeByProtocolCaller >= NameFieldByteOffset);
111 NameFieldBytes = SizeByProtocolCaller - NameFieldByteOffset;
112 ASSERT (NameFieldBytes >= sizeof (CHAR16));
113 if (NameFieldBytes % sizeof (CHAR16) != 0) {
114 return EFI_INVALID_PARAMETER;
115 }
116
117 //
118 // The CHAR16 Name field at the end of the structure must be NUL-terminated.
119 //
120 NameFieldChar16s = NameFieldBytes / sizeof (CHAR16);
121 ASSERT (NameFieldChar16s >= 1);
122
123 NameField = (CHAR16 *)((UINT8 *)Buffer + NameFieldByteOffset);
124 if (NameField[NameFieldChar16s - 1] != L'\0') {
125 return EFI_INVALID_PARAMETER;
126 }
127
128 return EFI_SUCCESS;
129}
130
172STATIC
175 IN OUT VIRTIO_FS_FILE *VirtioFsFile,
176 IN CHAR16 *NewFileName
177 )
178{
179 VIRTIO_FS *VirtioFs;
180 EFI_STATUS Status;
181 CHAR8 *Destination;
182 BOOLEAN RootEscape;
183 UINT64 OldParentDirNodeId;
184 CHAR8 *OldLastComponent;
185 UINT64 NewParentDirNodeId;
186 CHAR8 *NewLastComponent;
187
188 VirtioFs = VirtioFsFile->OwnerFs;
189
190 //
191 // The root directory cannot be renamed.
192 //
193 if (AsciiStrCmp (VirtioFsFile->CanonicalPathname, "/") == 0) {
194 if (StrCmp (NewFileName, L"") == 0) {
195 //
196 // Not a rename request anyway.
197 //
198 return EFI_SUCCESS;
199 }
200
201 return EFI_ACCESS_DENIED;
202 }
203
204 //
205 // Compose the canonical pathname for the destination.
206 //
208 VirtioFsFile->CanonicalPathname,
209 NewFileName,
210 &Destination,
211 &RootEscape
212 );
213 if (EFI_ERROR (Status)) {
214 return Status;
215 }
216
217 if (RootEscape) {
218 Status = EFI_NOT_FOUND;
219 goto FreeDestination;
220 }
221
222 //
223 // If the rename would leave VirtioFsFile->CanonicalPathname unchanged, then
224 // EFI_FILE_PROTOCOL.SetInfo() isn't asking for a rename actually.
225 //
226 if (AsciiStrCmp (VirtioFsFile->CanonicalPathname, Destination) == 0) {
227 Status = EFI_SUCCESS;
228 goto FreeDestination;
229 }
230
231 //
232 // Check if the rename would break the canonical pathnames of other
233 // VIRTIO_FS_FILE instances of the same VIRTIO_FS.
234 //
235 if (VirtioFsFile->IsDirectory) {
236 UINTN PathLen;
237 LIST_ENTRY *OpenFilesEntry;
238
239 PathLen = AsciiStrLen (VirtioFsFile->CanonicalPathname);
240 BASE_LIST_FOR_EACH (OpenFilesEntry, &VirtioFs->OpenFiles) {
241 VIRTIO_FS_FILE *OtherFile;
242
243 OtherFile = VIRTIO_FS_FILE_FROM_OPEN_FILES_ENTRY (OpenFilesEntry);
244 if ((OtherFile != VirtioFsFile) &&
245 (AsciiStrnCmp (
246 VirtioFsFile->CanonicalPathname,
247 OtherFile->CanonicalPathname,
248 PathLen
249 ) == 0) &&
250 ((OtherFile->CanonicalPathname[PathLen] == '\0') ||
251 (OtherFile->CanonicalPathname[PathLen] == '/')))
252 {
253 //
254 // OtherFile refers to the same directory as VirtioFsFile, or is a
255 // (possibly indirect) child of the directory referred to by
256 // VirtioFsFile.
257 //
258 Status = EFI_ACCESS_DENIED;
259 goto FreeDestination;
260 }
261 }
262 }
263
264 //
265 // From this point on, the file needs to be open for writing.
266 //
267 if (!VirtioFsFile->IsOpenForWriting) {
268 Status = EFI_ACCESS_DENIED;
269 goto FreeDestination;
270 }
271
272 //
273 // Split both source and destination canonical pathnames into (most specific
274 // parent directory, last component) pairs.
275 //
277 VirtioFs,
278 VirtioFsFile->CanonicalPathname,
279 &OldParentDirNodeId,
280 &OldLastComponent
281 );
282 if (EFI_ERROR (Status)) {
283 goto FreeDestination;
284 }
285
287 VirtioFs,
288 Destination,
289 &NewParentDirNodeId,
290 &NewLastComponent
291 );
292 if (EFI_ERROR (Status)) {
293 goto ForgetOldParentDirNodeId;
294 }
295
296 //
297 // Perform the rename. If the destination path exists, the rename will fail.
298 //
299 Status = VirtioFsFuseRename (
300 VirtioFs,
301 OldParentDirNodeId,
302 OldLastComponent,
303 NewParentDirNodeId,
304 NewLastComponent
305 );
306 if (EFI_ERROR (Status)) {
307 goto ForgetNewParentDirNodeId;
308 }
309
310 //
311 // Swap in the new canonical pathname.
312 //
313 FreePool (VirtioFsFile->CanonicalPathname);
314 VirtioFsFile->CanonicalPathname = Destination;
315 Destination = NULL;
316 Status = EFI_SUCCESS;
317
318 //
319 // Fall through.
320 //
321ForgetNewParentDirNodeId:
322 if (NewParentDirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {
323 VirtioFsFuseForget (VirtioFs, NewParentDirNodeId);
324 }
325
326ForgetOldParentDirNodeId:
327 if (OldParentDirNodeId != VIRTIO_FS_FUSE_ROOT_DIR_NODE_ID) {
328 VirtioFsFuseForget (VirtioFs, OldParentDirNodeId);
329 }
330
331FreeDestination:
332 if (Destination != NULL) {
333 FreePool (Destination);
334 }
335
336 return Status;
337}
338
360STATIC
363 IN OUT VIRTIO_FS_FILE *VirtioFsFile,
364 IN EFI_FILE_INFO *NewFileInfo
365 )
366{
367 VIRTIO_FS *VirtioFs;
368 EFI_STATUS Status;
371 BOOLEAN UpdateFileSize;
372 UINT64 FileSize;
373 BOOLEAN UpdateAtime;
374 BOOLEAN UpdateMtime;
375 UINT64 Atime;
376 UINT64 Mtime;
377 BOOLEAN UpdateMode;
378 UINT32 Mode;
379
380 VirtioFs = VirtioFsFile->OwnerFs;
381
382 //
383 // Fetch the current attributes first, so we can build the difference between
384 // them and NewFileInfo.
385 //
386 Status = VirtioFsFuseGetAttr (VirtioFs, VirtioFsFile->NodeId, &FuseAttr);
387 if (EFI_ERROR (Status)) {
388 return Status;
389 }
390
391 Status = VirtioFsFuseAttrToEfiFileInfo (&FuseAttr, &FileInfo);
392 if (EFI_ERROR (Status)) {
393 return Status;
394 }
395
396 //
397 // Collect the updates.
398 //
399 if (VirtioFsFile->IsDirectory) {
400 UpdateFileSize = FALSE;
401 } else {
403 &FileInfo,
404 NewFileInfo,
405 &UpdateFileSize,
406 &FileSize
407 );
408 }
409
411 &FileInfo,
412 NewFileInfo,
413 &UpdateAtime,
414 &UpdateMtime,
415 &Atime,
416 &Mtime
417 );
418 if (EFI_ERROR (Status)) {
419 return Status;
420 }
421
423 &FileInfo,
424 NewFileInfo,
425 &UpdateMode,
426 &Mode
427 );
428 if (EFI_ERROR (Status)) {
429 return Status;
430 }
431
432 //
433 // If no attribute updates are necessary, we're done.
434 //
435 if (!UpdateFileSize && !UpdateAtime && !UpdateMtime && !UpdateMode) {
436 return EFI_SUCCESS;
437 }
438
439 //
440 // If the file is not open for writing, then only Mode may be updated (for
441 // toggling EFI_FILE_READ_ONLY).
442 //
443 if (!VirtioFsFile->IsOpenForWriting &&
444 (UpdateFileSize || UpdateAtime || UpdateMtime))
445 {
446 return EFI_ACCESS_DENIED;
447 }
448
449 //
450 // Send the FUSE_SETATTR request now.
451 //
452 Status = VirtioFsFuseSetAttr (
453 VirtioFs,
454 VirtioFsFile->NodeId,
455 UpdateFileSize ? &FileSize : NULL,
456 UpdateAtime ? &Atime : NULL,
457 UpdateMtime ? &Mtime : NULL,
458 UpdateMode ? &Mode : NULL
459 );
460 return Status;
461}
462
466STATIC
469 IN EFI_FILE_PROTOCOL *This,
470 IN UINTN BufferSize,
471 IN VOID *Buffer
472 )
473{
474 VIRTIO_FS_FILE *VirtioFsFile;
475 EFI_STATUS Status;
477
478 VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);
479
480 //
481 // Validate if Buffer passes as EFI_FILE_INFO.
482 //
483 Status = ValidateInfoStructure (
484 BufferSize, // SizeByProtocolCaller
485 OFFSET_OF (
487 FileName
488 ) + sizeof (CHAR16), // MinimumStructSize
489 TRUE, // IsSizeByInfoPresent
490 Buffer
491 );
492 if (EFI_ERROR (Status)) {
493 return Status;
494 }
495
496 FileInfo = Buffer;
497
498 //
499 // Perform the rename/move request, if any.
500 //
501 Status = Rename (VirtioFsFile, FileInfo->FileName);
502 if (EFI_ERROR (Status)) {
503 return Status;
504 }
505
506 //
507 // Update any attributes requested.
508 //
509 Status = UpdateAttributes (VirtioFsFile, FileInfo);
510 //
511 // The UEFI spec does not speak about partial failure in
512 // EFI_FILE_PROTOCOL.SetInfo(); we won't try to roll back the rename (if
513 // there was one) in case the attribute updates fail.
514 //
515 return Status;
516}
517
521STATIC
524 IN EFI_FILE_PROTOCOL *This,
525 IN UINTN BufferSize,
526 IN VOID *Buffer
527 )
528{
529 VIRTIO_FS_FILE *VirtioFsFile;
530 VIRTIO_FS *VirtioFs;
531 EFI_STATUS Status;
532 EFI_FILE_SYSTEM_INFO *FileSystemInfo;
533
534 VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);
535 VirtioFs = VirtioFsFile->OwnerFs;
536
537 //
538 // Validate if Buffer passes as EFI_FILE_SYSTEM_INFO.
539 //
540 Status = ValidateInfoStructure (
541 BufferSize, // SizeByProtocolCaller
542 OFFSET_OF (
544 VolumeLabel
545 ) + sizeof (CHAR16), // MinimumStructSize
546 TRUE, // IsSizeByInfoPresent
547 Buffer
548 );
549 if (EFI_ERROR (Status)) {
550 return Status;
551 }
552
553 FileSystemInfo = Buffer;
554
555 //
556 // EFI_FILE_SYSTEM_INFO fields other than VolumeLabel cannot be changed, per
557 // spec.
558 //
559 // If the label is being changed to its current value, report success;
560 // otherwise, reject the request, as the Virtio Filesystem device does not
561 // support changing the label.
562 //
563 if (StrCmp (FileSystemInfo->VolumeLabel, VirtioFs->Label) == 0) {
564 return EFI_SUCCESS;
565 }
566
567 return EFI_WRITE_PROTECTED;
568}
569
573STATIC
576 IN EFI_FILE_PROTOCOL *This,
577 IN UINTN BufferSize,
578 IN VOID *Buffer
579 )
580{
581 VIRTIO_FS_FILE *VirtioFsFile;
582 VIRTIO_FS *VirtioFs;
583 EFI_STATUS Status;
584 EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
585
586 VirtioFsFile = VIRTIO_FS_FILE_FROM_SIMPLE_FILE (This);
587 VirtioFs = VirtioFsFile->OwnerFs;
588
589 //
590 // Validate if Buffer passes as EFI_FILE_SYSTEM_VOLUME_LABEL.
591 //
592 Status = ValidateInfoStructure (
593 BufferSize, // SizeByProtocolCaller
594 OFFSET_OF (
596 VolumeLabel
597 ) + sizeof (CHAR16), // MinimumStructSize
598 FALSE, // IsSizeByInfoPresent
599 Buffer
600 );
601 if (EFI_ERROR (Status)) {
602 return Status;
603 }
604
605 FileSystemVolumeLabel = Buffer;
606
607 //
608 // If the label is being changed to its current value, report success;
609 // otherwise, reject the request, as the Virtio Filesystem device does not
610 // support changing the label.
611 //
612 if (StrCmp (FileSystemVolumeLabel->VolumeLabel, VirtioFs->Label) == 0) {
613 return EFI_SUCCESS;
614 }
615
616 return EFI_WRITE_PROTECTED;
617}
618
620EFIAPI
621VirtioFsSimpleFileSetInfo (
622 IN EFI_FILE_PROTOCOL *This,
623 IN EFI_GUID *InformationType,
624 IN UINTN BufferSize,
625 IN VOID *Buffer
626 )
627{
628 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
629 return SetFileInfo (This, BufferSize, Buffer);
630 }
631
632 if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
633 return SetFileSystemInfo (This, BufferSize, Buffer);
634 }
635
636 if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
637 return SetFileSystemVolumeLabelInfo (This, BufferSize, Buffer);
638 }
639
640 return EFI_UNSUPPORTED;
641}
UINT64 UINTN
INTN EFIAPI StrCmp(IN CONST CHAR16 *FirstString, IN CONST CHAR16 *SecondString)
Definition: String.c:109
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
INTN EFIAPI AsciiStrCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString)
Definition: String.c:716
INTN EFIAPI AsciiStrnCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString, IN UINTN Length)
Definition: String.c:872
#define BASE_LIST_FOR_EACH(Entry, ListHead)
Definition: BaseLib.h:2913
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
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 VirtioFsFuseRename(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 OldParentNodeId, IN CHAR8 *OldName, IN UINT64 NewParentNodeId, IN CHAR8 *NewName)
Definition: FuseRename.c:51
EFI_STATUS VirtioFsFuseSetAttr(IN OUT VIRTIO_FS *VirtioFs, IN UINT64 NodeId, IN UINT64 *Size OPTIONAL, IN UINT64 *Atime OPTIONAL, IN UINT64 *Mtime OPTIONAL, IN UINT32 *Mode OPTIONAL)
Definition: FuseSetAttr.c:54
#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 OFFSET_OF(TYPE, Field)
Definition: Base.h:758
#define OUT
Definition: Base.h:284
EFI_FILE_INFO * FileInfo(IN EFI_FILE_HANDLE FHand)
STATIC EFI_STATUS SetFileInfo(IN EFI_FILE_PROTOCOL *This, IN UINTN BufferSize, IN VOID *Buffer)
STATIC EFI_STATUS UpdateAttributes(IN OUT VIRTIO_FS_FILE *VirtioFsFile, IN EFI_FILE_INFO *NewFileInfo)
STATIC EFI_STATUS SetFileSystemInfo(IN EFI_FILE_PROTOCOL *This, IN UINTN BufferSize, IN VOID *Buffer)
STATIC EFI_STATUS SetFileSystemVolumeLabelInfo(IN EFI_FILE_PROTOCOL *This, IN UINTN BufferSize, IN VOID *Buffer)
STATIC EFI_STATUS Rename(IN OUT VIRTIO_FS_FILE *VirtioFsFile, IN CHAR16 *NewFileName)
STATIC EFI_STATUS ValidateInfoStructure(IN UINTN SizeByProtocolCaller, IN UINTN MinimumStructSize, IN BOOLEAN IsSizeByInfoPresent, IN VOID *Buffer)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_STATUS VirtioFsGetFuseModeUpdate(IN EFI_FILE_INFO *Info, IN EFI_FILE_INFO *NewInfo, OUT BOOLEAN *Update, OUT UINT32 *Mode)
Definition: Helpers.c:2459
VOID VirtioFsGetFuseSizeUpdate(IN EFI_FILE_INFO *Info, IN EFI_FILE_INFO *NewInfo, OUT BOOLEAN *Update, OUT UINT64 *Size)
Definition: Helpers.c:2290
EFI_STATUS VirtioFsLookupMostSpecificParentDir(IN OUT VIRTIO_FS *VirtioFs, IN OUT CHAR8 *Path, OUT UINT64 *DirNodeId, OUT CHAR8 **LastComponent)
Definition: Helpers.c:1701
EFI_STATUS VirtioFsGetFuseTimeUpdates(IN EFI_FILE_INFO *Info, IN EFI_FILE_INFO *NewInfo, OUT BOOLEAN *UpdateAtime, OUT BOOLEAN *UpdateMtime, OUT UINT64 *Atime, OUT UINT64 *Mtime)
Definition: Helpers.c:2355
EFI_STATUS VirtioFsFuseAttrToEfiFileInfo(IN VIRTIO_FS_FUSE_ATTRIBUTES_RESPONSE *FuseAttr, OUT EFI_FILE_INFO *FileInfo)
Definition: Helpers.c:2090
EFI_STATUS VirtioFsComposeRenameDestination(IN CHAR8 *LhsPath8, IN CHAR16 *RhsPath16, OUT CHAR8 **ResultPath8, OUT BOOLEAN *RootEscape)
Definition: Helpers.c:1918
CHAR16 FileName[1]
Definition: FileInfo.h:52
Definition: Base.h:213