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