]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Disk/UdfDxe/File.c
MdeModulePkg/UdfDxe: ASSERT for false positives of NULL ptr deref
[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
135 Error_Read_Udf_Volume:
136 Error_Invalid_Params:
137 gBS->RestoreTPL (OldTpl);
138
139 return Status;
140 }
141
142 /**
143 Opens a new file relative to the source file's location.
144
145 @param This The protocol instance pointer.
146 @param NewHandle Returns File Handle for FileName.
147 @param FileName Null terminated string. "\", ".", and ".." are supported.
148 @param OpenMode Open mode for file.
149 @param Attributes Only used for EFI_FILE_MODE_CREATE.
150
151 @retval EFI_SUCCESS The device was opened.
152 @retval EFI_NOT_FOUND The specified file could not be found on the
153 device.
154 @retval EFI_NO_MEDIA The device has no media.
155 @retval EFI_MEDIA_CHANGED The media has changed.
156 @retval EFI_DEVICE_ERROR The device reported an error.
157 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
158 @retval EFI_ACCESS_DENIED The service denied access to the file.
159 @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of
160 resources.
161 @retval EFI_VOLUME_FULL The volume is full.
162
163 **/
164 EFI_STATUS
165 EFIAPI
166 UdfOpen (
167 IN EFI_FILE_PROTOCOL *This,
168 OUT EFI_FILE_PROTOCOL **NewHandle,
169 IN CHAR16 *FileName,
170 IN UINT64 OpenMode,
171 IN UINT64 Attributes
172 )
173 {
174 EFI_TPL OldTpl;
175 EFI_STATUS Status;
176 PRIVATE_UDF_FILE_DATA *PrivFileData;
177 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
178 CHAR16 FilePath[UDF_PATH_LENGTH];
179 UDF_FILE_INFO File;
180 PRIVATE_UDF_FILE_DATA *NewPrivFileData;
181 CHAR16 *TempFileName;
182
183 ZeroMem (FilePath, sizeof FilePath);
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];
328 UINT64 FileSize;
329 UINT64 BufferSizeUint64;
330
331 ZeroMem (FileName, sizeof FileName);
332 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
333
334 if (This == NULL || BufferSize == NULL || (*BufferSize != 0 &&
335 Buffer == NULL)) {
336 Status = EFI_INVALID_PARAMETER;
337 goto Error_Invalid_Params;
338 }
339
340 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
341 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
342
343 BlockIo = PrivFsData->BlockIo;
344 DiskIo = PrivFsData->DiskIo;
345 Volume = &PrivFsData->Volume;
346 ReadDirInfo = &PrivFileData->ReadDirInfo;
347 NewFileIdentifierDesc = NULL;
348 NewFileEntryData = NULL;
349
350 Parent = _PARENT_FILE (PrivFileData);
351
352 Status = EFI_VOLUME_CORRUPTED;
353
354 if (IS_FID_NORMAL_FILE (Parent->FileIdentifierDesc)) {
355 if (PrivFileData->FilePosition > PrivFileData->FileSize) {
356 //
357 // File's position is beyond the EOF
358 //
359 Status = EFI_DEVICE_ERROR;
360 goto Error_File_Beyond_The_Eof;
361 }
362
363 if (PrivFileData->FilePosition == PrivFileData->FileSize) {
364 *BufferSize = 0;
365 Status = EFI_SUCCESS;
366 goto Done;
367 }
368
369 BufferSizeUint64 = *BufferSize;
370
371 Status = ReadFileData (
372 BlockIo,
373 DiskIo,
374 Volume,
375 Parent,
376 PrivFileData->FileSize,
377 &PrivFileData->FilePosition,
378 Buffer,
379 &BufferSizeUint64
380 );
381 ASSERT (BufferSizeUint64 <= MAX_UINTN);
382 *BufferSize = (UINTN)BufferSizeUint64;
383 } else if (IS_FID_DIRECTORY_FILE (Parent->FileIdentifierDesc)) {
384 if (ReadDirInfo->FidOffset == 0 && PrivFileData->FilePosition > 0) {
385 Status = EFI_DEVICE_ERROR;
386 *BufferSize = 0;
387 goto Done;
388 }
389
390 for (;;) {
391 Status = ReadDirectoryEntry (
392 BlockIo,
393 DiskIo,
394 Volume,
395 &Parent->FileIdentifierDesc->Icb,
396 Parent->FileEntry,
397 ReadDirInfo,
398 &NewFileIdentifierDesc
399 );
400 if (EFI_ERROR (Status)) {
401 if (Status == EFI_DEVICE_ERROR) {
402 FreePool (ReadDirInfo->DirectoryData);
403 ZeroMem ((VOID *)ReadDirInfo, sizeof (UDF_READ_DIRECTORY_INFO));
404
405 *BufferSize = 0;
406 Status = EFI_SUCCESS;
407 }
408
409 goto Done;
410 }
411 //
412 // After calling function ReadDirectoryEntry(), if 'NewFileIdentifierDesc'
413 // is NULL, then the 'Status' must be EFI_OUT_OF_RESOURCES. Hence, if the
414 // code reaches here, 'NewFileIdentifierDesc' must be not NULL.
415 //
416 // The ASSERT here is for addressing a false positive NULL pointer
417 // dereference issue raised from static analysis.
418 //
419 ASSERT (NewFileIdentifierDesc != NULL);
420
421 if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) {
422 break;
423 }
424
425 FreePool ((VOID *)NewFileIdentifierDesc);
426 }
427
428 Status = FindFileEntry (
429 BlockIo,
430 DiskIo,
431 Volume,
432 &NewFileIdentifierDesc->Icb,
433 &NewFileEntryData
434 );
435 if (EFI_ERROR (Status)) {
436 goto Error_Find_Fe;
437 }
438 ASSERT (NewFileEntryData != NULL);
439
440 if (FE_ICB_FILE_TYPE (NewFileEntryData) == UdfFileEntrySymlink) {
441 Status = ResolveSymlink (
442 BlockIo,
443 DiskIo,
444 Volume,
445 Parent,
446 NewFileEntryData,
447 &FoundFile
448 );
449 if (EFI_ERROR (Status)) {
450 goto Error_Resolve_Symlink;
451 }
452
453 FreePool ((VOID *)NewFileEntryData);
454 NewFileEntryData = FoundFile.FileEntry;
455
456 Status = GetFileNameFromFid (NewFileIdentifierDesc, FileName);
457 if (EFI_ERROR (Status)) {
458 FreePool ((VOID *)FoundFile.FileIdentifierDesc);
459 goto Error_Get_FileName;
460 }
461
462 FreePool ((VOID *)NewFileIdentifierDesc);
463 NewFileIdentifierDesc = FoundFile.FileIdentifierDesc;
464 } else {
465 FoundFile.FileIdentifierDesc = NewFileIdentifierDesc;
466 FoundFile.FileEntry = NewFileEntryData;
467
468 Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, FileName);
469 if (EFI_ERROR (Status)) {
470 goto Error_Get_FileName;
471 }
472 }
473
474 Status = GetFileSize (
475 BlockIo,
476 DiskIo,
477 Volume,
478 &FoundFile,
479 &FileSize
480 );
481 if (EFI_ERROR (Status)) {
482 goto Error_Get_File_Size;
483 }
484
485 Status = SetFileInfo (
486 &FoundFile,
487 FileSize,
488 FileName,
489 BufferSize,
490 Buffer
491 );
492 if (EFI_ERROR (Status)) {
493 goto Error_Set_File_Info;
494 }
495
496 PrivFileData->FilePosition++;
497 Status = EFI_SUCCESS;
498 } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) {
499 Status = EFI_DEVICE_ERROR;
500 }
501
502 Error_Set_File_Info:
503 Error_Get_File_Size:
504 Error_Get_FileName:
505 Error_Resolve_Symlink:
506 if (NewFileEntryData != NULL) {
507 FreePool (NewFileEntryData);
508 }
509
510 Error_Find_Fe:
511 if (NewFileIdentifierDesc != NULL) {
512 FreePool ((VOID *)NewFileIdentifierDesc);
513 }
514
515 Done:
516 Error_File_Beyond_The_Eof:
517 Error_Invalid_Params:
518 gBS->RestoreTPL (OldTpl);
519
520 return Status;
521 }
522
523 /**
524 Close the file handle.
525
526 @param This Protocol instance pointer.
527
528 @retval EFI_SUCCESS The file was closed.
529
530 **/
531 EFI_STATUS
532 EFIAPI
533 UdfClose (
534 IN EFI_FILE_PROTOCOL *This
535 )
536 {
537 EFI_TPL OldTpl;
538 EFI_STATUS Status;
539 PRIVATE_UDF_FILE_DATA *PrivFileData;
540
541 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
542
543 Status = EFI_SUCCESS;
544
545 if (This == NULL) {
546 Status = EFI_INVALID_PARAMETER;
547 goto Exit;
548 }
549
550 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
551
552 if (!PrivFileData->IsRootDirectory) {
553 CleanupFileInformation (&PrivFileData->File);
554
555 if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {
556 FreePool (PrivFileData->ReadDirInfo.DirectoryData);
557 }
558 }
559
560 FreePool ((VOID *)PrivFileData);
561
562 Exit:
563 gBS->RestoreTPL (OldTpl);
564
565 return Status;
566 }
567
568 /**
569 Close and delete the file handle.
570
571 @param This Protocol instance pointer.
572
573 @retval EFI_SUCCESS The file was closed and deleted.
574 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not
575 deleted.
576
577 **/
578 EFI_STATUS
579 EFIAPI
580 UdfDelete (
581 IN EFI_FILE_PROTOCOL *This
582 )
583 {
584 PRIVATE_UDF_FILE_DATA *PrivFileData;
585
586 if (This == NULL) {
587 return EFI_INVALID_PARAMETER;
588 }
589
590 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
591
592 (VOID)PrivFileData->FileIo.Close(This);
593
594 return EFI_WARN_DELETE_FAILURE;
595 }
596
597 /**
598 Write data to a file.
599
600 @param This Protocol instance pointer.
601 @param BufferSize On input size of buffer, on output amount of data in
602 buffer.
603 @param Buffer The buffer in which data to write.
604
605 @retval EFI_SUCCESS Data was written.
606 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.
607 @retval EFI_NO_MEDIA The device has no media.
608 @retval EFI_DEVICE_ERROR The device reported an error.
609 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.
610 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
611 @retval EFI_WRITE_PROTECTED The device is write protected.
612 @retval EFI_ACCESS_DENIED The file was open for read only.
613 @retval EFI_VOLUME_FULL The volume is full.
614
615 **/
616 EFI_STATUS
617 EFIAPI
618 UdfWrite (
619 IN EFI_FILE_PROTOCOL *This,
620 IN OUT UINTN *BufferSize,
621 IN VOID *Buffer
622 )
623 {
624 return EFI_UNSUPPORTED;
625 }
626
627 /**
628 Get file's current position.
629
630 @param This Protocol instance pointer.
631 @param Position Byte position from the start of the file.
632
633 @retval EFI_SUCCESS Position was updated.
634 @retval EFI_UNSUPPORTED Seek request for directories is not valid.
635
636 **/
637 EFI_STATUS
638 EFIAPI
639 UdfGetPosition (
640 IN EFI_FILE_PROTOCOL *This,
641 OUT UINT64 *Position
642 )
643 {
644 PRIVATE_UDF_FILE_DATA *PrivFileData;
645
646 if (This == NULL || Position == NULL) {
647 return EFI_INVALID_PARAMETER;
648 }
649
650 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
651
652 //
653 // As per UEFI spec, if the file handle is a directory, then the current file
654 // position has no meaning and the operation is not supported.
655 //
656 if (IS_FID_DIRECTORY_FILE (PrivFileData->File.FileIdentifierDesc)) {
657 return EFI_UNSUPPORTED;
658 }
659
660 //
661 // The file is not a directory. So, return its position.
662 //
663 *Position = PrivFileData->FilePosition;
664
665 return EFI_SUCCESS;
666 }
667
668 /**
669 Set file's current position.
670
671 @param This Protocol instance pointer.
672 @param Position Byte position from the start of the file.
673
674 @retval EFI_SUCCESS Position was updated.
675 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.
676
677 **/
678 EFI_STATUS
679 EFIAPI
680 UdfSetPosition (
681 IN EFI_FILE_PROTOCOL *This,
682 IN UINT64 Position
683 )
684 {
685 EFI_STATUS Status;
686 PRIVATE_UDF_FILE_DATA *PrivFileData;
687 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;
688
689 if (This == NULL) {
690 return EFI_INVALID_PARAMETER;
691 }
692
693 Status = EFI_UNSUPPORTED;
694
695 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
696
697 FileIdentifierDesc = _FILE (PrivFileData)->FileIdentifierDesc;
698 ASSERT (FileIdentifierDesc != NULL);
699 if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {
700 //
701 // If the file handle is a directory, the _only_ position that may be set is
702 // zero. This has no effect of starting the read proccess of the directory
703 // entries over.
704 //
705 if (Position == 0) {
706 PrivFileData->FilePosition = Position;
707 PrivFileData->ReadDirInfo.FidOffset = 0;
708 Status = EFI_SUCCESS;
709 }
710 } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {
711 //
712 // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be
713 // set to the EOF.
714 //
715 if (Position == 0xFFFFFFFFFFFFFFFF) {
716 PrivFileData->FilePosition = PrivFileData->FileSize - 1;
717 } else {
718 PrivFileData->FilePosition = Position;
719 }
720
721 Status = EFI_SUCCESS;
722 }
723
724 return Status;
725 }
726
727 /**
728 Get information about a file.
729
730 @param This Protocol instance pointer.
731 @param InformationType Type of information to return in Buffer.
732 @param BufferSize On input size of buffer, on output amount of data in
733 buffer.
734 @param Buffer The buffer to return data.
735
736 @retval EFI_SUCCESS Data was returned.
737 @retval EFI_UNSUPPORTED InformationType is not supported.
738 @retval EFI_NO_MEDIA The device has no media.
739 @retval EFI_DEVICE_ERROR The device reported an error.
740 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
741 @retval EFI_WRITE_PROTECTED The device is write protected.
742 @retval EFI_ACCESS_DENIED The file was open for read only.
743 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in
744 BufferSize.
745
746 **/
747 EFI_STATUS
748 EFIAPI
749 UdfGetInfo (
750 IN EFI_FILE_PROTOCOL *This,
751 IN EFI_GUID *InformationType,
752 IN OUT UINTN *BufferSize,
753 OUT VOID *Buffer
754 )
755 {
756 EFI_STATUS Status;
757 PRIVATE_UDF_FILE_DATA *PrivFileData;
758 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;
759 EFI_FILE_SYSTEM_INFO *FileSystemInfo;
760 UINTN FileSystemInfoLength;
761 CHAR16 *String;
762 UDF_FILE_SET_DESCRIPTOR *FileSetDesc;
763 UINTN Index;
764 UINT8 *OstaCompressed;
765 UINT8 CompressionId;
766 UINT64 VolumeSize;
767 UINT64 FreeSpaceSize;
768 CHAR16 VolumeLabel[64];
769
770 if (This == NULL || InformationType == NULL || BufferSize == NULL ||
771 (*BufferSize != 0 && Buffer == NULL)) {
772 return EFI_INVALID_PARAMETER;
773 }
774
775 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);
776
777 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);
778
779 Status = EFI_UNSUPPORTED;
780
781 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {
782 Status = SetFileInfo (
783 _FILE (PrivFileData),
784 PrivFileData->FileSize,
785 PrivFileData->FileName,
786 BufferSize,
787 Buffer
788 );
789 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {
790 String = VolumeLabel;
791
792 FileSetDesc = &PrivFsData->Volume.FileSetDesc;
793
794 OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];
795
796 CompressionId = OstaCompressed[0];
797 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {
798 return EFI_VOLUME_CORRUPTED;
799 }
800
801 for (Index = 1; Index < 128; Index++) {
802 if (CompressionId == 16) {
803 *String = *(UINT8 *)(OstaCompressed + Index) << 8;
804 Index++;
805 } else {
806 *String = 0;
807 }
808
809 if (Index < 128) {
810 *String |= (CHAR16)(*(UINT8 *)(OstaCompressed + Index));
811 }
812
813 //
814 // Unlike FID Identifiers, Logical Volume Identifier is stored in a
815 // NULL-terminated OSTA compressed format, so we must check for the NULL
816 // character.
817 //
818 if (*String == L'\0') {
819 break;
820 }
821
822 String++;
823 }
824
825 *String = L'\0';
826
827 FileSystemInfoLength = StrSize (VolumeLabel) +
828 sizeof (EFI_FILE_SYSTEM_INFO);
829 if (*BufferSize < FileSystemInfoLength) {
830 *BufferSize = FileSystemInfoLength;
831 return EFI_BUFFER_TOO_SMALL;
832 }
833
834 FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
835 StrCpyS (FileSystemInfo->VolumeLabel, ARRAY_SIZE (VolumeLabel),
836 VolumeLabel);
837 Status = GetVolumeSize (
838 PrivFsData->BlockIo,
839 PrivFsData->DiskIo,
840 &PrivFsData->Volume,
841 &VolumeSize,
842 &FreeSpaceSize
843 );
844 if (EFI_ERROR (Status)) {
845 return Status;
846 }
847
848 FileSystemInfo->Size = FileSystemInfoLength;
849 FileSystemInfo->ReadOnly = TRUE;
850 FileSystemInfo->BlockSize =
851 PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize;
852 FileSystemInfo->VolumeSize = VolumeSize;
853 FileSystemInfo->FreeSpace = FreeSpaceSize;
854
855 *BufferSize = FileSystemInfoLength;
856 Status = EFI_SUCCESS;
857 }
858
859 return Status;
860 }
861
862 /**
863 Set information about a file.
864
865 @param This Protocol instance pointer.
866 @param InformationType Type of information in Buffer.
867 @param BufferSize Size of buffer.
868 @param Buffer The data to write.
869
870 @retval EFI_SUCCESS Data was set.
871 @retval EFI_UNSUPPORTED InformationType is not supported.
872 @retval EFI_NO_MEDIA The device has no media.
873 @retval EFI_DEVICE_ERROR The device reported an error.
874 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
875 @retval EFI_WRITE_PROTECTED The device is write protected.
876 @retval EFI_ACCESS_DENIED The file was open for read only.
877
878 **/
879 EFI_STATUS
880 EFIAPI
881 UdfSetInfo (
882 IN EFI_FILE_PROTOCOL *This,
883 IN EFI_GUID *InformationType,
884 IN UINTN BufferSize,
885 IN VOID *Buffer
886 )
887 {
888 return EFI_WRITE_PROTECTED;
889 }
890
891 /**
892 Flush data back for the file handle.
893
894 @param This Protocol instance pointer.
895
896 @retval EFI_SUCCESS Data was flushed.
897 @retval EFI_UNSUPPORTED Writes to Open directory are 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 @retval EFI_VOLUME_FULL The volume is full.
904
905 **/
906 EFI_STATUS
907 EFIAPI
908 UdfFlush (
909 IN EFI_FILE_PROTOCOL *This
910 )
911 {
912 return EFI_WRITE_PROTECTED;
913 }