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