[BOOTMGFW]
[reactos.git] / reactos / boot / environ / lib / io / file.c
1 /*
2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Library
4 * FILE: boot/environ/lib/io/file.c
5 * PURPOSE: Boot Library File Management Routines
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "bl.h"
12
13 /* DATA VARIABLES ************************************************************/
14
15 PVOID* FileTable;
16 ULONG FileEntries;
17
18 LIST_ENTRY RegisteredFileSystems;
19 BL_FILE_SYSTEM_REGISTRATION_TABLE FatRegisterFunctionTable =
20 {
21 FatInitialize,
22 NULL,
23 FatMount,
24 NULL
25 };
26 BL_FILE_SYSTEM_REGISTRATION_TABLE EtfsRegisterFunctionTable =
27 {
28 EtfsInitialize,
29 NULL,
30 EtfsMount,
31 NULL
32 };
33
34
35 extern ULONG DmTableEntries;
36 extern PVOID* DmDeviceTable;
37
38 /* FUNCTIONS *****************************************************************/
39
40 PWCHAR
41 FileIoCopyParentDirectoryPath (
42 _In_ PWCHAR FilePath
43 )
44 {
45 ULONG PathSize, PathSizeWithNull;
46 PWCHAR Backslash, ParentCopy;
47
48 PathSize = wcslen(FilePath) * sizeof(WCHAR);
49
50 PathSizeWithNull = PathSize + sizeof(UNICODE_NULL);
51 if (PathSizeWithNull < PathSize)
52 {
53 return NULL;
54 }
55
56 ParentCopy = BlMmAllocateHeap(PathSizeWithNull);
57 if (!ParentCopy)
58 {
59 return NULL;
60 }
61 wcsncpy(ParentCopy, FilePath, PathSizeWithNull / sizeof(WCHAR));
62
63 Backslash = wcsrchr(ParentCopy, '\\');
64 if (!Backslash)
65 {
66 BlMmFreeHeap(ParentCopy);
67 return NULL;
68 }
69
70 if (Backslash == ParentCopy)
71 {
72 ++Backslash;
73 }
74
75 *Backslash = UNICODE_NULL;
76 return ParentCopy;
77 }
78
79 PWCHAR
80 FileIoCopyFileName (
81 _In_ PWCHAR FilePath
82 )
83 {
84 PWCHAR Separator, FileCopy;
85 ULONG PathSize;
86
87 Separator = wcsrchr(FilePath, '\\');
88 if (!Separator)
89 {
90 return NULL;
91 }
92
93 PathSize = wcslen(Separator) * sizeof(WCHAR);
94
95 FileCopy = BlMmAllocateHeap(PathSize);
96 if (!FileCopy)
97 {
98 return NULL;
99 }
100
101 wcsncpy(FileCopy, Separator + 1, PathSize / sizeof(WCHAR));
102 return FileCopy;
103 }
104
105 BOOLEAN
106 FileTableCompareWithSubsetAttributes (
107 _In_ PVOID Entry,
108 _In_ PVOID Argument1,
109 _In_ PVOID Argument2,
110 _In_ PVOID Argument3,
111 _In_ PVOID Argument4
112 )
113 {
114 PBL_FILE_ENTRY FileEntry = (PBL_FILE_ENTRY)Entry;
115 ULONG DeviceId = *(PULONG)Argument1;
116 PWCHAR FilePath = (PWCHAR)Argument2;
117 ULONG Flags = *(PULONG)Argument3;
118 ULONG Unknown = *(PULONG)Argument4;
119 BOOLEAN Found;
120
121 Found = FALSE;
122
123 if ((FileEntry->DeviceId == DeviceId) && !(_wcsicmp(FileEntry->FilePath, FilePath)) && (FileEntry->Unknown == Unknown))
124 {
125 if ((!(Flags & 1) || (FileEntry->Flags & 2)) && (!(Flags & 2) || (FileEntry->Flags & 4)))
126 {
127 if ((!(Flags & 4) || (FileEntry->Flags & 0x10000)) && ((Flags & 4) || !(FileEntry->Flags & 0x10000)))
128 {
129 Found = TRUE;
130 }
131 }
132 }
133 return Found;
134 }
135
136 BOOLEAN
137 FileTableCompareWithSameAttributes (
138 _In_ PVOID Entry,
139 _In_ PVOID Argument1,
140 _In_ PVOID Argument2,
141 _In_ PVOID Argument3,
142 _In_ PVOID Argument4
143 )
144 {
145 PBL_FILE_ENTRY FileEntry = (PBL_FILE_ENTRY)Entry;
146 ULONG DeviceId = *(PULONG)Argument1;
147 PWCHAR FilePath = (PWCHAR)Argument2;
148 ULONG Flags = *(PULONG)Argument3;
149 ULONG Unknown = *(PULONG)Argument4;
150 BOOLEAN Found;
151
152 Found = FALSE;
153
154 if ((FileEntry->DeviceId == DeviceId) && !(_wcsicmp(FileEntry->FilePath, FilePath)) && (FileEntry->Unknown == Unknown))
155 {
156 if ((!(Flags & 1) || (FileEntry->Flags & 2)) && ((Flags & 1) || !(FileEntry->Flags & 2)) && (!(Flags & 2) || (FileEntry->Flags & 4)) && ((Flags & 2) || !(FileEntry->Flags & 4)))
157 {
158 if ((!(Flags & 4) || (FileEntry->Flags & 0x10000)) && ((Flags & 4) || !(FileEntry->Flags & 0x10000)))
159 {
160 Found = TRUE;
161 }
162 }
163 }
164 return Found;
165 }
166
167 NTSTATUS
168 FileTableDestroyEntry (
169 _In_ PBL_FILE_ENTRY FileEntry,
170 _In_ ULONG Index
171 )
172 {
173 ULONG DeviceId;
174 PBL_DEVICE_ENTRY DeviceEntry;
175 NTSTATUS Status;
176
177 DeviceId = FileEntry->DeviceId;
178 if (DmTableEntries > DeviceId)
179 {
180 DeviceEntry = DmDeviceTable[DeviceId];
181 if (DeviceEntry)
182 {
183 --DeviceEntry->ReferenceCount;
184 }
185 }
186
187 Status = FileEntry->Callbacks.Close(FileEntry);
188
189 BlMmFreeHeap(FileEntry);
190
191 FileTable[Index] = NULL;
192 return Status;
193 }
194
195 NTSTATUS
196 FileTablePurgeEntry (
197 _In_ PVOID Entry
198 )
199 {
200 PBL_FILE_ENTRY FileEntry = (PBL_FILE_ENTRY)Entry;
201 NTSTATUS Status;
202
203 if (((FileEntry->Flags & 1) || (FileEntry->Flags & 0x10000)) && (FileEntries < 0x200))
204 {
205 Status = STATUS_UNSUCCESSFUL;
206 }
207 else
208 {
209 Status = FileTableDestroyEntry(FileEntry, FileEntry->FileId);
210 }
211
212 return Status;
213 }
214
215 NTSTATUS
216 BlFileClose (
217 _In_ ULONG FileId
218 )
219 {
220 PBL_FILE_ENTRY FileEntry;
221
222 if (FileEntries <= FileId)
223 {
224 return STATUS_INVALID_PARAMETER;
225 }
226
227 FileEntry = FileTable[FileId];
228 if (!FileEntry)
229 {
230 return STATUS_INVALID_PARAMETER;
231 }
232
233 if (!(FileEntry->Flags & 1))
234 {
235 return STATUS_INVALID_PARAMETER;
236 }
237
238 --FileEntry->ReferenceCount;
239 if (!FileEntry->ReferenceCount)
240 {
241 FileEntry->Flags &= ~1;
242 }
243
244 return STATUS_SUCCESS;
245 }
246
247 NTSTATUS
248 FileIoOpen (
249 _In_ ULONG DeviceId,
250 _In_ PWCHAR FileName,
251 _In_ ULONG Flags,
252 _In_ ULONG Unknown,
253 _In_ PBL_TBL_LOOKUP_ROUTINE CompareRoutine,
254 _Out_ PBL_FILE_ENTRY *ReturnFileEntry
255 )
256 {
257 PWCHAR FileNameCopy, ParentFileName;
258 NTSTATUS Status;
259 PBL_DEVICE_ENTRY DeviceEntry;
260 PBL_FILE_SYSTEM_ENTRY FileSystem;
261 ULONG FileId;
262 PBL_FILE_ENTRY ParentDirectoryEntry, FileEntry;
263 PLIST_ENTRY NextEntry, ListHead;
264
265 ParentDirectoryEntry = NULL;
266 FileNameCopy = NULL;
267 Flags |= 1;
268 ParentFileName = NULL;
269 Status = STATUS_SUCCESS;
270
271 if (DmTableEntries <= DeviceId)
272 {
273 return STATUS_ACCESS_DENIED;
274 }
275
276 DeviceEntry = DmDeviceTable[DeviceId];
277 if (!DeviceEntry)
278 {
279 return STATUS_ACCESS_DENIED;
280 }
281
282 if ((Flags & 1) && (!(DeviceEntry->Flags & 1) || !(DeviceEntry->Flags & 2)))
283 {
284 EfiPrintf(L"Access denied\r\n");
285 return STATUS_ACCESS_DENIED;
286 }
287
288 if ((Flags & 2) && (!(DeviceEntry->Flags & 1) || !(DeviceEntry->Flags & 4)))
289 {
290 EfiPrintf(L"Access denied2\r\n");
291 return STATUS_ACCESS_DENIED;
292 }
293
294 FileEntry = (PBL_FILE_ENTRY )BlTblFindEntry(FileTable,
295 FileEntries,
296 &FileId,
297 CompareRoutine,
298 &DeviceId,
299 FileName,
300 &Flags,
301 &Unknown);
302 if (FileEntry)
303 {
304 EfiPrintf(L"Entry exists: %p\n", FileEntry);
305 goto FileOpened;
306 }
307
308 if ((*FileName != OBJ_NAME_PATH_SEPARATOR) || (FileName[1]))
309 {
310 ParentFileName = FileIoCopyParentDirectoryPath(FileName);
311 if (!ParentFileName)
312 {
313 Status = STATUS_NO_MEMORY;
314 goto FileOpenEnd;
315 }
316
317 Status = FileIoOpen(DeviceId,
318 ParentFileName,
319 5,
320 Unknown,
321 FileTableCompareWithSubsetAttributes,
322 &ParentDirectoryEntry);
323 if (Status < 0)
324 {
325 goto FileOpenEnd;
326 }
327
328 FileNameCopy = FileIoCopyFileName(FileName);
329 if (!FileNameCopy)
330 {
331 Status = STATUS_NO_MEMORY;
332 goto FileOpenEnd;
333 }
334
335 Status = ParentDirectoryEntry->Callbacks.Open(ParentDirectoryEntry,
336 FileNameCopy,
337 Flags,
338 &FileEntry);
339 }
340 else
341 {
342 EfiPrintf(L"Opening root drive\r\n");
343 Status = STATUS_UNSUCCESSFUL;
344
345 ListHead = &RegisteredFileSystems;
346 NextEntry = ListHead->Flink;
347 while (NextEntry != ListHead)
348 {
349 FileSystem = CONTAINING_RECORD(NextEntry, BL_FILE_SYSTEM_ENTRY, ListEntry);
350
351 EfiPrintf(L"Calling filesystem %p mount routine: %p\r\n", FileSystem, FileSystem->MountCallback);
352 Status = FileSystem->MountCallback(DeviceId, Unknown, &FileEntry);
353 if (NT_SUCCESS(Status))
354 {
355 break;
356 }
357
358 NextEntry = NextEntry->Flink;
359 }
360
361 FileNameCopy = NULL;
362 }
363
364 if (!NT_SUCCESS(Status))
365 {
366 EfiPrintf(L"Could not open file!: %lx\r\n", Status);
367 goto FileOpenEnd;
368 }
369
370 FileEntry->Unknown = Unknown;
371
372 if (Flags & 1)
373 {
374 FileEntry->Flags |= 2u;
375 }
376
377 if (Flags & 2)
378 {
379 FileEntry->Flags |= 4u;
380 }
381
382 Status = BlTblSetEntry(&FileTable,
383 &FileEntries,
384 (PVOID)FileEntry,
385 &FileId,
386 FileTablePurgeEntry);
387 if (!NT_SUCCESS(Status))
388 {
389 FileEntry->Callbacks.Close(FileEntry);
390 goto FileOpenEnd;
391 }
392
393 ++DeviceEntry->ReferenceCount;
394 Status = STATUS_SUCCESS;
395
396 EfiPrintf(L"File %s opened with ID: %lx\r\n", FileEntry->FilePath, FileId);
397 FileEntry->FileId = FileId;
398
399 FileOpened:
400 if (++FileEntry->ReferenceCount == 1)
401 {
402 FileEntry->Unknown1 = 0;
403 FileEntry->Unknown2 = 0;
404 }
405
406 FileEntry->Flags |= 1;
407
408 if (Flags & 0x10)
409 {
410 FileEntry->Flags |= 0x10;
411 }
412
413 if (ReturnFileEntry)
414 {
415 *ReturnFileEntry = FileEntry;
416 }
417
418 FileOpenEnd:
419 if (ParentDirectoryEntry)
420 {
421 BlFileClose(ParentDirectoryEntry->FileId);
422 }
423 if (ParentFileName)
424 {
425 BlMmFreeHeap(ParentFileName);
426 }
427 if (FileNameCopy)
428 {
429 BlMmFreeHeap(FileNameCopy);
430 }
431 return Status;
432 }
433
434 NTSTATUS
435 BlFileOpen (
436 _In_ ULONG DeviceId,
437 _In_ PWCHAR FileName,
438 _In_ ULONG Flags,
439 _Out_ PULONG FileId
440 )
441 {
442 NTSTATUS Status;
443 PBL_FILE_ENTRY FileEntry;
444 BL_DEVICE_INFORMATION DeviceInformation;
445
446 if (!(FileName) ||
447 (*FileName != OBJ_NAME_PATH_SEPARATOR) ||
448 !(FileId) ||
449 !(Flags & 3))
450 {
451 EfiPrintf(L"Invalid file options\r\n");
452 return STATUS_INVALID_PARAMETER;
453 }
454
455 Status = BlDeviceGetInformation(DeviceId, &DeviceInformation);
456 if (!NT_SUCCESS(Status))
457 {
458 EfiPrintf(L"Get device info failed: %lx\r\n", Status);
459 return Status;
460 }
461
462 if ((DeviceInformation.DeviceType != DiskDevice) &&
463 (DeviceInformation.DeviceType != LegacyPartitionDevice) &&
464 (DeviceInformation.DeviceType != UdpDevice))
465 {
466 EfiPrintf(L"Invalid device type\r\n");
467 return STATUS_INVALID_PARAMETER;
468 }
469
470 Status = FileIoOpen(DeviceId,
471 FileName,
472 Flags,
473 0,
474 FileTableCompareWithSameAttributes,
475 &FileEntry);
476 if (NT_SUCCESS(Status))
477 {
478 EfiPrintf(L"File opened: %lx\r\n", FileEntry->FileId);
479 *FileId = FileEntry->FileId;
480 }
481
482 return Status;
483 }
484
485 NTSTATUS
486 BlpFileRegisterFileSystem (
487 _In_ PBL_FS_INIT_CALLBACK InitCallback,
488 _In_ PBL_FS_DESTROY_CALLBACK DestroyCallback,
489 _In_ PBL_FS_MOUNT_CALLBACK MountCallback,
490 _In_ PBL_FS_PURGE_CALLBACK PurgeCallback,
491 _In_ ULONG Flags
492 )
493 {
494 PBL_FILE_SYSTEM_ENTRY FsEntry;
495 NTSTATUS Status;
496
497 /* Allocate an entry */
498 FsEntry = BlMmAllocateHeap(sizeof(*FsEntry));
499 if (!FsEntry)
500 {
501 return STATUS_NO_MEMORY;
502 }
503
504 /* Initialize the file system */
505 Status = InitCallback();
506 if (!NT_SUCCESS(Status))
507 {
508 BlMmFreeHeap(FsEntry);
509 return Status;
510 }
511
512 /* Register the callbacks */
513 FsEntry->MountCallback = MountCallback;
514 FsEntry->DestroyCallback = DestroyCallback;
515 FsEntry->InitCallback = InitCallback;
516 FsEntry->PurgeCallback = PurgeCallback;
517
518 /* Insert in the right location in the list */
519 if (Flags & BL_FS_REGISTER_AT_HEAD_FLAG)
520 {
521 InsertHeadList(&RegisteredFileSystems, &FsEntry->ListEntry);
522 }
523 else
524 {
525 InsertTailList(&RegisteredFileSystems, &FsEntry->ListEntry);
526 }
527
528 /* Return */
529 return STATUS_SUCCESS;
530 }
531
532 NTSTATUS
533 BlpFileInitialize (
534 VOID
535 )
536 {
537 NTSTATUS Status;
538
539 /* Allocate the file table */
540 FileEntries = 16;
541 FileTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) * FileEntries);
542 if (!FileTable)
543 {
544 return STATUS_INVALID_PARAMETER;
545 }
546
547 /* Initialize it */
548 RtlZeroMemory(FileTable, sizeof(PBL_FILE_ENTRY) * FileEntries);
549 InitializeListHead(&RegisteredFileSystems);
550
551 #if 0
552 /* Initialize the network file system */
553 Status = BlpFileRegisterFileSystem(NetRegisterFunctionTable.Init,
554 NetRegisterFunctionTable.Destroy,
555 NetRegisterFunctionTable.Mount,
556 NetRegisterFunctionTable.Purge,
557 1);
558 if (NT_SUCCESS(Status))
559 {
560 /* Initialize NTFS */
561 Status = BlpFileRegisterFileSystem(NtfsRegisterFunctionTable.Init,
562 NtfsRegisterFunctionTable.Destroy,
563 NtfsRegisterFunctionTable.Mount,
564 NtfsRegisterFunctionTable.Purge,
565 0);
566 }
567
568 if (NT_SUCCESS(Status))
569 #endif
570 {
571 /* Initialize FAT */
572 Status = BlpFileRegisterFileSystem(FatRegisterFunctionTable.Init,
573 FatRegisterFunctionTable.Destroy,
574 FatRegisterFunctionTable.Mount,
575 FatRegisterFunctionTable.Purge,
576 0);
577 }
578
579 #if 0
580 if (NT_SUCCESS(Status))
581 {
582 /* Initialize EXFAT (FatPlus) */
583 Status = BlpFileRegisterFileSystem(FppRegisterFunctionTable.Init,
584 FppRegisterFunctionTable.Destroy,
585 FppRegisterFunctionTable.Mount,
586 FppRegisterFunctionTable.Purge,
587 0);
588 }
589
590 if (NT_SUCCESS(Status))
591 {
592 /* Initialize WIM */
593 Status = BlpFileRegisterFileSystem(WimRegisterFunctionTable.Init,
594 WimRegisterFunctionTable.Destroy,
595 WimRegisterFunctionTable.Mount,
596 WimRegisterFunctionTable.Purge,
597 0);
598 }
599
600 if (NT_SUCCESS(Status))
601 {
602 /* Initialize UDFS */
603 Status = BlpFileRegisterFileSystem(UdfsRegisterFunctionTable.Init,
604 UdfsRegisterFunctionTable.Destroy,
605 UdfsRegisterFunctionTable.Mount,
606 UdfsRegisterFunctionTable.Purge,
607 0);
608 }
609 #endif
610 if (NT_SUCCESS(Status))
611 {
612 /* Initialize El-Torito CDFS */
613 Status = BlpFileRegisterFileSystem(EtfsRegisterFunctionTable.Init,
614 EtfsRegisterFunctionTable.Destroy,
615 EtfsRegisterFunctionTable.Mount,
616 EtfsRegisterFunctionTable.Purge,
617 0);
618 }
619
620 /* Destroy the file manager if any of the file systems didn't initialize */
621 if (!NT_SUCCESS(Status))
622 {
623 if (FileTable)
624 {
625 //BlpFileDestroy();
626 }
627 }
628 return Status;
629 }