hc
2024-03-25 edb30157bad0c0001c32b854271ace01d3b9a16a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/** @file
  Driver entry point
 
  Copyright (c) 2021 Pedro Falcato All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent
**/
 
#include "Ext4Dxe.h"
 
/**
   Opens an ext4 partition and installs the Simple File System protocol.
 
   @param[in]        DeviceHandle     Handle to the block device.
   @param[in]        DiskIo           Pointer to an EFI_DISK_IO_PROTOCOL.
   @param[in opt]    DiskIo2          Pointer to an EFI_DISK_IO2_PROTOCOL, if supported.
   @param[in]        BlockIo          Pointer to an EFI_BLOCK_IO_PROTOCOL.
 
   @retval EFI_SUCCESS      The opening was successful.
           !EFI_SUCCESS     Opening failed.
**/
EFI_STATUS
Ext4OpenPartition (
  IN EFI_HANDLE                      DeviceHandle,
  IN EFI_DISK_IO_PROTOCOL            *DiskIo,
  IN OPTIONAL EFI_DISK_IO2_PROTOCOL  *DiskIo2,
  IN EFI_BLOCK_IO_PROTOCOL           *BlockIo
  )
{
  EXT4_PARTITION  *Part;
  EFI_STATUS      Status;
 
  Part = AllocateZeroPool (sizeof (*Part));
 
  if (Part == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }
 
  InitializeListHead (&Part->OpenFiles);
 
  Part->BlockIo = BlockIo;
  Part->DiskIo  = DiskIo;
  Part->DiskIo2 = DiskIo2;
 
  Status = Ext4OpenSuperblock (Part);
 
  if (EFI_ERROR (Status)) {
    FreePool (Part);
    return Status;
  }
 
  Part->Interface.Revision   = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
  Part->Interface.OpenVolume = Ext4OpenVolume;
  Status = gBS->InstallMultipleProtocolInterfaces (
                  &DeviceHandle,
                  &gEfiSimpleFileSystemProtocolGuid,
                  &Part->Interface,
                  NULL
                  );
 
  if (EFI_ERROR (Status)) {
    FreePool (Part);
    return Status;
  }
 
  return EFI_SUCCESS;
}
 
/**
   Sets up the protocol and metadata of a file that is being opened.
 
   @param[in out]        File        Pointer to the file.
   @param[in]            Partition   Pointer to the opened partition.
**/
VOID
Ext4SetupFile (
  IN OUT EXT4_FILE   *File,
  IN EXT4_PARTITION  *Partition
  )
{
  // Note: We don't yet support revision 2 of the file protocol
  // (needs DISK_IO2 + asynchronous IO)
  File->Protocol.Revision    = EFI_FILE_PROTOCOL_REVISION;
  File->Protocol.Open        = Ext4Open;
  File->Protocol.Close       = Ext4Close;
  File->Protocol.Delete      = Ext4Delete;
  File->Protocol.Read        = Ext4ReadFile;
  File->Protocol.Write       = Ext4WriteFile;
  File->Protocol.SetPosition = Ext4SetPosition;
  File->Protocol.GetPosition = Ext4GetPosition;
  File->Protocol.GetInfo     = Ext4GetInfo;
  File->Protocol.SetInfo     = Ext4SetInfo;
 
  File->Partition = Partition;
}
 
/**
   Unmounts and frees an ext4 partition.
 
   @param[in]        Partition        Pointer to the opened partition.
 
   @retval Status of the unmount.
**/
EFI_STATUS
Ext4UnmountAndFreePartition (
  IN EXT4_PARTITION  *Partition
  )
{
  LIST_ENTRY  *Entry;
  LIST_ENTRY  *NextEntry;
  EXT4_FILE   *File;
  BOOLEAN     DeletedRootDentry;
 
  Partition->Unmounting = TRUE;
  Ext4CloseInternal (Partition->Root);
 
  BASE_LIST_FOR_EACH_SAFE (Entry, NextEntry, &Partition->OpenFiles) {
    File = EXT4_FILE_FROM_OPEN_FILES_NODE (Entry);
 
    Ext4CloseInternal (File);
  }
 
  DeletedRootDentry = Ext4UnrefDentry (Partition->RootDentry);
 
  if (!DeletedRootDentry) {
    DEBUG ((DEBUG_ERROR, "[ext4] Failed to delete root dentry - resource leak present.\n"));
  }
 
  FreePool (Partition->BlockGroups);
  FreePool (Partition);
 
  return EFI_SUCCESS;
}