MdeModulePkg/UDF: Fix creation of UDF logical partition
[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
411\r
412 if (!IS_FID_PARENT_FILE (NewFileIdentifierDesc)) {\r
413 break;\r
414 }\r
415\r
416 FreePool ((VOID *)NewFileIdentifierDesc);\r
417 }\r
418\r
419 Status = FindFileEntry (\r
420 BlockIo,\r
421 DiskIo,\r
422 Volume,\r
423 &NewFileIdentifierDesc->Icb,\r
424 &NewFileEntryData\r
425 );\r
426 if (EFI_ERROR (Status)) {\r
427 goto Error_Find_Fe;\r
428 }\r
3fa40d58 429 ASSERT (NewFileEntryData != NULL);\r
99c9b949 430\r
baaa3cee 431 if (FE_ICB_FILE_TYPE (NewFileEntryData) == UdfFileEntrySymlink) {\r
99c9b949
PA
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
99c9b949
PA
531\r
532 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
533\r
534 Status = EFI_SUCCESS;\r
535\r
536 if (This == NULL) {\r
537 Status = EFI_INVALID_PARAMETER;\r
538 goto Exit;\r
539 }\r
540\r
541 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
542\r
99c9b949
PA
543 if (!PrivFileData->IsRootDirectory) {\r
544 CleanupFileInformation (&PrivFileData->File);\r
545\r
546 if (PrivFileData->ReadDirInfo.DirectoryData != NULL) {\r
547 FreePool (PrivFileData->ReadDirInfo.DirectoryData);\r
548 }\r
549 }\r
550\r
99c9b949
PA
551 FreePool ((VOID *)PrivFileData);\r
552\r
553Exit:\r
554 gBS->RestoreTPL (OldTpl);\r
555\r
556 return Status;\r
557}\r
558\r
559/**\r
560 Close and delete the file handle.\r
561\r
562 @param This Protocol instance pointer.\r
563\r
564 @retval EFI_SUCCESS The file was closed and deleted.\r
565 @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not\r
566 deleted.\r
567\r
568**/\r
569EFI_STATUS\r
570EFIAPI\r
571UdfDelete (\r
572 IN EFI_FILE_PROTOCOL *This\r
573 )\r
574{\r
575 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
576\r
577 if (This == NULL) {\r
578 return EFI_INVALID_PARAMETER;\r
579 }\r
580\r
581 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
582\r
583 (VOID)PrivFileData->FileIo.Close(This);\r
584\r
585 return EFI_WARN_DELETE_FAILURE;\r
586}\r
587\r
588/**\r
589 Write data to a file.\r
590\r
591 @param This Protocol instance pointer.\r
592 @param BufferSize On input size of buffer, on output amount of data in\r
593 buffer.\r
594 @param Buffer The buffer in which data to write.\r
595\r
596 @retval EFI_SUCCESS Data was written.\r
597 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.\r
598 @retval EFI_NO_MEDIA The device has no media.\r
599 @retval EFI_DEVICE_ERROR The device reported an error.\r
600 @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file.\r
601 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
602 @retval EFI_WRITE_PROTECTED The device is write protected.\r
603 @retval EFI_ACCESS_DENIED The file was open for read only.\r
604 @retval EFI_VOLUME_FULL The volume is full.\r
605\r
606**/\r
607EFI_STATUS\r
608EFIAPI\r
609UdfWrite (\r
610 IN EFI_FILE_PROTOCOL *This,\r
611 IN OUT UINTN *BufferSize,\r
612 IN VOID *Buffer\r
613 )\r
614{\r
615 return EFI_UNSUPPORTED;\r
616}\r
617\r
618/**\r
619 Get file's current position.\r
620\r
621 @param This Protocol instance pointer.\r
622 @param Position Byte position from the start of the file.\r
623\r
624 @retval EFI_SUCCESS Position was updated.\r
625 @retval EFI_UNSUPPORTED Seek request for directories is not valid.\r
626\r
627**/\r
628EFI_STATUS\r
629EFIAPI\r
630UdfGetPosition (\r
631 IN EFI_FILE_PROTOCOL *This,\r
632 OUT UINT64 *Position\r
633 )\r
634{\r
635 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
636\r
637 if (This == NULL || Position == NULL) {\r
638 return EFI_INVALID_PARAMETER;\r
639 }\r
640\r
641 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
642\r
643 //\r
644 // As per UEFI spec, if the file handle is a directory, then the current file\r
645 // position has no meaning and the operation is not supported.\r
646 //\r
baaa3cee 647 if (IS_FID_DIRECTORY_FILE (PrivFileData->File.FileIdentifierDesc)) {\r
99c9b949
PA
648 return EFI_UNSUPPORTED;\r
649 }\r
650\r
651 //\r
652 // The file is not a directory. So, return its position.\r
653 //\r
654 *Position = PrivFileData->FilePosition;\r
655\r
656 return EFI_SUCCESS;\r
657}\r
658\r
659/**\r
660 Set file's current position.\r
661\r
662 @param This Protocol instance pointer.\r
663 @param Position Byte position from the start of the file.\r
664\r
665 @retval EFI_SUCCESS Position was updated.\r
666 @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.\r
667\r
668**/\r
669EFI_STATUS\r
670EFIAPI\r
671UdfSetPosition (\r
672 IN EFI_FILE_PROTOCOL *This,\r
673 IN UINT64 Position\r
674 )\r
675{\r
676 EFI_STATUS Status;\r
677 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
678 UDF_FILE_IDENTIFIER_DESCRIPTOR *FileIdentifierDesc;\r
679\r
680 if (This == NULL) {\r
681 return EFI_INVALID_PARAMETER;\r
682 }\r
683\r
684 Status = EFI_UNSUPPORTED;\r
685\r
686 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
687\r
11b4463e
PA
688 FileIdentifierDesc = _FILE (PrivFileData)->FileIdentifierDesc;\r
689 ASSERT (FileIdentifierDesc != NULL);\r
99c9b949
PA
690 if (IS_FID_DIRECTORY_FILE (FileIdentifierDesc)) {\r
691 //\r
692 // If the file handle is a directory, the _only_ position that may be set is\r
693 // zero. This has no effect of starting the read proccess of the directory\r
694 // entries over.\r
695 //\r
696 if (Position == 0) {\r
697 PrivFileData->FilePosition = Position;\r
698 PrivFileData->ReadDirInfo.FidOffset = 0;\r
699 Status = EFI_SUCCESS;\r
700 }\r
701 } else if (IS_FID_NORMAL_FILE (FileIdentifierDesc)) {\r
702 //\r
703 // Seeking to position 0xFFFFFFFFFFFFFFFF causes the current position to be\r
704 // set to the EOF.\r
705 //\r
706 if (Position == 0xFFFFFFFFFFFFFFFF) {\r
707 PrivFileData->FilePosition = PrivFileData->FileSize - 1;\r
708 } else {\r
709 PrivFileData->FilePosition = Position;\r
710 }\r
711\r
712 Status = EFI_SUCCESS;\r
713 }\r
714\r
715 return Status;\r
716}\r
717\r
718/**\r
719 Get information about a file.\r
720\r
721 @param This Protocol instance pointer.\r
722 @param InformationType Type of information to return in Buffer.\r
723 @param BufferSize On input size of buffer, on output amount of data in\r
724 buffer.\r
725 @param Buffer The buffer to return data.\r
726\r
727 @retval EFI_SUCCESS Data was returned.\r
728 @retval EFI_UNSUPPORTED InformationType is not supported.\r
729 @retval EFI_NO_MEDIA The device has no media.\r
730 @retval EFI_DEVICE_ERROR The device reported an error.\r
731 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
732 @retval EFI_WRITE_PROTECTED The device is write protected.\r
733 @retval EFI_ACCESS_DENIED The file was open for read only.\r
734 @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in\r
735 BufferSize.\r
736\r
737**/\r
738EFI_STATUS\r
739EFIAPI\r
740UdfGetInfo (\r
741 IN EFI_FILE_PROTOCOL *This,\r
742 IN EFI_GUID *InformationType,\r
743 IN OUT UINTN *BufferSize,\r
744 OUT VOID *Buffer\r
745 )\r
746{\r
747 EFI_STATUS Status;\r
748 PRIVATE_UDF_FILE_DATA *PrivFileData;\r
749 PRIVATE_UDF_SIMPLE_FS_DATA *PrivFsData;\r
750 EFI_FILE_SYSTEM_INFO *FileSystemInfo;\r
751 UINTN FileSystemInfoLength;\r
752 CHAR16 *String;\r
753 UDF_FILE_SET_DESCRIPTOR *FileSetDesc;\r
754 UINTN Index;\r
755 UINT8 *OstaCompressed;\r
756 UINT8 CompressionId;\r
757 UINT64 VolumeSize;\r
758 UINT64 FreeSpaceSize;\r
759 CHAR16 VolumeLabel[64];\r
760\r
761 if (This == NULL || InformationType == NULL || BufferSize == NULL ||\r
762 (*BufferSize != 0 && Buffer == NULL)) {\r
763 return EFI_INVALID_PARAMETER;\r
764 }\r
765\r
766 PrivFileData = PRIVATE_UDF_FILE_DATA_FROM_THIS (This);\r
767\r
768 PrivFsData = PRIVATE_UDF_SIMPLE_FS_DATA_FROM_THIS (PrivFileData->SimpleFs);\r
769\r
770 Status = EFI_UNSUPPORTED;\r
771\r
772 if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
773 Status = SetFileInfo (\r
774 _FILE (PrivFileData),\r
775 PrivFileData->FileSize,\r
776 PrivFileData->FileName,\r
777 BufferSize,\r
778 Buffer\r
779 );\r
780 } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) {\r
781 String = VolumeLabel;\r
782\r
baaa3cee 783 FileSetDesc = &PrivFsData->Volume.FileSetDesc;\r
99c9b949
PA
784\r
785 OstaCompressed = &FileSetDesc->LogicalVolumeIdentifier[0];\r
786\r
787 CompressionId = OstaCompressed[0];\r
788 if (!IS_VALID_COMPRESSION_ID (CompressionId)) {\r
789 return EFI_VOLUME_CORRUPTED;\r
790 }\r
791\r
792 for (Index = 1; Index < 128; Index++) {\r
793 if (CompressionId == 16) {\r
794 *String = *(UINT8 *)(OstaCompressed + Index) << 8;\r
795 Index++;\r
796 } else {\r
797 *String = 0;\r
798 }\r
799\r
800 if (Index < 128) {\r
fedec0a3 801 *String |= (CHAR16)(*(UINT8 *)(OstaCompressed + Index));\r
99c9b949
PA
802 }\r
803\r
804 //\r
805 // Unlike FID Identifiers, Logical Volume Identifier is stored in a\r
806 // NULL-terminated OSTA compressed format, so we must check for the NULL\r
807 // character.\r
808 //\r
809 if (*String == L'\0') {\r
810 break;\r
811 }\r
812\r
813 String++;\r
814 }\r
815\r
816 *String = L'\0';\r
817\r
818 FileSystemInfoLength = StrSize (VolumeLabel) +\r
819 sizeof (EFI_FILE_SYSTEM_INFO);\r
820 if (*BufferSize < FileSystemInfoLength) {\r
821 *BufferSize = FileSystemInfoLength;\r
822 return EFI_BUFFER_TOO_SMALL;\r
823 }\r
824\r
825 FileSystemInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;\r
826 StrCpyS (FileSystemInfo->VolumeLabel, ARRAY_SIZE (VolumeLabel),\r
827 VolumeLabel);\r
828 Status = GetVolumeSize (\r
829 PrivFsData->BlockIo,\r
830 PrivFsData->DiskIo,\r
831 &PrivFsData->Volume,\r
832 &VolumeSize,\r
833 &FreeSpaceSize\r
834 );\r
835 if (EFI_ERROR (Status)) {\r
836 return Status;\r
837 }\r
838\r
839 FileSystemInfo->Size = FileSystemInfoLength;\r
840 FileSystemInfo->ReadOnly = TRUE;\r
841 FileSystemInfo->BlockSize =\r
baaa3cee 842 PrivFsData->Volume.LogicalVolDesc.LogicalBlockSize;\r
99c9b949
PA
843 FileSystemInfo->VolumeSize = VolumeSize;\r
844 FileSystemInfo->FreeSpace = FreeSpaceSize;\r
845\r
846 *BufferSize = FileSystemInfoLength;\r
847 Status = EFI_SUCCESS;\r
848 }\r
849\r
850 return Status;\r
851}\r
852\r
853/**\r
854 Set information about a file.\r
855\r
077f8c43 856 @param This Protocol instance pointer.\r
99c9b949
PA
857 @param InformationType Type of information in Buffer.\r
858 @param BufferSize Size of buffer.\r
859 @param Buffer The data to write.\r
860\r
861 @retval EFI_SUCCESS Data was set.\r
862 @retval EFI_UNSUPPORTED InformationType is not supported.\r
863 @retval EFI_NO_MEDIA The device has no media.\r
864 @retval EFI_DEVICE_ERROR The device reported an error.\r
865 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
866 @retval EFI_WRITE_PROTECTED The device is write protected.\r
867 @retval EFI_ACCESS_DENIED The file was open for read only.\r
868\r
869**/\r
870EFI_STATUS\r
871EFIAPI\r
872UdfSetInfo (\r
873 IN EFI_FILE_PROTOCOL *This,\r
874 IN EFI_GUID *InformationType,\r
875 IN UINTN BufferSize,\r
876 IN VOID *Buffer\r
877 )\r
878{\r
879 return EFI_WRITE_PROTECTED;\r
880}\r
881\r
882/**\r
883 Flush data back for the file handle.\r
884\r
885 @param This Protocol instance pointer.\r
886\r
887 @retval EFI_SUCCESS Data was flushed.\r
888 @retval EFI_UNSUPPORTED Writes to Open directory are not supported.\r
889 @retval EFI_NO_MEDIA The device has no media.\r
890 @retval EFI_DEVICE_ERROR The device reported an error.\r
891 @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
892 @retval EFI_WRITE_PROTECTED The device is write protected.\r
893 @retval EFI_ACCESS_DENIED The file was open for read only.\r
894 @retval EFI_VOLUME_FULL The volume is full.\r
895\r
896**/\r
897EFI_STATUS\r
898EFIAPI\r
899UdfFlush (\r
900 IN EFI_FILE_PROTOCOL *This\r
901 )\r
902{\r
903 return EFI_WRITE_PROTECTED;\r
904}\r