OpenCore  1.0.6
OpenCore Bootloader
Loading...
Searching...
No Matches
Open.c
Go to the documentation of this file.
1
9#include "NTFS.h"
10#include "Helper.h"
11
12extern INT64 mIndexCounter;
13
14EFI_STATUS
15EFIAPI
17 IN EFI_FILE_PROTOCOL *This,
18 OUT EFI_FILE_PROTOCOL **NewHandle,
19 IN CHAR16 *FileName,
20 IN UINT64 OpenMode,
21 IN UINT64 Attributes
22 )
23{
24 EFI_STATUS Status;
25 EFI_NTFS_FILE *File;
26 EFI_FS *FileSystem;
27 EFI_NTFS_FILE *NewFile;
28 CHAR16 Path[MAX_PATH];
29 CHAR16 CleanPath[MAX_PATH];
30 CHAR16 *DirName;
31 UINTN Index;
32 UINTN Length;
33 BOOLEAN AbsolutePath;
34
35 ASSERT (This != NULL);
36 ASSERT (NewHandle != NULL);
37 ASSERT (FileName != NULL);
38
39 File = (EFI_NTFS_FILE *)This;
40 FileSystem = File->FileSystem;
41 AbsolutePath = (*FileName == L'\\');
42
43 ZeroMem (Path, sizeof (Path));
44
45 if (OpenMode != EFI_FILE_MODE_READ) {
46 DEBUG ((DEBUG_INFO, "NTFS: File '%s' can only be opened in read-only mode\n", FileName));
47 return EFI_WRITE_PROTECTED;
48 }
49
50 if ((*FileName == 0) || (CompareMem (FileName, L".", sizeof (L".")) == 0)) {
51 ++File->RefCount;
52 *NewHandle = This;
53 return EFI_SUCCESS;
54 }
55
56 if (AbsolutePath) {
57 Length = 0;
58 } else {
59 Length = StrnLenS (File->Path, MAX_PATH);
60 if (Length == MAX_PATH) {
61 DEBUG ((DEBUG_INFO, "NTFS: Path is too long.\n"));
62 return EFI_OUT_OF_RESOURCES;
63 }
64
65 Status = StrCpyS (Path, MAX_PATH, File->Path);
66 if (EFI_ERROR (Status)) {
67 DEBUG ((DEBUG_INFO, "NTFS: Could not copy string.\n"));
68 return Status;
69 }
70
71 if ((Length == 0) || (Path[Length - 1U] != '/')) {
72 Path[Length++] = L'/';
73 }
74 }
75
76 Status = StrCpyS (&Path[Length], MAX_PATH - Length, FileName);
77 if (EFI_ERROR (Status)) {
78 DEBUG ((DEBUG_INFO, "NTFS: Could not copy FileName `%s`.\n", FileName));
79 return Status;
80 }
81
82 Index = StrnLenS (Path, MAX_PATH);
83 while (Index > Length) {
84 --Index;
85 if (Path[Index] == L'\\') {
86 Path[Index] = L'/';
87 }
88 }
89
90 ZeroMem (CleanPath, sizeof (CleanPath));
91 Status = RelativeToAbsolute (CleanPath, Path);
92 if (EFI_ERROR (Status)) {
93 return Status;
94 }
95
96 NewFile = AllocateZeroPool (sizeof (EFI_NTFS_FILE));
97 if (NewFile == NULL) {
98 return EFI_OUT_OF_RESOURCES;
99 }
100
101 NewFile->FileSystem = FileSystem;
102 CopyMem (&NewFile->EfiFile, &FileSystem->EfiFile, sizeof (EFI_FILE_PROTOCOL));
103
104 NewFile->Path = AllocateZeroPool (StrnSizeS (CleanPath, MAX_PATH));
105 if (NewFile->Path == NULL) {
106 DEBUG ((DEBUG_INFO, "NTFS: Could not instantiate path\n"));
107 FreePool (NewFile);
108 return EFI_OUT_OF_RESOURCES;
109 }
110
111 CopyMem (NewFile->Path, CleanPath, StrnSizeS (CleanPath, MAX_PATH));
112
113 Length = StrnLenS (CleanPath, MAX_PATH);
114 if (Length == MAX_PATH) {
115 DEBUG ((DEBUG_INFO, "NTFS: CleanPath is too long.\n"));
116 return EFI_OUT_OF_RESOURCES;
117 }
118
119 Index = Length;
120 while (Index > 0) {
121 --Index;
122 if (CleanPath[Index] == L'/') {
123 CleanPath[Index] = 0;
124 break;
125 }
126 }
127
128 DirName = (Index == 0) ? L"/" : CleanPath;
129 NewFile->BaseName = (Index == Length) ? L"\0" : &NewFile->Path[Index + 1U];
130
131 Status = NtfsDir (FileSystem, DirName, NewFile, INFO_HOOK);
132 if (EFI_ERROR (Status)) {
133 FreePool (NewFile->Path);
134 FreePool (NewFile);
135 return Status;
136 }
137
138 if (!NewFile->IsDir) {
139 Status = NtfsOpen (NewFile);
140 if (EFI_ERROR (Status)) {
141 FreePool (NewFile->Path);
142 FreePool (NewFile);
143 return Status;
144 }
145 }
146
147 NewFile->RefCount++;
148 *NewHandle = &NewFile->EfiFile;
149
150 return EFI_SUCCESS;
151}
152
153STATIC
154EFI_STATUS
156 IN EFI_NTFS_FILE *File,
157 OUT VOID *Data,
158 IN OUT UINTN *Size
159 )
160{
161 EFI_STATUS Status;
162 EFI_FILE_INFO *Info;
163 CHAR16 Path[MAX_PATH];
164 EFI_NTFS_FILE *TmpFile = NULL;
165 UINTN Length;
166 INTN Res;
167
168 ASSERT (File != NULL);
169 ASSERT (Size != NULL);
170 ASSERT ((Data != NULL) || ((Data == NULL) && (*Size == 0)));
171
172 ZeroMem (Path, sizeof (Path));
173 Status = StrCpyS (Path, MAX_PATH, File->Path);
174 if (EFI_ERROR (Status)) {
175 DEBUG ((DEBUG_INFO, "NTFS: Could not copy string.\n"));
176 return Status;
177 }
178
179 Length = StrnLenS (Path, MAX_PATH);
180 if (Length == MAX_PATH) {
181 DEBUG ((DEBUG_INFO, "NTFS: Path is too long.\n"));
182 return EFI_OUT_OF_RESOURCES;
183 }
184
185 if ((Length == 0) || (Path[Length - 1U] != L'/')) {
186 Path[Length] = L'/';
187 Length++;
188 }
189
190 Res = NtfsCfiPop (
191 File->FileSystem,
192 Path,
193 *Size,
194 (INT64)File->DirIndex,
195 Data
196 );
197
198 if (Res != 0) {
199 if (Res < 0) {
200 *Size = File->FileSystem->CFIDataSize;
201 return EFI_BUFFER_TOO_SMALL;
202 }
203
204 Info = (EFI_FILE_INFO *)Data;
205 *Size = (UINTN)Info->Size;
206 ++File->DirIndex;
207 return EFI_SUCCESS;
208 }
209
210 ZeroMem (File->FileSystem->CFIData, MINIMUM_INFO_LENGTH);
211 Info = (EFI_FILE_INFO *)File->FileSystem->CFIData;
212 Info->Size = MINIMUM_INFO_LENGTH;
213
214 mIndexCounter = (INT64)File->DirIndex;
215 if (Length == 0) {
216 Status = NtfsDir (File->FileSystem, L"/", File->FileSystem->CFIData, DIR_HOOK);
217 } else {
218 Status = NtfsDir (File->FileSystem, File->Path, File->FileSystem->CFIData, DIR_HOOK);
219 }
220
221 if (mIndexCounter >= 0) {
222 //
223 // No entries left
224 //
225 *Size = 0;
226 return EFI_SUCCESS;
227 }
228
229 if (EFI_ERROR (Status)) {
230 DEBUG ((DEBUG_INFO, "NTFS: Directory listing failed.\n"));
231 return Status;
232 }
233
234 Info->FileSize = 0;
235 Info->PhysicalSize = 0;
236
237 if ((Info->Attribute & EFI_FILE_DIRECTORY) == 0) {
238 TmpFile = AllocateZeroPool (sizeof (EFI_NTFS_FILE));
239 if (TmpFile == NULL) {
240 return EFI_OUT_OF_RESOURCES;
241 }
242
243 TmpFile->FileSystem = File->FileSystem;
244 CopyMem (&TmpFile->EfiFile, &File->FileSystem->EfiFile, sizeof (EFI_FILE_PROTOCOL));
245
246 if ((MAX_PATH - Length) < StrSize (Info->FileName)) {
247 DEBUG ((DEBUG_INFO, "NTFS: FileName is too long.\n"));
248 FreePool (TmpFile);
249 return EFI_OUT_OF_RESOURCES;
250 }
251
252 CopyMem (&Path[Length], Info->FileName, StrSize (Info->FileName));
253 TmpFile->Path = Path;
254
255 Status = NtfsOpen (TmpFile);
256 if (EFI_ERROR (Status)) {
257 // DEBUG ((DEBUG_INFO, "NTFS: Unable to obtain the size of '%s'\n", Info->FileName));
258 } else {
259 Info->FileSize = TmpFile->RootFile.DataAttributeSize;
260 Info->PhysicalSize = TmpFile->RootFile.DataAttributeSize;
261 }
262
263 FreeFile (&TmpFile->RootFile);
264 FreePool (TmpFile);
265 }
266
267 if (*Size < Info->Size) {
268 *Size = (UINTN)Info->Size;
269 NtfsCfiPush (File->FileSystem, Path, (UINTN)Info->Size, (INT64)File->DirIndex);
270 return EFI_BUFFER_TOO_SMALL;
271 } else {
272 CopyMem (Data, File->FileSystem->CFIData, (UINTN)Info->Size);
273 }
274
275 *Size = (UINTN)Info->Size;
276 ++File->DirIndex;
277
278 // DEBUG ((DEBUG_INFO, "NTFS: Entry[%d]: '%s' %s\n", File->DirIndex - 1U, Info->FileName,
279 // (Info->Attribute & EFI_FILE_DIRECTORY) ? L"<DIR>" : L""));
280
281 return EFI_SUCCESS;
282}
283
284STATIC
285EFI_STATUS
287 IN EFI_NTFS_FILE *File,
288 OUT VOID *Data,
289 IN UINTN *Size
290 )
291{
292 EFI_STATUS Status;
293 UINT64 Remaining;
294 NTFS_FILE *BaseMftRecord;
295
296 ASSERT (File != NULL);
297 ASSERT (Size != NULL);
298 ASSERT ((Data != NULL) || ((Data == NULL) && (*Size == 0)));
299
300 Remaining = (File->RootFile.DataAttributeSize > File->Offset) ?
301 File->RootFile.DataAttributeSize - File->Offset : 0;
302
303 if (*Size > Remaining) {
304 *Size = (UINTN)Remaining;
305 }
306
307 BaseMftRecord = &File->RootFile;
308
309 Status = ReadAttr (&BaseMftRecord->Attr, Data, File->Offset, *Size);
310 if (EFI_ERROR (Status)) {
311 *Size = 0;
312 FreeAttr (&BaseMftRecord->Attr);
313 return Status;
314 }
315
316 File->Offset += *Size;
317
318 return EFI_SUCCESS;
319}
320
321EFI_STATUS
322EFIAPI
324 IN EFI_FILE_PROTOCOL *This,
325 IN OUT UINTN *BufferSize,
326 OUT VOID *Buffer
327 )
328{
329 EFI_NTFS_FILE *File;
330
331 ASSERT (This != NULL);
332 ASSERT (BufferSize != NULL);
333 ASSERT ((Buffer != NULL) || ((Buffer == NULL) && (*BufferSize == 0)));
334
335 File = (EFI_NTFS_FILE *)This;
336
337 if (File->IsDir) {
338 return FileReadDir (File, Buffer, BufferSize);
339 }
340
341 return Read (File, Buffer, BufferSize);
342}
343
344EFI_STATUS
345EFIAPI
347 IN EFI_FILE_PROTOCOL *This,
348 IN OUT UINTN *BufferSize,
349 IN VOID *Buffer
350 )
351{
352 return EFI_WRITE_PROTECTED;
353}
354
355EFI_STATUS
356EFIAPI
358 IN EFI_FILE_PROTOCOL *This
359 )
360{
361 FileClose (This);
362
363 return EFI_WARN_DELETE_FAILURE;
364}
365
366EFI_STATUS
367EFIAPI
369 IN EFI_FILE_PROTOCOL *This
370 )
371{
372 return EFI_ACCESS_DENIED;
373}
374
375EFI_STATUS
376EFIAPI
378 IN EFI_FILE_PROTOCOL *This
379 )
380{
381 EFI_NTFS_FILE *File;
382
383 ASSERT (This != NULL);
384
385 File = (EFI_NTFS_FILE *)This;
386
387 if (&File->RootFile == File->FileSystem->RootIndex) {
388 return EFI_SUCCESS;
389 }
390
391 if (--File->RefCount == 0) {
392 FreeFile (&File->RootFile);
393 FreeFile (&File->MftFile);
394
395 if (File->Path != NULL) {
396 FreePool (File->Path);
397 }
398
399 FreePool (File);
400 }
401
402 return EFI_SUCCESS;
403}
UINT64 Length
INTN NtfsCfiPop(IN EFI_FS *Fs, IN CONST CHAR16 *Path, IN UINTN Size, IN INT64 DirIndex, OUT VOID *Buffer)
Definition Cache.c:88
VOID NtfsCfiPush(IN EFI_FS *Fs, IN CONST CHAR16 *Path, IN UINTN Size, IN INT64 DirIndex)
Definition Cache.c:72
EFI_STATUS EFIAPI ReadAttr(IN NTFS_ATTR *Attr, OUT UINT8 *Dest, IN UINT64 Offset, IN UINTN Length)
Definition Data.c:184
VOID FreeFile(IN NTFS_FILE *File)
Definition Disc.c:817
EFI_STATUS NtfsDir(IN EFI_FS *FileSystem, IN CONST CHAR16 *Path, OUT EFI_NTFS_FILE *File, IN FUNCTION_TYPE FunctionType)
Definition Disc.c:13
VOID FreeAttr(IN NTFS_ATTR *Attr)
Definition Disc.c:799
EFI_STATUS NtfsOpen(IN EFI_NTFS_FILE *File)
Definition Disc.c:53
#define MAX_PATH
Definition Driver.h:16
#define MINIMUM_INFO_LENGTH
Definition Driver.h:17
EFI_STATUS RelativeToAbsolute(OUT CHAR16 *Dest, IN CHAR16 *Source)
Definition Index.c:826
@ INFO_HOOK
Definition Helper.h:55
@ DIR_HOOK
Definition Helper.h:56
DMG_SIZE_DEVICE_PATH Size
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
EFI_STATUS EFIAPI FileClose(IN EFI_FILE_PROTOCOL *This)
Definition Open.c:377
EFI_STATUS EFIAPI FileFlush(IN EFI_FILE_PROTOCOL *This)
Definition Open.c:368
EFI_STATUS EFIAPI FileDelete(IN EFI_FILE_PROTOCOL *This)
Definition Open.c:357
INT64 mIndexCounter
Definition Index.c:14
STATIC EFI_STATUS FileReadDir(IN EFI_NTFS_FILE *File, OUT VOID *Data, IN OUT UINTN *Size)
Definition Open.c:155
EFI_STATUS EFIAPI FileOpen(IN EFI_FILE_PROTOCOL *This, OUT EFI_FILE_PROTOCOL **NewHandle, IN CHAR16 *FileName, IN UINT64 OpenMode, IN UINT64 Attributes)
Definition Open.c:16
EFI_STATUS EFIAPI FileWrite(IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, IN VOID *Buffer)
Definition Open.c:346
STATIC EFI_STATUS Read(IN EFI_NTFS_FILE *File, OUT VOID *Data, IN UINTN *Size)
Definition Open.c:286
EFI_STATUS EFIAPI FileRead(IN EFI_FILE_PROTOCOL *This, IN OUT UINTN *BufferSize, OUT VOID *Buffer)
Definition Open.c:323
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define ASSERT(x)
Definition coder.h:55
EFI_FILE_PROTOCOL EfiFile
Definition Driver.h:648
NTFS_FILE * RootIndex
Definition Driver.h:653
NTFS_FILE RootFile
Definition Driver.h:641
UINT32 RefCount
Definition Driver.h:640
BOOLEAN IsDir
Definition Driver.h:635
CHAR16 * Path
Definition Driver.h:637
CHAR16 * BaseName
Definition Driver.h:638
EFI_FS * FileSystem
Definition Driver.h:643
EFI_FILE_PROTOCOL EfiFile
Definition Driver.h:634
NTFS_FILE MftFile
Definition Driver.h:642
NTFS_ATTR Attr
Definition Driver.h:629
UINT64 DataAttributeSize
Definition Driver.h:623