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