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