]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/UdfDxe/File.c
MdeModulePkg: Initial UDF/ECMA-167 file system support
[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] = { 0 };
180 UDF_FILE_INFO File;
181 PRIVATE_UDF_FILE_DATA *NewPrivFileData;
182 CHAR16 *TempFileName;
183
184 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
185
186 if (This == NULL || NewHandle == NULL || FileName == NULL) {
187 Status = EFI_INVALID_PARAMETER;
188 goto Error_Invalid_Params;
189 }
190
191 if (OpenMode != EFI_FILE_MODE_READ) {
192 Status = EFI_WRITE_PROTECTED;
193 goto Error_Invalid_Params;
194 }
195
196 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
197
198 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
199
200 //
201 // Build full path
202 //
203 if (*FileName == L'\\') {
204 StrCpyS (FilePath, UDF_PATH_LENGTH, FileName);
205 } else {
206 StrCpyS (FilePath, UDF_PATH_LENGTH, PrivFileData->AbsoluteFileName);
207 StrCatS (FilePath, UDF_PATH_LENGTH, L"\\");
208 StrCatS (FilePath, UDF_PATH_LENGTH, FileName);
209 }
210
211 MangleFileName (FilePath);
212 if (FilePath[0] == L'\0') {
213 Status = EFI_NOT_FOUND;
214 goto Error_Bad_FileName;
215 }
216
217 Status = FindFile (
218 PrivFsData->BlockIo,
219 PrivFsData->DiskIo,
220 &PrivFsData->Volume,
221 FilePath,
222 _ROOT_FILE (PrivFileData),
223 _PARENT_FILE (PrivFileData),
224 &_PARENT_FILE(PrivFileData)->FileIdentifierDesc->Icb,
225 &File
226 );
227 if (EFI_ERROR (Status)) {
228 goto Error_Find_File;
229 }
230
231 NewPrivFileData =
232 (PRIVATE_UDF_FILE_DATA *)AllocateZeroPool (sizeof (PRIVATE_UDF_FILE_DATA));
233 if (NewPrivFileData == NULL) {
234 Status = EFI_OUT_OF_RESOURCES;
235 goto Error_Alloc_New_Priv_File_Data;
236 }
237
238 CopyMem ((VOID *)NewPrivFileData, (VOID *)PrivFileData,
239 sizeof (PRIVATE_UDF_FILE_DATA));
240 CopyMem ((VOID *)&NewPrivFileData->File, &File, sizeof (UDF_FILE_INFO));
241
242 NewPrivFileData->IsRootDirectory = FALSE;
243
244 StrCpyS (NewPrivFileData->AbsoluteFileName, UDF_PATH_LENGTH, FilePath);
245 FileName = NewPrivFileData->AbsoluteFileName;
246
247 while ((TempFileName = StrStr (FileName, L"\\")) != NULL) {
248 FileName = TempFileName + 1;
249 }
250
251 StrCpyS (NewPrivFileData->FileName, UDF_PATH_LENGTH, FileName);
252
253 Status = GetFileSize (
254 PrivFsData->BlockIo,
255 PrivFsData->DiskIo,
256 &PrivFsData->Volume,
257 &NewPrivFileData->File,
258 &NewPrivFileData->FileSize
259 );
260 ASSERT_EFI_ERROR (Status);
261 if (EFI_ERROR (Status)) {
262 goto Error_Get_File_Size;
263 }
264
265 NewPrivFileData->FilePosition = 0;
266 ZeroMem ((VOID *)&NewPrivFileData->ReadDirInfo,
267 sizeof (UDF_READ_DIRECTORY_INFO));
268
269 *NewHandle = &NewPrivFileData->FileIo;
270
271 PrivFsData->OpenFiles++;
272
273 gBS->RestoreTPL (OldTpl);
274
275 return Status;
276
277 Error_Get_File_Size:
278 FreePool ((VOID *)NewPrivFileData);
279
280 Error_Alloc_New_Priv_File_Data:
281 CleanupFileInformation (&File);
282
283 Error_Find_File:
284 Error_Bad_FileName:
285 Error_Invalid_Params:
286 gBS->RestoreTPL (OldTpl);
287
288 return Status;
289 }
290
291 /**
292 Read data from the file.
293
294 @param This Protocol instance pointer.
295 @param BufferSize On input size of buffer, on output amount of data in
296 buffer.
297 @param Buffer The buffer in which data is read.
298
299 @retval EFI_SUCCESS Data was read.
300 @retval EFI_NO_MEDIA The device has no media.
301 @retval EFI_DEVICE_ERROR The device reported an error.
302 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
303 @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains
304 required size.
305
306 **/
307 EFI_STATUS
308 EFIAPI
309 UdfRead (
310 IN EFI_FILE_PROTOCOL *This,
311 IN OUT UINTN *BufferSize,
312 OUT VOID *Buffer
313 )
314 {
315 EFI_TPL OldTpl;
316 EFI_STATUS Status;
317 PRIVATE_UDF_FILE_DATA *PrivFileData;
318 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
319 UDF_VOLUME_INFO *Volume;
320 UDF_FILE_INFO *Parent;
321 UDF_READ_DIRECTORY_INFO *ReadDirInfo;
322 EFI_BLOCK_IO_PROTOCOL *BlockIo;
323 EFI_DISK_IO_PROTOCOL *DiskIo;
324 UDF_FILE_INFO FoundFile;
325 UDF_FILE_IDENTIFIER_DESCRIPTOR *NewFileIdentifierDesc;
326 VOID *NewFileEntryData;
327 CHAR16 FileName[UDF_FILENAME_LENGTH] = { 0 };
328 UINT64 FileSize;
329 UINT64 BufferSizeUint64;
330
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 if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) {
412 break;
413 }
414
415 FreePool ((VOID *)NewFileIdentifierDesc);
416 }
417
418 Status = FindFileEntry (
419 BlockIo,
420 DiskIo,
421 Volume,
422 &NewFileIdentifierDesc->Icb,
423 &NewFileEntryData
424 );
425 if (EFI_ERROR (Status)) {
426 goto Error_Find_Fe;
427 }
428
429 if (IS_FE_SYMLINK (NewFileEntryData)) {
430 Status = ResolveSymlink (
431 BlockIo,
432 DiskIo,
433 Volume,
434 Parent,
435 NewFileEntryData,
436 &FoundFile
437 );
438 if (EFI_ERROR (Status)) {
439 goto Error_Resolve_Symlink;
440 }
441
442 FreePool ((VOID *)NewFileEntryData);
443 NewFileEntryData = FoundFile.FileEntry;
444
445 Status = GetFileNameFromFid (NewFileIdentifierDesc, FileName);
446 if (EFI_ERROR (Status)) {
447 FreePool ((VOID *)FoundFile.FileIdentifierDesc);
448 goto Error_Get_FileName;
449 }
450
451 FreePool ((VOID *)NewFileIdentifierDesc);
452 NewFileIdentifierDesc = FoundFile.FileIdentifierDesc;
453 } else {
454 FoundFile.FileIdentifierDesc = NewFileIdentifierDesc;
455 FoundFile.FileEntry = NewFileEntryData;
456
457 Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, FileName);
458 if (EFI_ERROR (Status)) {
459 goto Error_Get_FileName;
460 }
461 }
462
463 Status = GetFileSize (
464 BlockIo,
465 DiskIo,
466 Volume,
467 &FoundFile,
468 &FileSize
469 );
470 if (EFI_ERROR (Status)) {
471 goto Error_Get_File_Size;
472 }
473
474 Status = SetFileInfo (
475 &FoundFile,
476 FileSize,
477 FileName,
478 BufferSize,
479 Buffer
480 );
481 if (EFI_ERROR (Status)) {
482 goto Error_Set_File_Info;
483 }
484
485 PrivFileData->FilePosition++;
486 Status = EFI_SUCCESS;
487 } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) {
488 Status = EFI_DEVICE_ERROR;
489 }
490
491 Error_Set_File_Info:
492 Error_Get_File_Size:
493 Error_Get_FileName:
494 Error_Resolve_Symlink:
495 if (NewFileEntryData != NULL) {
496 FreePool (NewFileEntryData);
497 }
498
499 Error_Find_Fe:
500 if (NewFileIdentifierDesc != NULL) {
501 FreePool ((VOID *)NewFileIdentifierDesc);
502 }
503
504 Done:
505 Error_File_Beyond_The_Eof:
506 Error_Invalid_Params:
507 gBS->RestoreTPL (OldTpl);
508
509 return Status;
510 }
511
512 /**
513 Close the file handle.
514
515 @param This Protocol instance pointer.
516
517 @retval EFI_SUCCESS The file was closed.
518
519 **/
520 EFI_STATUS
521 EFIAPI
522 UdfClose (
523 IN EFI_FILE_PROTOCOL *This
524 )
525 {
526 EFI_TPL OldTpl;
527 EFI_STATUS Status;
528 PRIVATE_UDF_FILE_DATA *PrivFileData;
529 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
530
531 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
532
533 Status = EFI_SUCCESS;
534
535 if (This == NULL) {
536 Status = EFI_INVALID_PARAMETER;
537 goto Exit;
538 }
539
540 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
541
542 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
543
544 if (!PrivFileData->IsRootDirectory) {
545 CleanupFileInformation (&PrivFileData->File);
546
547 if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {
548 FreePool (PrivFileData->ReadDirInfo.DirectoryData);
549 }
550 }
551
552 if (--PrivFsData->OpenFiles == 0) {
553 CleanupVolumeInformation (&PrivFsData->Volume);
554 }
555
556 FreePool ((VOID *)PrivFileData);
557
558 Exit:
559 gBS->RestoreTPL (OldTpl);
560
561 return Status;
562 }
563
564 /**
565 Close and delete the file handle.
566
567 @param This Protocol instance pointer.
568
569 @retval EFI_SUCCESS The file was closed and deleted.
570 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not
571 deleted.
572
573 **/
574 EFI_STATUS
575 EFIAPI
576 UdfDelete (
577 IN EFI_FILE_PROTOCOL *This
578 )
579 {
580 PRIVATE_UDF_FILE_DATA *PrivFileData;
581
582 if (This == NULL) {
583 return EFI_INVALID_PARAMETER;
584 }
585
586 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
587
588 (VOID)PrivFileData->FileIo.Close(This);
589
590 return EFI_WARN_DELETE_FAILURE;
591 }
592
593 /**
594 Write data to a file.
595
596 @param This Protocol instance pointer.
597 @param BufferSize On input size of buffer, on output amount of data in
598 buffer.
599 @param Buffer The buffer in which data to write.
600
601 @retval EFI_SUCCESS Data was written.
602 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
603 @retval EFI_NO_MEDIA The device has no media.
604 @retval EFI_DEVICE_ERROR The device reported an error.
605 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
606 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
607 @retval EFI_WRITE_PROTECTED The device is write protected.
608 @retval EFI_ACCESS_DENIED The file was open for read only.
609 @retval EFI_VOLUME_FULL The volume is full.
610
611 **/
612 EFI_STATUS
613 EFIAPI
614 UdfWrite (
615 IN EFI_FILE_PROTOCOL *This,
616 IN OUT UINTN *BufferSize,
617 IN VOID *Buffer
618 )
619 {
620 return EFI_UNSUPPORTED;
621 }
622
623 /**
624 Get file's current position.
625
626 @param This Protocol instance pointer.
627 @param Position Byte position from the start of the file.
628
629 @retval EFI_SUCCESS Position was updated.
630 @retval EFI_UNSUPPORTED Seek request for directories is not valid.
631
632 **/
633 EFI_STATUS
634 EFIAPI
635 UdfGetPosition (
636 IN EFI_FILE_PROTOCOL *This,
637 OUT UINT64 *Position
638 )
639 {
640 PRIVATE_UDF_FILE_DATA *PrivFileData;
641
642 if (This == NULL || Position == NULL) {
643 return EFI_INVALID_PARAMETER;
644 }
645
646 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
647
648 //
649 // As per UEFI spec, if the file handle is a directory, then the current file
650 // position has no meaning and the operation is not supported.
651 //
652 if (IS_FID_DIRECTORY_FILE (&PrivFileData->File.FileIdentifierDesc)) {
653 return EFI_UNSUPPORTED;
654 }
655
656 //
657 // The file is not a directory. So, return its position.
658 //
659 *Position = PrivFileData->FilePosition;
660
661 return EFI_SUCCESS;
662 }
663
664 /**
665 Set file's current position.
666
667 @param This Protocol instance pointer.
668 @param Position Byte position from the start of the file.
669
670 @retval EFI_SUCCESS Position was updated.
671 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
672
673 **/
674 EFI_STATUS
675 EFIAPI
676 UdfSetPosition (
677 IN EFI_FILE_PROTOCOL *This,
678 IN UINT64 Position
679 )
680 {
681 EFI_STATUS Status;
682 PRIVATE_UDF_FILE_DATA *PrivFileData;
683 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
684
685 if (This == NULL) {
686 return EFI_INVALID_PARAMETER;
687 }
688
689 Status = EFI_UNSUPPORTED;
690
691 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
692
693 FileIdentifierDesc = PrivFileData->File.FileIdentifierDesc;
694 if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {
695 //
696 // If the file handle is a directory, the _only_ position that may be set is
697 // zero. This has no effect of starting the read proccess of the directory
698 // entries over.
699 //
700 if (Position == 0) {
701 PrivFileData->FilePosition = Position;
702 PrivFileData->ReadDirInfo.FidOffset = 0;
703 Status = EFI_SUCCESS;
704 }
705 } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {
706 //
707 // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be
708 // set to the EOF.
709 //
710 if (Position == 0xFFFFFFFFFFFFFFFF) {
711 PrivFileData->FilePosition = PrivFileData->FileSize - 1;
712 } else {
713 PrivFileData->FilePosition = Position;
714 }
715
716 Status = EFI_SUCCESS;
717 }
718
719 return Status;
720 }
721
722 /**
723 Get information about a file.
724
725 @param This Protocol instance pointer.
726 @param InformationType Type of information to return in Buffer.
727 @param BufferSize On input size of buffer, on output amount of data in
728 buffer.
729 @param Buffer The buffer to return data.
730
731 @retval EFI_SUCCESS Data was returned.
732 @retval EFI_UNSUPPORTED InformationType is not supported.
733 @retval EFI_NO_MEDIA The device has no media.
734 @retval EFI_DEVICE_ERROR The device reported an error.
735 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
736 @retval EFI_WRITE_PROTECTED The device is write protected.
737 @retval EFI_ACCESS_DENIED The file was open for read only.
738 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
739 BufferSize.
740
741 **/
742 EFI_STATUS
743 EFIAPI
744 UdfGetInfo (
745 IN EFI_FILE_PROTOCOL *This,
746 IN EFI_GUID *InformationType,
747 IN OUT UINTN *BufferSize,
748 OUT VOID *Buffer
749 )
750 {
751 EFI_STATUS Status;
752 PRIVATE_UDF_FILE_DATA *PrivFileData;
753 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
754 EFI_FILE_SYSTEM_INFO *FileSystemInfo;
755 UINTN FileSystemInfoLength;
756 CHAR16 *String;
757 UDF_FILE_SET_DESCRIPTOR *FileSetDesc;
758 UINTN Index;
759 UINT8 *OstaCompressed;
760 UINT8 CompressionId;
761 UINT64 VolumeSize;
762 UINT64 FreeSpaceSize;
763 CHAR16 VolumeLabel[64];
764
765 if (This == NULL || InformationType == NULL || BufferSize == NULL ||
766 (*BufferSize != 0 && Buffer == NULL)) {
767 return EFI_INVALID_PARAMETER;
768 }
769
770 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
771
772 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
773
774 Status = EFI_UNSUPPORTED;
775
776 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
777 Status = SetFileInfo (
778 _FILE (PrivFileData),
779 PrivFileData->FileSize,
780 PrivFileData->FileName,
781 BufferSize,
782 Buffer
783 );
784 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
785 String = VolumeLabel;
786
787 FileSetDesc = PrivFsData->Volume.FileSetDescs[0];
788
789 OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];
790
791 CompressionId = OstaCompressed[0];
792 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
793 return EFI_VOLUME_CORRUPTED;
794 }
795
796 for (Index = 1; Index < 128; Index++) {
797 if (CompressionId == 16) {
798 *String = *(UINT8 *)(OstaCompressed + Index) << 8;
799 Index++;
800 } else {
801 *String = 0;
802 }
803
804 if (Index < 128) {
805 *String |= *(UINT8 *)(OstaCompressed + Index);
806 }
807
808 //
809 // Unlike FID Identifiers, Logical Volume Identifier is stored in a
810 // NULL-terminated OSTA compressed format, so we must check for the NULL
811 // character.
812 //
813 if (*String == L'\0') {
814 break;
815 }
816
817 String++;
818 }
819
820 *String = L'\0';
821
822 FileSystemInfoLength = StrSize (VolumeLabel) +
823 sizeof (EFI_FILE_SYSTEM_INFO);
824 if (*BufferSize < FileSystemInfoLength) {
825 *BufferSize = FileSystemInfoLength;
826 return EFI_BUFFER_TOO_SMALL;
827 }
828
829 FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
830 StrCpyS (FileSystemInfo->VolumeLabel, ARRAY_SIZE (VolumeLabel),
831 VolumeLabel);
832 Status = GetVolumeSize (
833 PrivFsData->BlockIo,
834 PrivFsData->DiskIo,
835 &PrivFsData->Volume,
836 &VolumeSize,
837 &FreeSpaceSize
838 );
839 if (EFI_ERROR (Status)) {
840 return Status;
841 }
842
843 FileSystemInfo->Size = FileSystemInfoLength;
844 FileSystemInfo->ReadOnly = TRUE;
845 FileSystemInfo->BlockSize =
846 LV_BLOCK_SIZE (&PrivFsData->Volume, UDF_DEFAULT_LV_NUM);
847 FileSystemInfo->VolumeSize = VolumeSize;
848 FileSystemInfo->FreeSpace = FreeSpaceSize;
849
850 *BufferSize = FileSystemInfoLength;
851 Status = EFI_SUCCESS;
852 }
853
854 return Status;
855 }
856
857 /**
858 Set information about a file.
859
860 @param File Protocol instance pointer.
861 @param InformationType Type of information in Buffer.
862 @param BufferSize Size of buffer.
863 @param Buffer The data to write.
864
865 @retval EFI_SUCCESS Data was set.
866 @retval EFI_UNSUPPORTED InformationType is not supported.
867 @retval EFI_NO_MEDIA The device has no media.
868 @retval EFI_DEVICE_ERROR The device reported an error.
869 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
870 @retval EFI_WRITE_PROTECTED The device is write protected.
871 @retval EFI_ACCESS_DENIED The file was open for read only.
872
873 **/
874 EFI_STATUS
875 EFIAPI
876 UdfSetInfo (
877 IN EFI_FILE_PROTOCOL *This,
878 IN EFI_GUID *InformationType,
879 IN UINTN BufferSize,
880 IN VOID *Buffer
881 )
882 {
883 return EFI_WRITE_PROTECTED;
884 }
885
886 /**
887 Flush data back for the file handle.
888
889 @param This Protocol instance pointer.
890
891 @retval EFI_SUCCESS Data was flushed.
892 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
893 @retval EFI_NO_MEDIA The device has no media.
894 @retval EFI_DEVICE_ERROR The device reported an error.
895 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
896 @retval EFI_WRITE_PROTECTED The device is write protected.
897 @retval EFI_ACCESS_DENIED The file was open for read only.
898 @retval EFI_VOLUME_FULL The volume is full.
899
900 **/
901 EFI_STATUS
902 EFIAPI
903 UdfFlush (
904 IN EFI_FILE_PROTOCOL *This
905 )
906 {
907 return EFI_WRITE_PROTECTED;
908 }