]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/UdfDxe/File.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Disk / UdfDxe / File.c
1 /** @file
2 Handle operations in files and directories from UDF/ECMA-167 file systems.
3
4 Copyright (C) 2014-2017 Paulo Alcantara <pcacjr@zytor.com>
5 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 **/
9
10 #include "Udf.h"
11
12 EFI_FILE_PROTOCOL gUdfFileIoOps = {
13 EFI_FILE_PROTOCOL_REVISION,
14 UdfOpen,
15 UdfClose,
16 UdfDelete,
17 UdfRead,
18 UdfWrite,
19 UdfGetPosition,
20 UdfSetPosition,
21 UdfGetInfo,
22 UdfSetInfo,
23 UdfFlush,
24 NULL,
25 NULL,
26 NULL,
27 NULL
28 };
29
30 #define _ROOT_FILE(_PrivData) (_PrivData)->Root
31 #define _PARENT_FILE(_PrivData) \
32 ((_PrivData)->IsRootDirectory ? (_PrivData)->Root : &(_PrivData)->File)
33 #define _FILE(_PrivData) _PARENT_FILE(_PrivData)
34
35 /**
36 Open the root directory on a volume.
37
38 @param This Protocol instance pointer.
39 @param Root Returns an Open file handle for the root directory
40
41 @retval EFI_SUCCESS The device was opened.
42 @retval EFI_UNSUPPORTED This volume does not support the file system.
43 @retval EFI_NO_MEDIA The device has no media.
44 @retval EFI_DEVICE_ERROR The device reported an error.
45 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
46 @retval EFI_ACCESS_DENIED The service denied access to the file.
47 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
48 resources.
49
50 **/
51 EFI_STATUS
52 EFIAPI
53 UdfOpenVolume (
54 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
55 OUT EFI_FILE_PROTOCOL **Root
56 )
57 {
58 EFI_TPL OldTpl;
59 EFI_STATUS Status;
60 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
61 PRIVATE_UDF_FILE_DATA *PrivFileData;
62
63 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
64
65 if (This == NULL || Root == NULL) {
66 Status = EFI_INVALID_PARAMETER;
67 goto Error_Invalid_Params;
68 }
69
70 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (This);
71
72 if (PrivFsData->OpenFiles == 0) {
73 //
74 // There is no more open files. Read volume information again since it was
75 // cleaned up on the last UdfClose() call.
76 //
77 Status = ReadUdfVolumeInformation (
78 PrivFsData->BlockIo,
79 PrivFsData->DiskIo,
80 &PrivFsData->Volume
81 );
82 if (EFI_ERROR (Status)) {
83 goto Error_Read_Udf_Volume;
84 }
85 }
86
87 CleanupFileInformation (&PrivFsData->Root);
88
89 //
90 // Find root directory file.
91 //
92 Status = FindRootDirectory (
93 PrivFsData->BlockIo,
94 PrivFsData->DiskIo,
95 &PrivFsData->Volume,
96 &PrivFsData->Root
97 );
98 if (EFI_ERROR (Status)) {
99 goto Error_Find_Root_Dir;
100 }
101
102 PrivFileData =
103 (PRIVATE_UDF_FILE_DATA *) AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
104 if (PrivFileData == NULL) {
105 Status = EFI_OUT_OF_RESOURCES;
106 goto Error_Alloc_Priv_File_Data;
107 }
108
109 PrivFileData->Signature = PRIVATE_UDF_FILE_DATA_SIGNATURE;
110 PrivFileData->SimpleFs = This;
111 PrivFileData->Root = &PrivFsData->Root;
112 PrivFileData->IsRootDirectory = TRUE;
113
114 CopyMem ((VOID *)&PrivFileData->FileIo, (VOID *)&gUdfFileIoOps,
115 sizeof (EFI_FILE_PROTOCOL));
116
117 *Root = &PrivFileData->FileIo;
118
119 PrivFsData->OpenFiles++;
120
121 gBS->RestoreTPL (OldTpl);
122
123 return EFI_SUCCESS;
124
125 Error_Alloc_Priv_File_Data:
126 CleanupFileInformation (&PrivFsData->Root);
127
128 Error_Find_Root_Dir:
129
130 Error_Read_Udf_Volume:
131 Error_Invalid_Params:
132 gBS->RestoreTPL (OldTpl);
133
134 return Status;
135 }
136
137 /**
138 Opens a new file relative to the source file's location.
139
140 @param This The protocol instance pointer.
141 @param NewHandle Returns File Handle for FileName.
142 @param FileName Null terminated string. "\", ".", and ".." are supported.
143 @param OpenMode Open mode for file.
144 @param Attributes Only used for EFI_FILE_MODE_CREATE.
145
146 @retval EFI_SUCCESS The device was opened.
147 @retval EFI_NOT_FOUND The specified file could not be found on the
148 device.
149 @retval EFI_NO_MEDIA The device has no media.
150 @retval EFI_MEDIA_CHANGED The media has changed.
151 @retval EFI_DEVICE_ERROR The device reported an error.
152 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
153 @retval EFI_ACCESS_DENIED The service denied access to the file.
154 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
155 resources.
156 @retval EFI_VOLUME_FULL The volume is full.
157
158 **/
159 EFI_STATUS
160 EFIAPI
161 UdfOpen (
162 IN EFI_FILE_PROTOCOL *This,
163 OUT EFI_FILE_PROTOCOL **NewHandle,
164 IN CHAR16 *FileName,
165 IN UINT64 OpenMode,
166 IN UINT64 Attributes
167 )
168 {
169 EFI_TPL OldTpl;
170 EFI_STATUS Status;
171 PRIVATE_UDF_FILE_DATA *PrivFileData;
172 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
173 CHAR16 FilePath[UDF_PATH_LENGTH];
174 UDF_FILE_INFO File;
175 PRIVATE_UDF_FILE_DATA *NewPrivFileData;
176 CHAR16 *TempFileName;
177
178 ZeroMem (FilePath, sizeof FilePath);
179 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
180
181 if (This == NULL || NewHandle == NULL || FileName == NULL) {
182 Status = EFI_INVALID_PARAMETER;
183 goto Error_Invalid_Params;
184 }
185
186 if (OpenMode != EFI_FILE_MODE_READ) {
187 Status = EFI_WRITE_PROTECTED;
188 goto Error_Invalid_Params;
189 }
190
191 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
192
193 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
194
195 //
196 // Build full path
197 //
198 if (*FileName == L'\\') {
199 StrCpyS (FilePath, UDF_PATH_LENGTH, FileName);
200 } else {
201 StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName);
202 StrCatS (FilePath, UDF_PATH_LENGTH, L"\\");
203 StrCatS (FilePath, UDF_PATH_LENGTH, FileName);
204 }
205
206 MangleFileName (FilePath);
207 if (FilePath[0] == L'\0') {
208 Status = EFI_NOT_FOUND;
209 goto Error_Bad_FileName;
210 }
211
212 Status = FindFile (
213 PrivFsData->BlockIo,
214 PrivFsData->DiskIo,
215 &PrivFsData->Volume,
216 FilePath,
217 _ROOT_FILE (PrivFileData),
218 _PARENT_FILE (PrivFileData),
219 &_PARENT_FILE(PrivFileData)->FileIdentifierDesc->Icb,
220 &File
221 );
222 if (EFI_ERROR (Status)) {
223 goto Error_Find_File;
224 }
225
226 NewPrivFileData =
227 (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
228 if (NewPrivFileData == NULL) {
229 Status = EFI_OUT_OF_RESOURCES;
230 goto Error_Alloc_New_Priv_File_Data;
231 }
232
233 CopyMem ((VOID *)NewPrivFileData, (VOID *)PrivFileData,
234 sizeof (PRIVATE_UDF_FILE_DATA));
235 CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO));
236
237 NewPrivFileData->IsRootDirectory = FALSE;
238
239 StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath);
240 FileName = NewPrivFileData->AbsoluteFileName;
241
242 while ((TempFileName = StrStr (FileName, L"\\")) != NULL) {
243 FileName = TempFileName + 1;
244 }
245
246 StrCpyS (NewPrivFileData->FileName, UDF_FILENAME_LENGTH, FileName);
247
248 Status = GetFileSize (
249 PrivFsData->BlockIo,
250 PrivFsData->DiskIo,
251 &PrivFsData->Volume,
252 &NewPrivFileData->File,
253 &NewPrivFileData->FileSize
254 );
255 if (EFI_ERROR (Status)) {
256 DEBUG ((
257 DEBUG_ERROR,
258 "%a: GetFileSize() fails with status - %r.\n",
259 __FUNCTION__, Status
260 ));
261 goto Error_Get_File_Size;
262 }
263
264 NewPrivFileData->FilePosition = 0;
265 ZeroMem ((VOID *)&NewPrivFileData->ReadDirInfo,
266 sizeof (UDF_READ_DIRECTORY_INFO));
267
268 *NewHandle = &NewPrivFileData->FileIo;
269
270 PrivFsData->OpenFiles++;
271
272 gBS->RestoreTPL (OldTpl);
273
274 return Status;
275
276 Error_Get_File_Size:
277 FreePool ((VOID *)NewPrivFileData);
278
279 Error_Alloc_New_Priv_File_Data:
280 CleanupFileInformation (&File);
281
282 Error_Find_File:
283 Error_Bad_FileName:
284 Error_Invalid_Params:
285 gBS->RestoreTPL (OldTpl);
286
287 return Status;
288 }
289
290 /**
291 Read data from the file.
292
293 @param This Protocol instance pointer.
294 @param BufferSize On input size of buffer, on output amount of data in
295 buffer.
296 @param Buffer The buffer in which data is read.
297
298 @retval EFI_SUCCESS Data was read.
299 @retval EFI_NO_MEDIA The device has no media.
300 @retval EFI_DEVICE_ERROR The device reported an error.
301 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
302 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains
303 required size.
304
305 **/
306 EFI_STATUS
307 EFIAPI
308 UdfRead (
309 IN EFI_FILE_PROTOCOL *This,
310 IN OUT UINTN *BufferSize,
311 OUT VOID *Buffer
312 )
313 {
314 EFI_TPL OldTpl;
315 EFI_STATUS Status;
316 PRIVATE_UDF_FILE_DATA *PrivFileData;
317 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
318 UDF_VOLUME_INFO *Volume;
319 UDF_FILE_INFO *Parent;
320 UDF_READ_DIRECTORY_INFO *ReadDirInfo;
321 EFI_BLOCK_IO_PROTOCOL *BlockIo;
322 EFI_DISK_IO_PROTOCOL *DiskIo;
323 UDF_FILE_INFO FoundFile;
324 UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc;
325 VOID *NewFileEntryData;
326 CHAR16 FileName[UDF_FILENAME_LENGTH];
327 UINT64 FileSize;
328 UINT64 BufferSizeUint64;
329
330 ZeroMem (FileName, sizeof FileName);
331 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
332
333 if (This == NULL || BufferSize == NULL || (*BufferSize != 0 &&
334 Buffer == NULL)) {
335 Status = EFI_INVALID_PARAMETER;
336 goto Error_Invalid_Params;
337 }
338
339 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
340 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
341
342 BlockIo = PrivFsData->BlockIo;
343 DiskIo = PrivFsData->DiskIo;
344 Volume = &PrivFsData->Volume;
345 ReadDirInfo = &PrivFileData->ReadDirInfo;
346 NewFileIdentifierDesc = NULL;
347 NewFileEntryData = NULL;
348
349 Parent = _PARENT_FILE (PrivFileData);
350
351 Status = EFI_VOLUME_CORRUPTED;
352
353 if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) {
354 if (PrivFileData->FilePosition > PrivFileData->FileSize) {
355 //
356 // File's position is beyond the EOF
357 //
358 Status = EFI_DEVICE_ERROR;
359 goto Error_File_Beyond_The_Eof;
360 }
361
362 if (PrivFileData->FilePosition == PrivFileData->FileSize) {
363 *BufferSize = 0;
364 Status = EFI_SUCCESS;
365 goto Done;
366 }
367
368 BufferSizeUint64 = *BufferSize;
369
370 Status = ReadFileData (
371 BlockIo,
372 DiskIo,
373 Volume,
374 Parent,
375 PrivFileData->FileSize,
376 &PrivFileData->FilePosition,
377 Buffer,
378 &BufferSizeUint64
379 );
380 ASSERT (BufferSizeUint64 <= MAX_UINTN);
381 *BufferSize = (UINTN)BufferSizeUint64;
382 } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) {
383 if (ReadDirInfo->FidOffset == 0 && PrivFileData->FilePosition > 0) {
384 Status = EFI_DEVICE_ERROR;
385 *BufferSize = 0;
386 goto Done;
387 }
388
389 for (;;) {
390 Status = ReadDirectoryEntry (
391 BlockIo,
392 DiskIo,
393 Volume,
394 &Parent->FileIdentifierDesc->Icb,
395 Parent->FileEntry,
396 ReadDirInfo,
397 &NewFileIdentifierDesc
398 );
399 if (EFI_ERROR (Status)) {
400 if (Status == EFI_DEVICE_ERROR) {
401 FreePool (ReadDirInfo->DirectoryData);
402 ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
403
404 *BufferSize = 0;
405 Status = EFI_SUCCESS;
406 }
407
408 goto Done;
409 }
410 //
411 // After calling function ReadDirectoryEntry(), if 'NewFileIdentifierDesc'
412 // is NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the
413 // code reaches here, 'NewFileIdentifierDesc' must be not NULL.
414 //
415 // The ASSERT here is for addressing a false positive NULL pointer
416 // dereference issue raised from static analysis.
417 //
418 ASSERT (NewFileIdentifierDesc != NULL);
419
420 if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) {
421 break;
422 }
423
424 FreePool ((VOID *)NewFileIdentifierDesc);
425 }
426
427 Status = FindFileEntry (
428 BlockIo,
429 DiskIo,
430 Volume,
431 &NewFileIdentifierDesc->Icb,
432 &NewFileEntryData
433 );
434 if (EFI_ERROR (Status)) {
435 goto Error_Find_Fe;
436 }
437 ASSERT (NewFileEntryData != NULL);
438
439 if (FE_ICB_FILE_TYPE (NewFileEntryData) == UdfFileEntrySymlink) {
440 Status = ResolveSymlink (
441 BlockIo,
442 DiskIo,
443 Volume,
444 Parent,
445 NewFileEntryData,
446 &FoundFile
447 );
448 if (EFI_ERROR (Status)) {
449 goto Error_Resolve_Symlink;
450 }
451
452 FreePool ((VOID *)NewFileEntryData);
453 NewFileEntryData = FoundFile.FileEntry;
454
455 Status = GetFileNameFromFid (NewFileIdentifierDesc, ARRAY_SIZE (FileName), FileName);
456 if (EFI_ERROR (Status)) {
457 FreePool ((VOID *)FoundFile.FileIdentifierDesc);
458 goto Error_Get_FileName;
459 }
460
461 FreePool ((VOID *)NewFileIdentifierDesc);
462 NewFileIdentifierDesc = FoundFile.FileIdentifierDesc;
463 } else {
464 FoundFile.FileIdentifierDesc = NewFileIdentifierDesc;
465 FoundFile.FileEntry = NewFileEntryData;
466
467 Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, ARRAY_SIZE (FileName), FileName);
468 if (EFI_ERROR (Status)) {
469 goto Error_Get_FileName;
470 }
471 }
472
473 Status = GetFileSize (
474 BlockIo,
475 DiskIo,
476 Volume,
477 &FoundFile,
478 &FileSize
479 );
480 if (EFI_ERROR (Status)) {
481 goto Error_Get_File_Size;
482 }
483
484 Status = SetFileInfo (
485 &FoundFile,
486 FileSize,
487 FileName,
488 BufferSize,
489 Buffer
490 );
491 if (EFI_ERROR (Status)) {
492 goto Error_Set_File_Info;
493 }
494
495 PrivFileData->FilePosition++;
496 Status = EFI_SUCCESS;
497 } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) {
498 //
499 // Code should never reach here.
500 //
501 ASSERT (FALSE);
502 Status = EFI_DEVICE_ERROR;
503 }
504
505 Error_Set_File_Info:
506 Error_Get_File_Size:
507 Error_Get_FileName:
508 Error_Resolve_Symlink:
509 if (NewFileEntryData != NULL) {
510 FreePool (NewFileEntryData);
511 }
512
513 Error_Find_Fe:
514 if (NewFileIdentifierDesc != NULL) {
515 FreePool ((VOID *)NewFileIdentifierDesc);
516 }
517
518 Done:
519 Error_File_Beyond_The_Eof:
520 Error_Invalid_Params:
521 gBS->RestoreTPL (OldTpl);
522
523 return Status;
524 }
525
526 /**
527 Close the file handle.
528
529 @param This Protocol instance pointer.
530
531 @retval EFI_SUCCESS The file was closed.
532
533 **/
534 EFI_STATUS
535 EFIAPI
536 UdfClose (
537 IN EFI_FILE_PROTOCOL *This
538 )
539 {
540 EFI_TPL OldTpl;
541 EFI_STATUS Status;
542 PRIVATE_UDF_FILE_DATA *PrivFileData;
543
544 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
545
546 Status = EFI_SUCCESS;
547
548 if (This == NULL) {
549 Status = EFI_INVALID_PARAMETER;
550 goto Exit;
551 }
552
553 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
554
555 if (!PrivFileData->IsRootDirectory) {
556 CleanupFileInformation (&PrivFileData->File);
557
558 if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {
559 FreePool (PrivFileData->ReadDirInfo.DirectoryData);
560 }
561 }
562
563 FreePool ((VOID *)PrivFileData);
564
565 Exit:
566 gBS->RestoreTPL (OldTpl);
567
568 return Status;
569 }
570
571 /**
572 Close and delete the file handle.
573
574 @param This Protocol instance pointer.
575
576 @retval EFI_SUCCESS The file was closed and deleted.
577 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not
578 deleted.
579
580 **/
581 EFI_STATUS
582 EFIAPI
583 UdfDelete (
584 IN EFI_FILE_PROTOCOL *This
585 )
586 {
587 PRIVATE_UDF_FILE_DATA *PrivFileData;
588
589 if (This == NULL) {
590 return EFI_INVALID_PARAMETER;
591 }
592
593 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
594
595 (VOID)PrivFileData->FileIo.Close(This);
596
597 return EFI_WARN_DELETE_FAILURE;
598 }
599
600 /**
601 Write data to a file.
602
603 @param This Protocol instance pointer.
604 @param BufferSize On input size of buffer, on output amount of data in
605 buffer.
606 @param Buffer The buffer in which data to write.
607
608 @retval EFI_SUCCESS Data was written.
609 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
610 @retval EFI_NO_MEDIA The device has no media.
611 @retval EFI_DEVICE_ERROR The device reported an error.
612 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
613 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
614 @retval EFI_WRITE_PROTECTED The device is write protected.
615 @retval EFI_ACCESS_DENIED The file was open for read only.
616 @retval EFI_VOLUME_FULL The volume is full.
617
618 **/
619 EFI_STATUS
620 EFIAPI
621 UdfWrite (
622 IN EFI_FILE_PROTOCOL *This,
623 IN OUT UINTN *BufferSize,
624 IN VOID *Buffer
625 )
626 {
627 return EFI_UNSUPPORTED;
628 }
629
630 /**
631 Get file's current position.
632
633 @param This Protocol instance pointer.
634 @param Position Byte position from the start of the file.
635
636 @retval EFI_SUCCESS Position was updated.
637 @retval EFI_UNSUPPORTED Seek request for directories is not valid.
638
639 **/
640 EFI_STATUS
641 EFIAPI
642 UdfGetPosition (
643 IN EFI_FILE_PROTOCOL *This,
644 OUT UINT64 *Position
645 )
646 {
647 PRIVATE_UDF_FILE_DATA *PrivFileData;
648
649 if (This == NULL || Position == NULL) {
650 return EFI_INVALID_PARAMETER;
651 }
652
653 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
654
655 //
656 // As per UEFI spec, if the file handle is a directory, then the current file
657 // position has no meaning and the operation is not supported.
658 //
659 if (IS_FID_DIRECTORY_FILE (PrivFileData->File.FileIdentifierDesc)) {
660 return EFI_UNSUPPORTED;
661 }
662
663 //
664 // The file is not a directory. So, return its position.
665 //
666 *Position = PrivFileData->FilePosition;
667
668 return EFI_SUCCESS;
669 }
670
671 /**
672 Set file's current position.
673
674 @param This Protocol instance pointer.
675 @param Position Byte position from the start of the file.
676
677 @retval EFI_SUCCESS Position was updated.
678 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
679
680 **/
681 EFI_STATUS
682 EFIAPI
683 UdfSetPosition (
684 IN EFI_FILE_PROTOCOL *This,
685 IN UINT64 Position
686 )
687 {
688 EFI_STATUS Status;
689 PRIVATE_UDF_FILE_DATA *PrivFileData;
690 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
691
692 if (This == NULL) {
693 return EFI_INVALID_PARAMETER;
694 }
695
696 Status = EFI_UNSUPPORTED;
697
698 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
699
700 FileIdentifierDesc = _FILE (PrivFileData)->FileIdentifierDesc;
701 ASSERT (FileIdentifierDesc != NULL);
702 if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {
703 //
704 // If the file handle is a directory, the _only_ position that may be set is
705 // zero. This has no effect of starting the read proccess of the directory
706 // entries over.
707 //
708 if (Position == 0) {
709 PrivFileData->FilePosition = Position;
710 PrivFileData->ReadDirInfo.FidOffset = 0;
711 Status = EFI_SUCCESS;
712 }
713 } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {
714 //
715 // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be
716 // set to the EOF.
717 //
718 if (Position == 0xFFFFFFFFFFFFFFFF) {
719 PrivFileData->FilePosition = PrivFileData->FileSize;
720 } else {
721 PrivFileData->FilePosition = Position;
722 }
723
724 Status = EFI_SUCCESS;
725 }
726
727 return Status;
728 }
729
730 /**
731 Get information about a file.
732
733 @param This Protocol instance pointer.
734 @param InformationType Type of information to return in Buffer.
735 @param BufferSize On input size of buffer, on output amount of data in
736 buffer.
737 @param Buffer The buffer to return data.
738
739 @retval EFI_SUCCESS Data was returned.
740 @retval EFI_UNSUPPORTED InformationType is not supported.
741 @retval EFI_NO_MEDIA The device has no media.
742 @retval EFI_DEVICE_ERROR The device reported an error.
743 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
744 @retval EFI_WRITE_PROTECTED The device is write protected.
745 @retval EFI_ACCESS_DENIED The file was open for read only.
746 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
747 BufferSize.
748
749 **/
750 EFI_STATUS
751 EFIAPI
752 UdfGetInfo (
753 IN EFI_FILE_PROTOCOL *This,
754 IN EFI_GUID *InformationType,
755 IN OUT UINTN *BufferSize,
756 OUT VOID *Buffer
757 )
758 {
759 EFI_STATUS Status;
760 PRIVATE_UDF_FILE_DATA *PrivFileData;
761 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
762 EFI_FILE_SYSTEM_INFO *FileSystemInfo;
763 UINTN FileSystemInfoLength;
764 UINT64 VolumeSize;
765 UINT64 FreeSpaceSize;
766 EFI_FILE_SYSTEM_VOLUME_LABEL *FileSystemVolumeLabel;
767 UINTN FileSystemVolumeLabelLength;
768 CHAR16 VolumeLabel[64];
769
770 if (This == NULL || InformationType == NULL || BufferSize == NULL ||
771 (*BufferSize != 0 && Buffer == NULL)) {
772 return EFI_INVALID_PARAMETER;
773 }
774
775 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
776
777 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
778
779 Status = EFI_UNSUPPORTED;
780
781 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
782 Status = SetFileInfo (
783 _FILE (PrivFileData),
784 PrivFileData->FileSize,
785 PrivFileData->FileName,
786 BufferSize,
787 Buffer
788 );
789 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
790 Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel);
791 if (EFI_ERROR (Status)) {
792 return Status;
793 }
794
795 FileSystemInfoLength = StrSize (VolumeLabel) +
796 sizeof (EFI_FILE_SYSTEM_INFO);
797 if (*BufferSize < FileSystemInfoLength) {
798 *BufferSize = FileSystemInfoLength;
799 return EFI_BUFFER_TOO_SMALL;
800 }
801
802 FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
803 StrCpyS (
804 FileSystemInfo->VolumeLabel,
805 (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_INFO) / sizeof (CHAR16),
806 VolumeLabel
807 );
808 Status = GetVolumeSize (
809 PrivFsData->BlockIo,
810 PrivFsData->DiskIo,
811 &PrivFsData->Volume,
812 &VolumeSize,
813 &FreeSpaceSize
814 );
815 if (EFI_ERROR (Status)) {
816 return Status;
817 }
818
819 FileSystemInfo->Size = FileSystemInfoLength;
820 FileSystemInfo->ReadOnly = TRUE;
821 FileSystemInfo->BlockSize =
822 PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize;
823 FileSystemInfo->VolumeSize = VolumeSize;
824 FileSystemInfo->FreeSpace = FreeSpaceSize;
825
826 *BufferSize = FileSystemInfoLength;
827 Status = EFI_SUCCESS;
828 } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
829 Status = GetVolumeLabel (&PrivFsData->Volume, ARRAY_SIZE (VolumeLabel), VolumeLabel);
830 if (EFI_ERROR (Status)) {
831 return Status;
832 }
833
834 FileSystemVolumeLabelLength = StrSize (VolumeLabel) +
835 sizeof (EFI_FILE_SYSTEM_VOLUME_LABEL);
836 if (*BufferSize < FileSystemVolumeLabelLength) {
837 *BufferSize = FileSystemVolumeLabelLength;
838 return EFI_BUFFER_TOO_SMALL;
839 }
840
841 FileSystemVolumeLabel = (EFI_FILE_SYSTEM_VOLUME_LABEL *)Buffer;
842 StrCpyS (
843 FileSystemVolumeLabel->VolumeLabel,
844 (*BufferSize - SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL) / sizeof (CHAR16),
845 VolumeLabel
846 );
847 Status = EFI_SUCCESS;
848 }
849
850 return Status;
851 }
852
853 /**
854 Set information about a file.
855
856 @param This Protocol instance pointer.
857 @param InformationType Type of information in Buffer.
858 @param BufferSize Size of buffer.
859 @param Buffer The data to write.
860
861 @retval EFI_SUCCESS Data was set.
862 @retval EFI_UNSUPPORTED InformationType is not supported.
863 @retval EFI_NO_MEDIA The device has no media.
864 @retval EFI_DEVICE_ERROR The device reported an error.
865 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
866 @retval EFI_WRITE_PROTECTED The device is write protected.
867 @retval EFI_ACCESS_DENIED The file was open for read only.
868
869 **/
870 EFI_STATUS
871 EFIAPI
872 UdfSetInfo (
873 IN EFI_FILE_PROTOCOL *This,
874 IN EFI_GUID *InformationType,
875 IN UINTN BufferSize,
876 IN VOID *Buffer
877 )
878 {
879 return EFI_WRITE_PROTECTED;
880 }
881
882 /**
883 Flush data back for the file handle.
884
885 @param This Protocol instance pointer.
886
887 @retval EFI_SUCCESS Data was flushed.
888 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
889 @retval EFI_NO_MEDIA The device has no media.
890 @retval EFI_DEVICE_ERROR The device reported an error.
891 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
892 @retval EFI_WRITE_PROTECTED The device is write protected.
893 @retval EFI_ACCESS_DENIED The file was open for read only.
894 @retval EFI_VOLUME_FULL The volume is full.
895
896 **/
897 EFI_STATUS
898 EFIAPI
899 UdfFlush (
900 IN EFI_FILE_PROTOCOL *This
901 )
902 {
903 return EFI_WRITE_PROTECTED;
904 }