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