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