Coverage Report

Created: 2025-12-09 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}