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