]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/UdfDxe/File.c
MdeModulePkg/UdfDxe: Refine boundary checks for file/path name string
[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 - 1;
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 @attention This is boundary function that may receive untrusted input.
740 @attention The input is from FileSystem.
741
742 The File Set Descriptor is external input, so this routine will do basic
743 validation for File Set Descriptor and report status.
744
745 @param This Protocol instance pointer.
746 @param InformationType Type of information to return in Buffer.
747 @param BufferSize On input size of buffer, on output amount of data in
748 buffer.
749 @param Buffer The buffer to return data.
750
751 @retval EFI_SUCCESS Data was returned.
752 @retval EFI_UNSUPPORTED InformationType is not supported.
753 @retval EFI_NO_MEDIA The device has no media.
754 @retval EFI_DEVICE_ERROR The device reported an error.
755 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
756 @retval EFI_WRITE_PROTECTED The device is write protected.
757 @retval EFI_ACCESS_DENIED The file was open for read only.
758 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
759 BufferSize.
760
761 **/
762 EFI_STATUS
763 EFIAPI
764 UdfGetInfo (
765 IN EFI_FILE_PROTOCOL *This,
766 IN EFI_GUID *InformationType,
767 IN OUT UINTN *BufferSize,
768 OUT VOID *Buffer
769 )
770 {
771 EFI_STATUS Status;
772 PRIVATE_UDF_FILE_DATA *PrivFileData;
773 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
774 EFI_FILE_SYSTEM_INFO *FileSystemInfo;
775 UINTN FileSystemInfoLength;
776 CHAR16 *String;
777 UDF_FILE_SET_DESCRIPTOR *FileSetDesc;
778 UINTN Index;
779 UINT8 *OstaCompressed;
780 UINT8 CompressionId;
781 UINT64 VolumeSize;
782 UINT64 FreeSpaceSize;
783 CHAR16 VolumeLabel[64];
784
785 if (This == NULL || InformationType == NULL || BufferSize == NULL ||
786 (*BufferSize != 0 && Buffer == NULL)) {
787 return EFI_INVALID_PARAMETER;
788 }
789
790 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
791
792 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
793
794 Status = EFI_UNSUPPORTED;
795
796 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
797 Status = SetFileInfo (
798 _FILE (PrivFileData),
799 PrivFileData->FileSize,
800 PrivFileData->FileName,
801 BufferSize,
802 Buffer
803 );
804 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
805 String = VolumeLabel;
806
807 FileSetDesc = &PrivFsData->Volume.FileSetDesc;
808
809 OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];
810
811 CompressionId = OstaCompressed[0];
812 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
813 return EFI_VOLUME_CORRUPTED;
814 }
815
816 for (Index = 1; Index < 128; Index++) {
817 if (CompressionId == 16) {
818 *String = *(UINT8 *)(OstaCompressed + Index) << 8;
819 Index++;
820 } else {
821 if (Index > ARRAY_SIZE (VolumeLabel)) {
822 return EFI_VOLUME_CORRUPTED;
823 }
824
825 *String = 0;
826 }
827
828 if (Index < 128) {
829 *String |= (CHAR16)(*(UINT8 *)(OstaCompressed + Index));
830 }
831
832 //
833 // Unlike FID Identifiers, Logical Volume Identifier is stored in a
834 // NULL-terminated OSTA compressed format, so we must check for the NULL
835 // character.
836 //
837 if (*String == L'\0') {
838 break;
839 }
840
841 String++;
842 }
843
844 Index = ((UINTN)String - (UINTN)VolumeLabel) / sizeof (CHAR16);
845 if (Index > ARRAY_SIZE (VolumeLabel) - 1) {
846 Index = ARRAY_SIZE (VolumeLabel) - 1;
847 }
848 VolumeLabel[Index] = L'\0';
849
850 FileSystemInfoLength = StrSize (VolumeLabel) +
851 sizeof (EFI_FILE_SYSTEM_INFO);
852 if (*BufferSize < FileSystemInfoLength) {
853 *BufferSize = FileSystemInfoLength;
854 return EFI_BUFFER_TOO_SMALL;
855 }
856
857 FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
858 StrCpyS (
859 FileSystemInfo->VolumeLabel,
860 (*BufferSize - OFFSET_OF (EFI_FILE_SYSTEM_INFO, VolumeLabel)) / sizeof (CHAR16),
861 VolumeLabel
862 );
863 Status = GetVolumeSize (
864 PrivFsData->BlockIo,
865 PrivFsData->DiskIo,
866 &PrivFsData->Volume,
867 &VolumeSize,
868 &FreeSpaceSize
869 );
870 if (EFI_ERROR (Status)) {
871 return Status;
872 }
873
874 FileSystemInfo->Size = FileSystemInfoLength;
875 FileSystemInfo->ReadOnly = TRUE;
876 FileSystemInfo->BlockSize =
877 PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize;
878 FileSystemInfo->VolumeSize = VolumeSize;
879 FileSystemInfo->FreeSpace = FreeSpaceSize;
880
881 *BufferSize = FileSystemInfoLength;
882 Status = EFI_SUCCESS;
883 }
884
885 return Status;
886 }
887
888 /**
889 Set information about a file.
890
891 @param This Protocol instance pointer.
892 @param InformationType Type of information in Buffer.
893 @param BufferSize Size of buffer.
894 @param Buffer The data to write.
895
896 @retval EFI_SUCCESS Data was set.
897 @retval EFI_UNSUPPORTED InformationType is not supported.
898 @retval EFI_NO_MEDIA The device has no media.
899 @retval EFI_DEVICE_ERROR The device reported an error.
900 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
901 @retval EFI_WRITE_PROTECTED The device is write protected.
902 @retval EFI_ACCESS_DENIED The file was open for read only.
903
904 **/
905 EFI_STATUS
906 EFIAPI
907 UdfSetInfo (
908 IN EFI_FILE_PROTOCOL *This,
909 IN EFI_GUID *InformationType,
910 IN UINTN BufferSize,
911 IN VOID *Buffer
912 )
913 {
914 return EFI_WRITE_PROTECTED;
915 }
916
917 /**
918 Flush data back for the file handle.
919
920 @param This Protocol instance pointer.
921
922 @retval EFI_SUCCESS Data was flushed.
923 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
924 @retval EFI_NO_MEDIA The device has no media.
925 @retval EFI_DEVICE_ERROR The device reported an error.
926 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
927 @retval EFI_WRITE_PROTECTED The device is write protected.
928 @retval EFI_ACCESS_DENIED The file was open for read only.
929 @retval EFI_VOLUME_FULL The volume is full.
930
931 **/
932 EFI_STATUS
933 EFIAPI
934 UdfFlush (
935 IN EFI_FILE_PROTOCOL *This
936 )
937 {
938 return EFI_WRITE_PROTECTED;
939 }