]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Disk/UdfDxe/File.c
MdeModulePkg/UdfDxe: Add checks to ensure no possible NULL ptr deref
[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
3fa40d58 430 ASSERT (NewFileEntryData != NULL);\r
99c9b949
PA
431\r
432 if (IS_FE_SYMLINK (NewFileEntryData)) {\r
433 Status = ResolveSymlink (\r
434 BlockIo,\r
435 DiskIo,\r
436 Volume,\r
437 Parent,\r
438 NewFileEntryData,\r
439 &FoundFile\r
440 );\r
441 if (EFI_ERROR (Status)) {\r
442 goto Error_Resolve_Symlink;\r
443 }\r
444\r
445 FreePool ((VOID *)NewFileEntryData);\r
446 NewFileEntryData = FoundFile.FileEntry;\r
447\r
448 Status = GetFileNameFromFid (NewFileIdentifierDesc, FileName);\r
449 if (EFI_ERROR (Status)) {\r
450 FreePool ((VOID *)FoundFile.FileIdentifierDesc);\r
451 goto Error_Get_FileName;\r
452 }\r
453\r
454 FreePool ((VOID *)NewFileIdentifierDesc);\r
455 NewFileIdentifierDesc = FoundFile.FileIdentifierDesc;\r
456 } else {\r
457 FoundFile.FileIdentifierDesc = NewFileIdentifierDesc;\r
458 FoundFile.FileEntry = NewFileEntryData;\r
459\r
460 Status = GetFileNameFromFid (FoundFile.FileIdentifierDesc, FileName);\r
461 if (EFI_ERROR (Status)) {\r
462 goto Error_Get_FileName;\r
463 }\r
464 }\r
465\r
466 Status = GetFileSize (\r
467 BlockIo,\r
468 DiskIo,\r
469 Volume,\r
470 &FoundFile,\r
471 &FileSize\r
472 );\r
473 if (EFI_ERROR (Status)) {\r
474 goto Error_Get_File_Size;\r
475 }\r
476\r
477 Status = SetFileInfo (\r
478 &FoundFile,\r
479 FileSize,\r
480 FileName,\r
481 BufferSize,\r
482 Buffer\r
483 );\r
484 if (EFI_ERROR (Status)) {\r
485 goto Error_Set_File_Info;\r
486 }\r
487\r
488 PrivFileData->FilePosition++;\r
489 Status = EFI_SUCCESS;\r
490 } else if (IS_FID_DELETED_FILE (Parent->FileIdentifierDesc)) {\r
491 Status = EFI_DEVICE_ERROR;\r
492 }\r
493\r
494Error_Set_File_Info:\r
495Error_Get_File_Size:\r
496Error_Get_FileName:\r
497Error_Resolve_Symlink:\r
498 if (NewFileEntryData != NULL) {\r
499 FreePool (NewFileEntryData);\r
500 }\r
501\r
502Error_Find_Fe:\r
503 if (NewFileIdentifierDesc != NULL) {\r
504 FreePool ((VOID *)NewFileIdentifierDesc);\r
505 }\r
506\r
507Done:\r
508Error_File_Beyond_The_Eof:\r
509Error_Invalid_Params:\r
510 gBS->RestoreTPL (OldTpl);\r
511\r
512 return Status;\r
513}\r
514\r
515/**\r
516 Close the file handle.\r
517\r
518 @param This Protocol instance pointer.\r
519\r
520 @retval EFI_SUCCESS The file was closed.\r
521\r
522**/\r
523EFI_STATUS\r
524EFIAPI\r
525UdfClose (\r
526 IN EFI_FILE_PROTOCOL *This\r
527 )\r
528{\r
529 EFI_TPL OldTpl;\r
530 EFI_STATUS Status;\r
531 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
532 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;\r
533\r
534 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
535\r
536 Status = EFI_SUCCESS;\r
537\r
538 if (This == NULL) {\r
539 Status = EFI_INVALID_PARAMETER;\r
540 goto Exit;\r
541 }\r
542\r
543 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
544\r
545 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);\r
546\r
547 if (!PrivFileData->IsRootDirectory) {\r
548 CleanupFileInformation (&PrivFileData->File);\r
549\r
550 if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {\r
551 FreePool (PrivFileData->ReadDirInfo.DirectoryData);\r
552 }\r
553 }\r
554\r
555 if (--PrivFsData->OpenFiles == 0) {\r
556 CleanupVolumeInformation (&PrivFsData->Volume);\r
557 }\r
558\r
559 FreePool ((VOID *)PrivFileData);\r
560\r
561Exit:\r
562 gBS->RestoreTPL (OldTpl);\r
563\r
564 return Status;\r
565}\r
566\r
567/**\r
568 Close and delete the file handle.\r
569\r
570 @param This Protocol instance pointer.\r
571\r
572 @retval EFI_SUCCESS The file was closed and deleted.\r
573 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not\r
574 deleted.\r
575\r
576**/\r
577EFI_STATUS\r
578EFIAPI\r
579UdfDelete (\r
580 IN EFI_FILE_PROTOCOL *This\r
581 )\r
582{\r
583 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
584\r
585 if (This == NULL) {\r
586 return EFI_INVALID_PARAMETER;\r
587 }\r
588\r
589 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
590\r
591 (VOID)PrivFileData->FileIo.Close(This);\r
592\r
593 return EFI_WARN_DELETE_FAILURE;\r
594}\r
595\r
596/**\r
597 Write data to a file.\r
598\r
599 @param This Protocol instance pointer.\r
600 @param BufferSize On input size of buffer, on output amount of data in\r
601 buffer.\r
602 @param Buffer The buffer in which data to write.\r
603\r
604 @retval EFI_SUCCESS Data was written.\r
605 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.\r
606 @retval EFI_NO_MEDIA The device has no media.\r
607 @retval EFI_DEVICE_ERROR The device reported an error.\r
608 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.\r
609 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
610 @retval EFI_WRITE_PROTECTED The device is write protected.\r
611 @retval EFI_ACCESS_DENIED The file was open for read only.\r
612 @retval EFI_VOLUME_FULL The volume is full.\r
613\r
614**/\r
615EFI_STATUS\r
616EFIAPI\r
617UdfWrite (\r
618 IN EFI_FILE_PROTOCOL *This,\r
619 IN OUT UINTN *BufferSize,\r
620 IN VOID *Buffer\r
621 )\r
622{\r
623 return EFI_UNSUPPORTED;\r
624}\r
625\r
626/**\r
627 Get file's current position.\r
628\r
629 @param This Protocol instance pointer.\r
630 @param Position Byte position from the start of the file.\r
631\r
632 @retval EFI_SUCCESS Position was updated.\r
633 @retval EFI_UNSUPPORTED Seek request for directories is not valid.\r
634\r
635**/\r
636EFI_STATUS\r
637EFIAPI\r
638UdfGetPosition (\r
639 IN EFI_FILE_PROTOCOL *This,\r
640 OUT UINT64 *Position\r
641 )\r
642{\r
643 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
644\r
645 if (This == NULL || Position == NULL) {\r
646 return EFI_INVALID_PARAMETER;\r
647 }\r
648\r
649 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
650\r
651 //\r
652 // As per UEFI spec, if the file handle is a directory, then the current file\r
653 // position has no meaning and the operation is not supported.\r
654 //\r
655 if (IS_FID_DIRECTORY_FILE (&PrivFileData->File.FileIdentifierDesc)) {\r
656 return EFI_UNSUPPORTED;\r
657 }\r
658\r
659 //\r
660 // The file is not a directory. So, return its position.\r
661 //\r
662 *Position = PrivFileData->FilePosition;\r
663\r
664 return EFI_SUCCESS;\r
665}\r
666\r
667/**\r
668 Set file's current position.\r
669\r
670 @param This Protocol instance pointer.\r
671 @param Position Byte position from the start of the file.\r
672\r
673 @retval EFI_SUCCESS Position was updated.\r
674 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.\r
675\r
676**/\r
677EFI_STATUS\r
678EFIAPI\r
679UdfSetPosition (\r
680 IN EFI_FILE_PROTOCOL *This,\r
681 IN UINT64 Position\r
682 )\r
683{\r
684 EFI_STATUS Status;\r
685 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
686 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;\r
687\r
688 if (This == NULL) {\r
689 return EFI_INVALID_PARAMETER;\r
690 }\r
691\r
692 Status = EFI_UNSUPPORTED;\r
693\r
694 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
695\r
11b4463e
PA
696 FileIdentifierDesc = _FILE (PrivFileData)->FileIdentifierDesc;\r
697 ASSERT (FileIdentifierDesc != NULL);\r
99c9b949
PA
698 if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {\r
699 //\r
700 // If the file handle is a directory, the _only_ position that may be set is\r
701 // zero. This has no effect of starting the read proccess of the directory\r
702 // entries over.\r
703 //\r
704 if (Position == 0) {\r
705 PrivFileData->FilePosition = Position;\r
706 PrivFileData->ReadDirInfo.FidOffset = 0;\r
707 Status = EFI_SUCCESS;\r
708 }\r
709 } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {\r
710 //\r
711 // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be\r
712 // set to the EOF.\r
713 //\r
714 if (Position == 0xFFFFFFFFFFFFFFFF) {\r
715 PrivFileData->FilePosition = PrivFileData->FileSize - 1;\r
716 } else {\r
717 PrivFileData->FilePosition = Position;\r
718 }\r
719\r
720 Status = EFI_SUCCESS;\r
721 }\r
722\r
723 return Status;\r
724}\r
725\r
726/**\r
727 Get information about a file.\r
728\r
729 @param This Protocol instance pointer.\r
730 @param InformationType Type of information to return in Buffer.\r
731 @param BufferSize On input size of buffer, on output amount of data in\r
732 buffer.\r
733 @param Buffer The buffer to return data.\r
734\r
735 @retval EFI_SUCCESS Data was returned.\r
736 @retval EFI_UNSUPPORTED InformationType is not supported.\r
737 @retval EFI_NO_MEDIA The device has no media.\r
738 @retval EFI_DEVICE_ERROR The device reported an error.\r
739 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
740 @retval EFI_WRITE_PROTECTED The device is write protected.\r
741 @retval EFI_ACCESS_DENIED The file was open for read only.\r
742 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in\r
743 BufferSize.\r
744\r
745**/\r
746EFI_STATUS\r
747EFIAPI\r
748UdfGetInfo (\r
749 IN EFI_FILE_PROTOCOL *This,\r
750 IN EFI_GUID *InformationType,\r
751 IN OUT UINTN *BufferSize,\r
752 OUT VOID *Buffer\r
753 )\r
754{\r
755 EFI_STATUS Status;\r
756 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
757 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;\r
758 EFI_FILE_SYSTEM_INFO *FileSystemInfo;\r
759 UINTN FileSystemInfoLength;\r
760 CHAR16 *String;\r
761 UDF_FILE_SET_DESCRIPTOR *FileSetDesc;\r
762 UINTN Index;\r
763 UINT8 *OstaCompressed;\r
764 UINT8 CompressionId;\r
765 UINT64 VolumeSize;\r
766 UINT64 FreeSpaceSize;\r
767 CHAR16 VolumeLabel[64];\r
768\r
769 if (This == NULL || InformationType == NULL || BufferSize == NULL ||\r
770 (*BufferSize != 0 && Buffer == NULL)) {\r
771 return EFI_INVALID_PARAMETER;\r
772 }\r
773\r
774 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
775\r
776 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);\r
777\r
778 Status = EFI_UNSUPPORTED;\r
779\r
780 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
781 Status = SetFileInfo (\r
782 _FILE (PrivFileData),\r
783 PrivFileData->FileSize,\r
784 PrivFileData->FileName,\r
785 BufferSize,\r
786 Buffer\r
787 );\r
788 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
789 String = VolumeLabel;\r
790\r
791 FileSetDesc = PrivFsData->Volume.FileSetDescs[0];\r
792\r
793 OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];\r
794\r
795 CompressionId = OstaCompressed[0];\r
796 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
797 return EFI_VOLUME_CORRUPTED;\r
798 }\r
799\r
800 for (Index = 1; Index < 128; Index++) {\r
801 if (CompressionId == 16) {\r
802 *String = *(UINT8 *)(OstaCompressed + Index) << 8;\r
803 Index++;\r
804 } else {\r
805 *String = 0;\r
806 }\r
807\r
808 if (Index < 128) {\r
809 *String |= *(UINT8 *)(OstaCompressed + Index);\r
810 }\r
811\r
812 //\r
813 // Unlike FID Identifiers, Logical Volume Identifier is stored in a\r
814 // NULL-terminated OSTA compressed format, so we must check for the NULL\r
815 // character.\r
816 //\r
817 if (*String == L'\0') {\r
818 break;\r
819 }\r
820\r
821 String++;\r
822 }\r
823\r
824 *String = L'\0';\r
825\r
826 FileSystemInfoLength = StrSize (VolumeLabel) +\r
827 sizeof (EFI_FILE_SYSTEM_INFO);\r
828 if (*BufferSize < FileSystemInfoLength) {\r
829 *BufferSize = FileSystemInfoLength;\r
830 return EFI_BUFFER_TOO_SMALL;\r
831 }\r
832\r
833 FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;\r
834 StrCpyS (FileSystemInfo->VolumeLabel, ARRAY_SIZE (VolumeLabel),\r
835 VolumeLabel);\r
836 Status = GetVolumeSize (\r
837 PrivFsData->BlockIo,\r
838 PrivFsData->DiskIo,\r
839 &PrivFsData->Volume,\r
840 &VolumeSize,\r
841 &FreeSpaceSize\r
842 );\r
843 if (EFI_ERROR (Status)) {\r
844 return Status;\r
845 }\r
846\r
847 FileSystemInfo->Size = FileSystemInfoLength;\r
848 FileSystemInfo->ReadOnly = TRUE;\r
849 FileSystemInfo->BlockSize =\r
850 LV_BLOCK_SIZE (&PrivFsData->Volume, UDF_DEFAULT_LV_NUM);\r
851 FileSystemInfo->VolumeSize = VolumeSize;\r
852 FileSystemInfo->FreeSpace = FreeSpaceSize;\r
853\r
854 *BufferSize = FileSystemInfoLength;\r
855 Status = EFI_SUCCESS;\r
856 }\r
857\r
858 return Status;\r
859}\r
860\r
861/**\r
862 Set information about a file.\r
863\r
864 @param File Protocol instance pointer.\r
865 @param InformationType Type of information in Buffer.\r
866 @param BufferSize Size of buffer.\r
867 @param Buffer The data to write.\r
868\r
869 @retval EFI_SUCCESS Data was set.\r
870 @retval EFI_UNSUPPORTED InformationType is not supported.\r
871 @retval EFI_NO_MEDIA The device has no media.\r
872 @retval EFI_DEVICE_ERROR The device reported an error.\r
873 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
874 @retval EFI_WRITE_PROTECTED The device is write protected.\r
875 @retval EFI_ACCESS_DENIED The file was open for read only.\r
876\r
877**/\r
878EFI_STATUS\r
879EFIAPI\r
880UdfSetInfo (\r
881 IN EFI_FILE_PROTOCOL *This,\r
882 IN EFI_GUID *InformationType,\r
883 IN UINTN BufferSize,\r
884 IN VOID *Buffer\r
885 )\r
886{\r
887 return EFI_WRITE_PROTECTED;\r
888}\r
889\r
890/**\r
891 Flush data back for the file handle.\r
892\r
893 @param This Protocol instance pointer.\r
894\r
895 @retval EFI_SUCCESS Data was flushed.\r
896 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.\r
897 @retval EFI_NO_MEDIA The device has no media.\r
898 @retval EFI_DEVICE_ERROR The device reported an error.\r
899 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
900 @retval EFI_WRITE_PROTECTED The device is write protected.\r
901 @retval EFI_ACCESS_DENIED The file was open for read only.\r
902 @retval EFI_VOLUME_FULL The volume is full.\r
903\r
904**/\r
905EFI_STATUS\r
906EFIAPI\r
907UdfFlush (\r
908 IN EFI_FILE_PROTOCOL *This\r
909 )\r
910{\r
911 return EFI_WRITE_PROTECTED;\r
912}\r