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