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