da91dc12a88650faf7afd576180ab22ab5359d25
[reactos.git] / reactos / drivers / filesystems / ext2 / src / memory.c
1 /*
2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
4 * FILE: memory.c
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
7 * UPDATE HISTORY:
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "ext2fs.h"
13
14 /* GLOBALS ***************************************************************/
15
16 extern PEXT2_GLOBAL Ext2Global;
17
18 /* DEFINITIONS *************************************************************/
19
20 #ifdef ALLOC_PRAGMA
21 #pragma alloc_text(PAGE, Ext2AllocateFcb)
22 #pragma alloc_text(PAGE, Ext2FreeFcb)
23 #pragma alloc_text(PAGE, Ext2AllocateInode)
24 #pragma alloc_text(PAGE, Ext2DestroyInode)
25 #pragma alloc_text(PAGE, Ext2CheckBitmapConsistency)
26 #pragma alloc_text(PAGE, Ext2CheckSetBlock)
27 #pragma alloc_text(PAGE, Ext2InitializeVcb)
28 #pragma alloc_text(PAGE, Ext2FreeCcb)
29 #pragma alloc_text(PAGE, Ext2AllocateCcb)
30 #pragma alloc_text(PAGE, Ext2TearDownStream)
31 #pragma alloc_text(PAGE, Ext2DestroyVcb)
32 #pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
33 #pragma alloc_text(PAGE, Ext2ReaperThread)
34 #pragma alloc_text(PAGE, Ext2StartReaperThread)
35 #endif
36
37 PEXT2_IRP_CONTEXT
38 Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject,
39 IN PIRP Irp )
40 {
41 PIO_STACK_LOCATION irpSp;
42 PEXT2_IRP_CONTEXT IrpContext;
43
44 ASSERT(DeviceObject != NULL);
45 ASSERT(Irp != NULL);
46
47 irpSp = IoGetCurrentIrpStackLocation(Irp);
48
49 IrpContext = (PEXT2_IRP_CONTEXT) (
50 ExAllocateFromNPagedLookasideList(
51 &(Ext2Global->Ext2IrpContextLookasideList)));
52
53 if (IrpContext == NULL) {
54 return NULL;
55 }
56
57 RtlZeroMemory(IrpContext, sizeof(EXT2_IRP_CONTEXT) );
58
59 IrpContext->Identifier.Type = EXT2ICX;
60 IrpContext->Identifier.Size = sizeof(EXT2_IRP_CONTEXT);
61
62 IrpContext->Irp = Irp;
63 IrpContext->MajorFunction = irpSp->MajorFunction;
64 IrpContext->MinorFunction = irpSp->MinorFunction;
65 IrpContext->DeviceObject = DeviceObject;
66 IrpContext->FileObject = irpSp->FileObject;
67 if (NULL != IrpContext->FileObject) {
68 IrpContext->Fcb = (PEXT2_FCB)IrpContext->FileObject->FsContext;
69 IrpContext->Ccb = (PEXT2_CCB)IrpContext->FileObject->FsContext2;
70 }
71
72 if (IrpContext->FileObject != NULL) {
73 IrpContext->RealDevice = IrpContext->FileObject->DeviceObject;
74 } else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) {
75 if (irpSp->Parameters.MountVolume.Vpb) {
76 IrpContext->RealDevice = irpSp->Parameters.MountVolume.Vpb->RealDevice;
77 }
78 }
79
80 if (IsFlagOn(irpSp->Flags, SL_WRITE_THROUGH)) {
81 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
82 }
83
84 if (IsFlagOn(irpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME)) {
85 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ);
86 }
87
88 if (IrpContext->MajorFunction == IRP_MJ_CLEANUP ||
89 IrpContext->MajorFunction == IRP_MJ_CLOSE ||
90 IrpContext->MajorFunction == IRP_MJ_SHUTDOWN ||
91 IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
92 IrpContext->MajorFunction == IRP_MJ_PNP ) {
93
94 if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
95 IrpContext->MajorFunction == IRP_MJ_PNP) {
96 if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL ||
97 IoIsOperationSynchronous(Irp)) {
98 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
99 }
100 } else {
101 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
102 }
103
104 } else if (IoIsOperationSynchronous(Irp)) {
105
106 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
107 }
108
109 IrpContext->IsTopLevel = (IoGetTopLevelIrp() == Irp);
110 IrpContext->ExceptionInProgress = FALSE;
111 INC_IRP_COUNT(IrpContext);
112
113 return IrpContext;
114 }
115
116 VOID
117 Ext2FreeIrpContext (IN PEXT2_IRP_CONTEXT IrpContext)
118 {
119 ASSERT(IrpContext != NULL);
120
121 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
122 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
123
124 /* free the IrpContext to NonPagedList */
125 IrpContext->Identifier.Type = 0;
126 IrpContext->Identifier.Size = 0;
127
128 DEC_IRP_COUNT(IrpContext);
129 ExFreeToNPagedLookasideList(&(Ext2Global->Ext2IrpContextLookasideList), IrpContext);
130 }
131
132
133 PEXT2_FCB
134 Ext2AllocateFcb (
135 IN PEXT2_VCB Vcb,
136 IN PEXT2_MCB Mcb
137 )
138 {
139 PEXT2_FCB Fcb;
140
141 Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
142 &(Ext2Global->Ext2FcbLookasideList));
143
144 if (!Fcb) {
145 return NULL;
146 }
147
148 RtlZeroMemory(Fcb, sizeof(EXT2_FCB));
149 Fcb->Identifier.Type = EXT2FCB;
150 Fcb->Identifier.Size = sizeof(EXT2_FCB);
151
152 #ifndef _WIN2K_TARGET_
153 ExInitializeFastMutex(&Fcb->Mutex);
154 FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->Mutex);
155 #endif
156
157 FsRtlInitializeOplock(&Fcb->Oplock);
158 FsRtlInitializeFileLock (
159 &Fcb->FileLockAnchor,
160 NULL,
161 NULL );
162
163 Fcb->OpenHandleCount = 0;
164 Fcb->ReferenceCount = 0;
165 Fcb->Vcb = Vcb;
166 Fcb->Inode = &Mcb->Inode;
167
168 ASSERT(Mcb->Fcb == NULL);
169 Ext2ReferMcb(Mcb);
170 Fcb->Mcb = Mcb;
171 Mcb->Fcb = Fcb;
172
173 DEBUG(DL_RES, ("Ext2AllocateFcb: Fcb %p created: %wZ.\n",
174 Fcb, &Fcb->Mcb->FullName));
175
176 RtlZeroMemory(&Fcb->Header, sizeof(FSRTL_COMMON_FCB_HEADER));
177 Fcb->Header.NodeTypeCode = (USHORT) EXT2FCB;
178 Fcb->Header.NodeByteSize = sizeof(EXT2_FCB);
179 Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
180 Fcb->Header.Resource = &(Fcb->MainResource);
181 Fcb->Header.PagingIoResource = &(Fcb->PagingIoResource);
182
183 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
184 Fcb->Header.ValidDataLength.QuadPart = Mcb->Inode.i_size;
185 Fcb->Header.AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
186 Fcb->Header.FileSize.QuadPart, (ULONGLONG)Vcb->BlockSize);
187
188 Fcb->SectionObject.DataSectionObject = NULL;
189 Fcb->SectionObject.SharedCacheMap = NULL;
190 Fcb->SectionObject.ImageSectionObject = NULL;
191
192 ExInitializeResourceLite(&(Fcb->MainResource));
193 ExInitializeResourceLite(&(Fcb->PagingIoResource));
194
195 Ext2InsertFcb(Vcb, Fcb);
196
197 INC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
198
199 return Fcb;
200 }
201
202 VOID
203 Ext2FreeFcb (IN PEXT2_FCB Fcb)
204 {
205 PEXT2_VCB Vcb = Fcb->Vcb;
206
207 ASSERT((Fcb != NULL) && (Fcb->Identifier.Type == EXT2FCB) &&
208 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
209 ASSERT((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
210 (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB)));
211
212 #ifndef _WIN2K_TARGET_
213 FsRtlTeardownPerStreamContexts(&Fcb->Header);
214 #endif
215
216 if ((Fcb->Mcb->Identifier.Type == EXT2MCB) &&
217 (Fcb->Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
218
219 ASSERT (Fcb->Mcb->Fcb == Fcb);
220 if (IsMcbSpecialFile(Fcb->Mcb) || IsFileDeleted(Fcb->Mcb)) {
221
222 ASSERT(!IsRoot(Fcb));
223 Ext2RemoveMcb(Fcb->Vcb, Fcb->Mcb);
224 Fcb->Mcb->Fcb = NULL;
225
226 Ext2UnlinkMcb(Vcb, Fcb->Mcb);
227 Ext2DerefMcb(Fcb->Mcb);
228 Ext2LinkHeadMcb(Vcb, Fcb->Mcb);
229
230 } else {
231
232 Fcb->Mcb->Fcb = NULL;
233 Ext2DerefMcb(Fcb->Mcb);
234 }
235
236 } else {
237 DbgBreak();
238 }
239
240 Ext2RemoveFcb(Fcb->Vcb, Fcb);
241
242 FsRtlUninitializeFileLock(&Fcb->FileLockAnchor);
243 FsRtlUninitializeOplock(&Fcb->Oplock);
244 ExDeleteResourceLite(&Fcb->MainResource);
245 ExDeleteResourceLite(&Fcb->PagingIoResource);
246
247 DEBUG(DL_RES, ( "Ext2FreeFcb: Fcb (%p) is being released: %wZ.\n",
248 Fcb, &Fcb->Mcb->FullName));
249
250 Fcb->Identifier.Type = 0;
251 Fcb->Identifier.Size = 0;
252
253 ExFreeToNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList), Fcb);
254 DEC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
255 }
256
257 /* Insert Fcb to Vcb->FcbList queue */
258
259 VOID
260 Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
261 {
262 ExInterlockedInsertTailList(&Vcb->FcbList, &Fcb->Next, &Vcb->FcbLock);
263 Ext2ReferXcb(&Vcb->FcbCount);
264 }
265
266 /* Remove Fcb from Vcb->FcbList queue */
267
268 VOID
269 Ext2RemoveFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
270 {
271 KIRQL irql;
272
273 KeAcquireSpinLock(&Vcb->FcbLock, &irql);
274 RemoveEntryList(&(Fcb->Next));
275 if (Vcb->FcbCount > 0) {
276 Ext2DerefXcb(&Vcb->FcbCount);
277 } else {
278 DbgBreak();
279 }
280 KeReleaseSpinLock(&Vcb->FcbLock, irql);
281 }
282
283 PEXT2_CCB
284 Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink)
285 {
286 PEXT2_CCB Ccb;
287
288 Ccb = (PEXT2_CCB) (ExAllocateFromNPagedLookasideList(
289 &(Ext2Global->Ext2CcbLookasideList)));
290 if (!Ccb) {
291 return NULL;
292 }
293
294 DEBUG(DL_RES, ( "ExtAllocateCcb: Ccb created: %ph.\n", Ccb));
295
296 RtlZeroMemory(Ccb, sizeof(EXT2_CCB));
297
298 Ccb->Identifier.Type = EXT2CCB;
299 Ccb->Identifier.Size = sizeof(EXT2_CCB);
300 Ccb->Flags = Flags;
301
302 Ccb->SymLink = SymLink;
303 if (SymLink) {
304 ASSERT(SymLink->Refercount > 0);
305 Ext2ReferMcb(SymLink);
306 DEBUG(DL_INF, ( "ExtAllocateCcb: Ccb SymLink: %wZ.\n",
307 &Ccb->SymLink->FullName));
308 }
309
310 Ccb->DirectorySearchPattern.Length = 0;
311 Ccb->DirectorySearchPattern.MaximumLength = 0;
312 Ccb->DirectorySearchPattern.Buffer = 0;
313
314 INC_MEM_COUNT(PS_CCB, Ccb, sizeof(EXT2_CCB));
315
316 return Ccb;
317 }
318
319 VOID
320 Ext2FreeCcb (IN PEXT2_VCB Vcb, IN PEXT2_CCB Ccb)
321 {
322 ASSERT(Ccb != NULL);
323
324 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
325 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
326
327 DEBUG(DL_RES, ( "Ext2FreeCcb: Ccb = %ph.\n", Ccb));
328
329 if (Ccb->SymLink) {
330 DEBUG(DL_INF, ( "Ext2FreeCcb: Ccb SymLink: %wZ.\n",
331 &Ccb->SymLink->FullName));
332 if (IsFileDeleted(Ccb->SymLink->Target)) {
333 Ext2UnlinkMcb(Vcb, Ccb->SymLink);
334 Ext2DerefMcb(Ccb->SymLink);
335 Ext2LinkHeadMcb(Vcb, Ccb->SymLink);
336 } else {
337 Ext2DerefMcb(Ccb->SymLink);
338 }
339 }
340
341 if (Ccb->DirectorySearchPattern.Buffer != NULL) {
342 DEC_MEM_COUNT(PS_DIR_PATTERN, Ccb->DirectorySearchPattern.Buffer,
343 Ccb->DirectorySearchPattern.MaximumLength );
344 Ext2FreePool(Ccb->DirectorySearchPattern.Buffer, EXT2_DIRSP_MAGIC);
345 }
346
347 ExFreeToNPagedLookasideList(&(Ext2Global->Ext2CcbLookasideList), Ccb);
348 DEC_MEM_COUNT(PS_CCB, Ccb, sizeof(EXT2_CCB));
349 }
350
351 PEXT2_INODE
352 Ext2AllocateInode (PEXT2_VCB Vcb)
353 {
354 PVOID inode = NULL;
355
356 inode = ExAllocateFromNPagedLookasideList(
357 &(Vcb->InodeLookasideList));
358 if (!inode) {
359 return NULL;
360 }
361
362 RtlZeroMemory(inode, INODE_SIZE);
363
364 DEBUG(DL_INF, ("ExtAllocateInode: Inode created: %ph.\n", inode));
365 INC_MEM_COUNT(PS_EXT2_INODE, inode, INODE_SIZE);
366
367 return inode;
368 }
369
370 VOID
371 Ext2DestroyInode (IN PEXT2_VCB Vcb, IN PEXT2_INODE inode)
372 {
373 ASSERT(inode != NULL);
374
375 DEBUG(DL_INF, ("Ext2FreeInode: Inode = %ph.\n", inode));
376
377 ExFreeToNPagedLookasideList(&(Vcb->InodeLookasideList), inode);
378 DEC_MEM_COUNT(PS_EXT2_INODE, inode, INODE_SIZE);
379 }
380
381 struct dentry * Ext2AllocateEntry()
382 {
383 struct dentry *de;
384
385 de = (struct dentry *)ExAllocateFromNPagedLookasideList(
386 &(Ext2Global->Ext2DentryLookasideList));
387 if (!de) {
388 return NULL;
389 }
390
391 RtlZeroMemory(de, sizeof(struct dentry));
392 INC_MEM_COUNT(PS_DENTRY, de, sizeof(struct dentry));
393
394 return de;
395 }
396
397 VOID Ext2FreeEntry (IN struct dentry *de)
398 {
399 ASSERT(de != NULL);
400
401 if (de->d_name.name)
402 ExFreePool(de->d_name.name);
403
404 ExFreeToNPagedLookasideList(&(Ext2Global->Ext2DentryLookasideList), de);
405 DEC_MEM_COUNT(PS_DENTRY, de, sizeof(struct dentry));
406 }
407
408
409 struct dentry *Ext2BuildEntry(PEXT2_VCB Vcb, PEXT2_MCB Dcb, PUNICODE_STRING FileName)
410 {
411 OEM_STRING Oem = { 0 };
412 struct dentry *de = NULL;
413 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
414
415 _SEH2_TRY {
416
417 de = Ext2AllocateEntry();
418 if (!de) {
419 DEBUG(DL_ERR, ("Ext2BuildEntry: failed to allocate dentry.\n"));
420 _SEH2_LEAVE;
421 }
422 de->d_sb = &Vcb->sb;
423 if (Dcb)
424 de->d_parent = Dcb->de;
425
426 Oem.MaximumLength = (USHORT)Ext2UnicodeToOEMSize(Vcb, FileName) + 1;
427 Oem.Buffer = ExAllocatePool(PagedPool, Oem.MaximumLength);
428 if (!Oem.Buffer) {
429 DEBUG(DL_ERR, ( "Ex2BuildEntry: failed to allocate OEM name.\n"));
430 _SEH2_LEAVE;
431 }
432 de->d_name.name = Oem.Buffer;
433 RtlZeroMemory(Oem.Buffer, Oem.MaximumLength);
434 Status = Ext2UnicodeToOEM(Vcb, &Oem, FileName);
435 if (!NT_SUCCESS(Status)) {
436 DEBUG(DL_CP, ("Ext2BuildEntry: failed to convert %S to OEM.\n", FileName->Buffer));
437 _SEH2_LEAVE;
438 }
439 de->d_name.len = Oem.Length;
440
441 } _SEH2_FINALLY {
442
443 if (!NT_SUCCESS(Status)) {
444 if (de)
445 Ext2FreeEntry(de);
446 }
447 } _SEH2_END;
448
449 return de;
450 }
451
452 PEXT2_EXTENT
453 Ext2AllocateExtent ()
454 {
455 PEXT2_EXTENT Extent;
456
457 Extent = (PEXT2_EXTENT)ExAllocateFromNPagedLookasideList(
458 &(Ext2Global->Ext2ExtLookasideList));
459 if (!Extent) {
460 return NULL;
461 }
462
463 RtlZeroMemory(Extent, sizeof(EXT2_EXTENT));
464 INC_MEM_COUNT(PS_EXTENT, Extent, sizeof(EXT2_EXTENT));
465
466 return Extent;
467 }
468
469 VOID
470 Ext2FreeExtent (IN PEXT2_EXTENT Extent)
471 {
472 ASSERT(Extent != NULL);
473 ExFreeToNPagedLookasideList(&(Ext2Global->Ext2ExtLookasideList), Extent);
474 DEC_MEM_COUNT(PS_EXTENT, Extent, sizeof(EXT2_EXTENT));
475 }
476
477 ULONG
478 Ext2CountExtents(IN PEXT2_EXTENT Chain)
479 {
480 ULONG count = 0;
481 PEXT2_EXTENT List = Chain;
482
483 while (List) {
484 count += 1;
485 List = List->Next;
486 }
487
488 return count;
489 }
490
491 VOID
492 Ext2JointExtents(
493 IN PEXT2_EXTENT Chain,
494 IN PEXT2_EXTENT Extent
495 )
496 {
497 #ifndef __REACTOS__
498 ULONG count = 0;
499 #endif
500 PEXT2_EXTENT List = Chain;
501
502 while (List->Next) {
503 List = List->Next;
504 }
505
506 List->Next = Extent;
507 }
508
509
510 VOID
511 Ext2DestroyExtentChain(IN PEXT2_EXTENT Chain)
512 {
513 PEXT2_EXTENT Extent = NULL, List = Chain;
514
515 while (List) {
516 Extent = List->Next;
517 Ext2FreeExtent(List);
518 List = Extent;
519 }
520 }
521
522 BOOLEAN
523 Ext2ListExtents(PLARGE_MCB Extents)
524 {
525 if (FsRtlNumberOfRunsInLargeMcb(Extents) != 0) {
526
527 LONGLONG DirtyVba;
528 LONGLONG DirtyLba;
529 LONGLONG DirtyLength;
530 int i, n = 0;
531
532 for (i = 0; FsRtlGetNextLargeMcbEntry(
533 Extents, i, &DirtyVba,
534 &DirtyLba, &DirtyLength); i++) {
535 if (DirtyVba > 0 && DirtyLba != -1) {
536 DEBUG(DL_EXT, ("Vba:%I64xh Lba:%I64xh Len:%I64xh.\n", DirtyVba, DirtyLba, DirtyLength));
537 n++;
538 }
539 }
540
541 return n ? TRUE : FALSE;
542 }
543
544 return FALSE;
545 }
546
547 VOID
548 Ext2CheckExtent(
549 PLARGE_MCB Zone,
550 LONGLONG Vbn,
551 LONGLONG Lbn,
552 LONGLONG Length,
553 BOOLEAN bAdded
554 )
555 {
556 #if EXT2_DEBUG
557 LONGLONG DirtyLbn;
558 LONGLONG DirtyLen;
559 LONGLONG RunStart;
560 LONGLONG RunLength;
561 ULONG Index;
562 BOOLEAN bFound = FALSE;
563
564 bFound = FsRtlLookupLargeMcbEntry(
565 Zone,
566 Vbn,
567 &DirtyLbn,
568 &DirtyLen,
569 &RunStart,
570 &RunLength,
571 &Index );
572
573 if (!bAdded && (!bFound || DirtyLbn == -1)) {
574 return;
575 }
576
577 if ( !bFound || (DirtyLbn == -1) ||
578 (DirtyLbn != Lbn) ||
579 (DirtyLen < Length)) {
580
581 DbgBreak();
582
583 for (Index = 0; TRUE; Index++) {
584
585 if (!FsRtlGetNextLargeMcbEntry(
586 Zone,
587 Index,
588 &Vbn,
589 &Lbn,
590 &Length)) {
591 break;
592 }
593
594 DEBUG(DL_EXT, ("Index = %xh Vbn = %I64xh Lbn = %I64xh Len = %I64xh\n",
595 Index, Vbn, Lbn, Length ));
596 }
597 }
598 #endif
599 }
600
601 VOID
602 Ext2ClearAllExtents(PLARGE_MCB Zone)
603 {
604 _SEH2_TRY {
605 FsRtlTruncateLargeMcb(Zone, (LONGLONG)0);
606 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
607 DbgBreak();
608 } _SEH2_END;
609 }
610
611
612 BOOLEAN
613 Ext2AddVcbExtent (
614 IN PEXT2_VCB Vcb,
615 IN LONGLONG Vbn,
616 IN LONGLONG Length
617 )
618 {
619 ULONG TriedTimes = 0;
620
621 LONGLONG Offset = 0;
622 BOOLEAN rc = FALSE;
623
624 Offset = Vbn & (~(Vcb->IoUnitSize - 1));
625 Length = (Vbn - Offset + Length + Vcb->IoUnitSize - 1) &
626 ~(Vcb->IoUnitSize - 1);
627
628 ASSERT ((Offset & (Vcb->IoUnitSize - 1)) == 0);
629 ASSERT ((Length & (Vcb->IoUnitSize - 1)) == 0);
630
631 Offset = (Offset >> Vcb->IoUnitBits) + 1;
632 Length = (Length >> Vcb->IoUnitBits);
633
634 Again:
635
636 _SEH2_TRY {
637 rc = FsRtlAddLargeMcbEntry(
638 &Vcb->Extents,
639 Offset,
640 Offset,
641 Length
642 );
643 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
644 DbgBreak();
645 rc = FALSE;
646 } _SEH2_END;
647
648 if (!rc && ++TriedTimes < 10) {
649 Ext2Sleep(TriedTimes * 100);
650 goto Again;
651 }
652
653 DEBUG(DL_EXT, ("Ext2AddVcbExtent: Vbn=%I64xh Length=%I64xh,"
654 " rc=%d Runs=%u\n", Offset, Length, rc,
655 FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
656
657 if (rc) {
658 Ext2CheckExtent(&Vcb->Extents, Offset, Offset, Length, TRUE);
659 }
660
661 return rc;
662 }
663
664 BOOLEAN
665 Ext2RemoveVcbExtent (
666 IN PEXT2_VCB Vcb,
667 IN LONGLONG Vbn,
668 IN LONGLONG Length
669 )
670 {
671 ULONG TriedTimes = 0;
672 LONGLONG Offset = 0;
673 BOOLEAN rc = TRUE;
674
675 Offset = Vbn & (~(Vcb->IoUnitSize - 1));
676 Length = (Length + Vbn - Offset + Vcb->IoUnitSize - 1) & (~(Vcb->IoUnitSize - 1));
677
678 ASSERT ((Offset & (Vcb->IoUnitSize - 1)) == 0);
679 ASSERT ((Length & (Vcb->IoUnitSize - 1)) == 0);
680
681 Offset = (Offset >> Vcb->IoUnitBits) + 1;
682 Length = (Length >> Vcb->IoUnitBits);
683
684 Again:
685
686 _SEH2_TRY {
687 FsRtlRemoveLargeMcbEntry(
688 &Vcb->Extents,
689 Offset,
690 Length
691 );
692 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
693 DbgBreak();
694 rc = FALSE;
695 } _SEH2_END;
696
697 if (!rc && ++TriedTimes < 10) {
698 Ext2Sleep(TriedTimes * 100);
699 goto Again;
700 }
701
702 DEBUG(DL_EXT, ("Ext2RemoveVcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
703 Offset, Length, FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
704 if (rc) {
705 Ext2CheckExtent(&Vcb->Extents, Offset, 0, Length, FALSE);
706 }
707
708 return rc;
709 }
710
711 BOOLEAN
712 Ext2LookupVcbExtent (
713 IN PEXT2_VCB Vcb,
714 IN LONGLONG Vbn,
715 OUT PLONGLONG Lbn,
716 OUT PLONGLONG Length
717 )
718 {
719 LONGLONG offset;
720 BOOLEAN rc;
721
722 offset = Vbn & (~(Vcb->IoUnitSize - 1));
723 ASSERT ((offset & (Vcb->IoUnitSize - 1)) == 0);
724 offset = (offset >> Vcb->IoUnitBits) + 1;
725
726 rc = FsRtlLookupLargeMcbEntry(
727 &(Vcb->Extents),
728 offset,
729 Lbn,
730 Length,
731 NULL,
732 NULL,
733 NULL
734 );
735
736 if (rc) {
737
738 if (Lbn && ((*Lbn) != -1)) {
739 ASSERT((*Lbn) > 0);
740 (*Lbn) = (((*Lbn) - 1) << Vcb->IoUnitBits);
741 (*Lbn) += ((Vbn) & (Vcb->IoUnitSize - 1));
742 }
743
744 if (Length && *Length) {
745 (*Length) <<= Vcb->IoUnitBits;
746 (*Length) -= ((Vbn) & (Vcb->IoUnitSize - 1));
747 }
748 }
749
750 return rc;
751 }
752
753
754 BOOLEAN
755 Ext2AddMcbExtent (
756 IN PEXT2_VCB Vcb,
757 IN PEXT2_MCB Mcb,
758 IN LONGLONG Vbn,
759 IN LONGLONG Lbn,
760 IN LONGLONG Length
761 )
762 {
763 ULONG TriedTimes = 0;
764 LONGLONG Base = 0;
765 UCHAR Bits = 0;
766 BOOLEAN rc = FALSE;
767
768 Base = (LONGLONG)BLOCK_SIZE;
769 Bits = (UCHAR)BLOCK_BITS;
770
771 ASSERT ((Vbn & (Base - 1)) == 0);
772 ASSERT ((Lbn & (Base - 1)) == 0);
773 ASSERT ((Length & (Base - 1)) == 0);
774
775 Vbn = (Vbn >> Bits) + 1;
776 Lbn = (Lbn >> Bits) + 1;
777 Length = (Length >> Bits);
778
779 Again:
780
781 _SEH2_TRY {
782
783 rc = FsRtlAddLargeMcbEntry(
784 &Mcb->Extents,
785 Vbn,
786 Lbn,
787 Length
788 );
789
790 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
791
792 DbgBreak();
793 rc = FALSE;
794 } _SEH2_END;
795
796 if (!rc && ++TriedTimes < 10) {
797 Ext2Sleep(TriedTimes * 100);
798 goto Again;
799 }
800
801 DEBUG(DL_EXT, ("Ext2AddMcbExtent: Vbn=%I64xh Lbn=%I64xh Length=%I64xh,"
802 " rc=%d Runs=%u\n", Vbn, Lbn, Length, rc,
803 FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)));
804
805 if (rc) {
806 Ext2CheckExtent(&Mcb->Extents, Vbn, Lbn, Length, TRUE);
807 }
808
809 return rc;
810 }
811
812 BOOLEAN
813 Ext2RemoveMcbExtent (
814 IN PEXT2_VCB Vcb,
815 IN PEXT2_MCB Mcb,
816 IN LONGLONG Vbn,
817 IN LONGLONG Length
818 )
819 {
820 ULONG TriedTimes = 0;
821 LONGLONG Base = 0;
822 UCHAR Bits = 0;
823 BOOLEAN rc = TRUE;
824
825 Base = (LONGLONG)BLOCK_SIZE;
826 Bits = (UCHAR)BLOCK_BITS;
827
828 ASSERT ((Vbn & (Base - 1)) == 0);
829 ASSERT ((Length & (Base - 1)) == 0);
830
831 Vbn = (Vbn >> Bits) + 1;
832 Length = (Length >> Bits);
833
834 Again:
835
836 _SEH2_TRY {
837 FsRtlRemoveLargeMcbEntry(
838 &Mcb->Extents,
839 Vbn,
840 Length
841 );
842 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
843 DbgBreak();
844 rc = FALSE;
845 } _SEH2_END;
846
847 if (!rc && ++TriedTimes < 10) {
848 Ext2Sleep(TriedTimes * 100);
849 goto Again;
850 }
851
852 DEBUG(DL_EXT, ("Ext2RemoveMcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
853 Vbn, Length, FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)));
854 if (rc) {
855 Ext2CheckExtent(&Mcb->Extents, Vbn, 0, Length, FALSE);
856 }
857
858 return rc;
859 }
860
861 BOOLEAN
862 Ext2LookupMcbExtent (
863 IN PEXT2_VCB Vcb,
864 IN PEXT2_MCB Mcb,
865 IN LONGLONG Vbn,
866 OUT PLONGLONG Lbn,
867 OUT PLONGLONG Length
868 )
869 {
870 LONGLONG offset;
871 BOOLEAN rc;
872
873 offset = Vbn & (~((LONGLONG)BLOCK_SIZE - 1));
874 ASSERT ((offset & (BLOCK_SIZE - 1)) == 0);
875 offset = (offset >> BLOCK_BITS) + 1;
876
877 rc = FsRtlLookupLargeMcbEntry(
878 &(Mcb->Extents),
879 offset,
880 Lbn,
881 Length,
882 NULL,
883 NULL,
884 NULL
885 );
886
887 if (rc) {
888
889 if (Lbn && ((*Lbn) != -1)) {
890 ASSERT((*Lbn) > 0);
891 (*Lbn) = (((*Lbn) - 1) << BLOCK_BITS);
892 (*Lbn) += ((Vbn) & ((LONGLONG)BLOCK_SIZE - 1));
893 }
894
895 if (Length && *Length) {
896 (*Length) <<= BLOCK_BITS;
897 (*Length) -= ((Vbn) & ((LONGLONG)BLOCK_SIZE - 1));
898 }
899 }
900
901 return rc;
902 }
903
904
905 BOOLEAN
906 Ext2AddMcbMetaExts (
907 IN PEXT2_VCB Vcb,
908 IN PEXT2_MCB Mcb,
909 IN ULONG Block,
910 IN ULONG Length
911 )
912 {
913 ULONG TriedTimes = 0;
914 LONGLONG Lbn = Block + 1;
915 BOOLEAN rc = TRUE;
916
917 Again:
918
919 _SEH2_TRY {
920
921 rc = FsRtlAddLargeMcbEntry(
922 &Mcb->MetaExts,
923 Lbn,
924 Lbn,
925 Length
926 );
927
928 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
929
930 DbgBreak();
931 rc = FALSE;
932 } _SEH2_END;
933
934 if (!rc && ++TriedTimes < 10) {
935 Ext2Sleep(TriedTimes * 100);
936 goto Again;
937 }
938
939 DEBUG(DL_EXT, ("Ext2AddMcbMetaExts: Block: %xh-%xh rc=%d Runs=%u\n", Block,
940 Length, rc, FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)));
941
942 if (rc) {
943 Ext2CheckExtent(&Mcb->MetaExts, Lbn, Lbn, Length, TRUE);
944 }
945
946 return rc;
947 }
948
949 BOOLEAN
950 Ext2RemoveMcbMetaExts (
951 IN PEXT2_VCB Vcb,
952 IN PEXT2_MCB Mcb,
953 IN ULONG Block,
954 IN ULONG Length
955 )
956 {
957 ULONG TriedTimes = 0;
958 LONGLONG Lbn = Block + 1;
959 BOOLEAN rc = TRUE;
960
961 Again:
962
963 _SEH2_TRY {
964
965 FsRtlRemoveLargeMcbEntry(
966 &Mcb->MetaExts,
967 Lbn,
968 Length
969 );
970
971 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
972 DbgBreak();
973 rc = FALSE;
974 } _SEH2_END;
975
976 if (!rc && ++TriedTimes < 10) {
977 Ext2Sleep(TriedTimes * 100);
978 goto Again;
979 }
980
981 DEBUG(DL_EXT, ("Ext2RemoveMcbMetaExts: Block: %xh-%xhh Runs=%u\n", Block,
982 Length, FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)));
983 if (rc) {
984 Ext2CheckExtent(&Mcb->MetaExts, Lbn, 0, Length, FALSE);
985 }
986
987 return rc;
988 }
989
990
991 BOOLEAN
992 Ext2AddBlockExtent(
993 IN PEXT2_VCB Vcb,
994 IN PEXT2_MCB Mcb,
995 IN ULONG Start,
996 IN ULONG Block,
997 IN ULONG Number
998 )
999 {
1000 LONGLONG Vbn = 0;
1001 LONGLONG Lbn = 0;
1002 LONGLONG Length = 0;
1003
1004 Vbn = ((LONGLONG) Start) << BLOCK_BITS;
1005 Lbn = ((LONGLONG) Block) << BLOCK_BITS;
1006 Length = ((LONGLONG)Number << BLOCK_BITS);
1007
1008 if (Mcb) {
1009 #if EXT2_DEBUG
1010 ULONG _block = 0, _mapped = 0;
1011 BOOLEAN _rc = Ext2LookupBlockExtent(Vcb, Mcb, Start, &_block, &_mapped);
1012 if (_rc && _block != 0 && (_block != Block)) {
1013 DbgBreak();
1014 }
1015 #endif
1016 return Ext2AddMcbExtent(Vcb, Mcb, Vbn, Lbn, Length);
1017
1018 }
1019
1020 ASSERT(Start == Block);
1021 return Ext2AddVcbExtent(Vcb, Vbn, Length);
1022 }
1023
1024
1025 BOOLEAN
1026 Ext2LookupBlockExtent(
1027 IN PEXT2_VCB Vcb,
1028 IN PEXT2_MCB Mcb,
1029 IN ULONG Start,
1030 IN PULONG Block,
1031 IN PULONG Mapped
1032 )
1033 {
1034 LONGLONG Vbn = 0;
1035 LONGLONG Lbn = 0;
1036 LONGLONG Length = 0;
1037
1038 BOOLEAN rc = FALSE;
1039
1040 Vbn = ((LONGLONG) Start) << BLOCK_BITS;
1041
1042 if (Mcb) {
1043 rc = Ext2LookupMcbExtent(Vcb, Mcb, Vbn, &Lbn, &Length);
1044 } else {
1045 rc = Ext2LookupVcbExtent(Vcb, Vbn, &Lbn, &Length);
1046 }
1047
1048 if (rc) {
1049 *Mapped = (ULONG)(Length >> BLOCK_BITS);
1050 if (Lbn != -1 && Length > 0) {
1051 *Block = (ULONG)(Lbn >> BLOCK_BITS);
1052 } else {
1053 *Block = 0;
1054 }
1055 }
1056
1057 return rc;
1058 }
1059
1060
1061 BOOLEAN
1062 Ext2RemoveBlockExtent(
1063 IN PEXT2_VCB Vcb,
1064 IN PEXT2_MCB Mcb,
1065 IN ULONG Start,
1066 IN ULONG Number
1067 )
1068 {
1069 LONGLONG Vbn = 0;
1070 LONGLONG Length = 0;
1071 BOOLEAN rc;
1072
1073 Vbn = ((LONGLONG) Start) << BLOCK_BITS;
1074 Length = ((LONGLONG)Number << BLOCK_BITS);
1075
1076 if (Mcb) {
1077 rc = Ext2RemoveMcbExtent(Vcb, Mcb, Vbn, Length);
1078 } else {
1079 rc = Ext2RemoveVcbExtent(Vcb, Vbn, Length);
1080 }
1081
1082 return rc;
1083 }
1084
1085 NTSTATUS
1086 Ext2InitializeZone(
1087 IN PEXT2_IRP_CONTEXT IrpContext,
1088 IN PEXT2_VCB Vcb,
1089 IN PEXT2_MCB Mcb
1090 )
1091 {
1092 NTSTATUS Status = STATUS_SUCCESS;
1093
1094 ULONG Start = 0;
1095 ULONG End;
1096 ULONG Block;
1097 ULONG Mapped;
1098
1099 Ext2ClearAllExtents(&Mcb->Extents);
1100 Ext2ClearAllExtents(&Mcb->MetaExts);
1101
1102 ASSERT(Mcb != NULL);
1103 End = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
1104
1105 while (Start < End) {
1106
1107 Block = Mapped = 0;
1108
1109 /* mapping file offset to ext2 block */
1110 if (INODE_HAS_EXTENT(&Mcb->Inode)) {
1111 Status = Ext2MapExtent(
1112 IrpContext,
1113 Vcb,
1114 Mcb,
1115 Start,
1116 FALSE,
1117 &Block,
1118 &Mapped
1119 );
1120 } else {
1121 Status = Ext2MapIndirect(
1122 IrpContext,
1123 Vcb,
1124 Mcb,
1125 Start,
1126 FALSE,
1127 &Block,
1128 &Mapped
1129 );
1130 }
1131
1132 if (!NT_SUCCESS(Status)) {
1133 goto errorout;
1134 }
1135
1136 /* skip wrong blocks, in case wrongly treating symlink
1137 target names as blocks, silly */
1138 if (Block >= TOTAL_BLOCKS) {
1139 Block = 0;
1140 }
1141
1142 if (Block) {
1143 if (!Ext2AddBlockExtent(Vcb, Mcb, Start, Block, Mapped)) {
1144 DbgBreak();
1145 ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
1146 Ext2ClearAllExtents(&Mcb->Extents);
1147 Status = STATUS_INSUFFICIENT_RESOURCES;
1148 goto errorout;
1149 }
1150 DEBUG(DL_MAP, ("Ext2InitializeZone %wZ: Block = %xh Mapped = %xh\n",
1151 &Mcb->FullName, Block, Mapped));
1152 }
1153
1154 /* Mapped is total number of continous blocks or NULL blocks */
1155 Start += Mapped;
1156 }
1157
1158 /* set mcb zone as initialized */
1159 SetLongFlag(Mcb->Flags, MCB_ZONE_INITED);
1160
1161 errorout:
1162
1163 if (!IsZoneInited(Mcb)) {
1164 Ext2ClearAllExtents(&Mcb->Extents);
1165 Ext2ClearAllExtents(&Mcb->MetaExts);
1166 }
1167
1168 return Status;
1169 }
1170
1171 NTSTATUS
1172 Ext2BuildExtents(
1173 IN PEXT2_IRP_CONTEXT IrpContext,
1174 IN PEXT2_VCB Vcb,
1175 IN PEXT2_MCB Mcb,
1176 IN ULONGLONG Offset,
1177 IN ULONG Size,
1178 IN BOOLEAN bAlloc,
1179 OUT PEXT2_EXTENT * Chain
1180 )
1181 {
1182 ULONG Start, End;
1183 ULONG Total = 0;
1184
1185 LONGLONG Lba = 0;
1186 NTSTATUS Status = STATUS_SUCCESS;
1187
1188 PEXT2_EXTENT Extent = NULL;
1189 PEXT2_EXTENT List = *Chain = NULL;
1190
1191 if (!IsZoneInited(Mcb)) {
1192 Status = Ext2InitializeZone(IrpContext, Vcb, Mcb);
1193 if (!NT_SUCCESS(Status)) {
1194 DbgBreak();
1195 }
1196 }
1197
1198 if ((IrpContext && IrpContext->Irp) &&
1199 ((IrpContext->Irp->Flags & IRP_NOCACHE) ||
1200 (IrpContext->Irp->Flags & IRP_PAGING_IO))) {
1201 Size = (Size + SECTOR_SIZE - 1) & (~(SECTOR_SIZE - 1));
1202 }
1203
1204 Start = (ULONG)(Offset >> BLOCK_BITS);
1205 End = (ULONG)((Size + Offset + BLOCK_SIZE - 1) >> BLOCK_BITS);
1206
1207 if (End > (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS) ) {
1208 End = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
1209 }
1210
1211 while (Size > 0 && Start < End) {
1212
1213 ULONG Mapped = 0;
1214 ULONG Length = 0;
1215 ULONG Block = 0;
1216
1217 BOOLEAN rc = FALSE;
1218
1219 /* try to map file offset to ext2 block upon Extents cache */
1220 if (IsZoneInited(Mcb)) {
1221 rc = Ext2LookupBlockExtent(
1222 Vcb,
1223 Mcb,
1224 Start,
1225 &Block,
1226 &Mapped);
1227
1228 if (!rc) {
1229 /* we likely get a sparse file here */
1230 Mapped = 1;
1231 Block = 0;
1232 }
1233 }
1234
1235 /* try to BlockMap in case failed to access Extents cache */
1236 if (!IsZoneInited(Mcb) || (bAlloc && Block == 0)) {
1237
1238 Status = Ext2BlockMap(
1239 IrpContext,
1240 Vcb,
1241 Mcb,
1242 Start,
1243 bAlloc,
1244 &Block,
1245 &Mapped
1246 );
1247 if (!NT_SUCCESS(Status)) {
1248 break;
1249 }
1250
1251 /* skip wrong blocks, in case wrongly treating symlink
1252 target names as blocks, silly */
1253 if (Block >= TOTAL_BLOCKS) {
1254 Block = 0;
1255 }
1256
1257 /* add new allocated blocks to Mcb zone */
1258 if (IsZoneInited(Mcb) && Block) {
1259 if (!Ext2AddBlockExtent(Vcb, Mcb, Start, Block, Mapped)) {
1260 DbgBreak();
1261 ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
1262 Ext2ClearAllExtents(&Mcb->Extents);
1263 }
1264 }
1265 }
1266
1267 /* calculate i/o extent */
1268 Lba = ((LONGLONG)Block << BLOCK_BITS) + Offset - ((LONGLONG)Start << BLOCK_BITS);
1269 Length = (ULONG)(((LONGLONG)(Start + Mapped) << BLOCK_BITS) - Offset);
1270 if (Length > Size) {
1271 Length = Size;
1272 }
1273
1274 if (0 == Length) {
1275 DbgBreak();
1276 break;
1277 }
1278
1279 Start += Mapped;
1280 Offset = (ULONGLONG)Start << BLOCK_BITS;
1281
1282 if (Block != 0) {
1283
1284 if (List && List->Lba + List->Length == Lba) {
1285
1286 /* it's continuous upon previous Extent */
1287 List->Length += Length;
1288
1289 } else {
1290
1291 /* have to allocate a new Extent */
1292 Extent = Ext2AllocateExtent();
1293 if (!Extent) {
1294 Status = STATUS_INSUFFICIENT_RESOURCES;
1295 DbgBreak();
1296 break;
1297 }
1298
1299 Extent->Lba = Lba;
1300 Extent->Length = Length;
1301 Extent->Offset = Total;
1302
1303 /* insert new Extent to chain */
1304 if (List) {
1305 List->Next = Extent;
1306 List = Extent;
1307 } else {
1308 *Chain = List = Extent;
1309 }
1310 }
1311 } else {
1312 if (bAlloc) {
1313 DbgBreak();
1314 }
1315 }
1316
1317 Total += Length;
1318 Size -= Length;
1319 }
1320
1321 return Status;
1322 }
1323
1324
1325 BOOLEAN
1326 Ext2BuildName(
1327 IN OUT PUNICODE_STRING Target,
1328 IN PUNICODE_STRING File,
1329 IN PUNICODE_STRING Parent
1330 )
1331 {
1332 USHORT Length = 0;
1333 USHORT ParentLen = 0;
1334 BOOLEAN bBackslash = TRUE;
1335
1336 /* free the original buffer */
1337 if (Target->Buffer) {
1338 DEC_MEM_COUNT(PS_MCB_NAME, Target->Buffer, Target->MaximumLength);
1339 Ext2FreePool(Target->Buffer, EXT2_FNAME_MAGIC);
1340 Target->Length = Target->MaximumLength = 0;
1341 }
1342
1343 /* check the parent directory's name and backslash */
1344 if (Parent && Parent->Buffer && Parent->Length > 0) {
1345 ParentLen = Parent->Length / sizeof(WCHAR);
1346 if (Parent->Buffer[ParentLen - 1] == L'\\') {
1347 bBackslash = FALSE;
1348 }
1349 }
1350
1351 if (Parent == NULL || File->Buffer[0] == L'\\') {
1352 /* must be root inode */
1353 ASSERT(ParentLen == 0);
1354 bBackslash = FALSE;
1355 }
1356
1357 /* allocate and initialize new name buffer */
1358 Length = File->Length;
1359 Length += (ParentLen + (bBackslash ? 1 : 0)) * sizeof(WCHAR);
1360
1361 Target->Buffer = Ext2AllocatePool(
1362 PagedPool,
1363 Length + 2,
1364 EXT2_FNAME_MAGIC
1365 );
1366
1367 if (!Target->Buffer) {
1368 DEBUG(DL_ERR, ( "Ex2BuildName: failed to allocate name bufer.\n"));
1369 return FALSE;
1370 }
1371 RtlZeroMemory(Target->Buffer, Length + 2);
1372
1373 if (ParentLen) {
1374 RtlCopyMemory(&Target->Buffer[0],
1375 Parent->Buffer,
1376 ParentLen * sizeof(WCHAR));
1377 }
1378
1379 if (bBackslash) {
1380 Target->Buffer[ParentLen++] = L'\\';
1381 }
1382
1383 RtlCopyMemory( &Target->Buffer[ParentLen],
1384 File->Buffer,
1385 File->Length);
1386
1387 INC_MEM_COUNT(PS_MCB_NAME, Target->Buffer, Length + 2);
1388 Target->Length = Length;
1389 Target->MaximumLength = Length + 2;
1390
1391 return TRUE;
1392 }
1393
1394 PEXT2_MCB
1395 Ext2AllocateMcb (
1396 IN PEXT2_VCB Vcb,
1397 IN PUNICODE_STRING FileName,
1398 IN PUNICODE_STRING Parent,
1399 IN ULONG FileAttr
1400 )
1401 {
1402 PEXT2_MCB Mcb = NULL;
1403 NTSTATUS Status = STATUS_SUCCESS;
1404
1405 /* need wake the reaper thread if there are many Mcb allocated */
1406 if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 4)) {
1407 KeSetEvent(&Ext2Global->Reaper.Wait, 0, FALSE);
1408 }
1409
1410 /* allocate Mcb from LookasideList */
1411 Mcb = (PEXT2_MCB) (ExAllocateFromNPagedLookasideList(
1412 &(Ext2Global->Ext2McbLookasideList)));
1413
1414 if (Mcb == NULL) {
1415 return NULL;
1416 }
1417
1418 /* initialize Mcb header */
1419 RtlZeroMemory(Mcb, sizeof(EXT2_MCB));
1420 Mcb->Identifier.Type = EXT2MCB;
1421 Mcb->Identifier.Size = sizeof(EXT2_MCB);
1422 Mcb->FileAttr = FileAttr;
1423
1424 Mcb->Inode.i_priv = (PVOID)Mcb;
1425 Mcb->Inode.i_sb = &Vcb->sb;
1426
1427 /* initialize Mcb names */
1428 if (FileName) {
1429
1430 #if EXT2_DEBUG
1431 if ( FileName->Length == 2 &&
1432 FileName->Buffer[0] == L'\\') {
1433 DEBUG(DL_RES, ( "Ext2AllocateMcb: Root Mcb is to be created !\n"));
1434 }
1435
1436 if ( FileName->Length == 2 &&
1437 FileName->Buffer[0] == L'.') {
1438 DbgBreak();
1439 }
1440
1441 if ( FileName->Length == 4 &&
1442 FileName->Buffer[0] == L'.' &&
1443 FileName->Buffer[1] == L'.' ) {
1444 DbgBreak();
1445 }
1446 #endif
1447
1448 if (( FileName->Length >= 4 && FileName->Buffer[0] == L'.') &&
1449 ((FileName->Length == 4 && FileName->Buffer[1] != L'.') ||
1450 FileName->Length >= 6 )) {
1451 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_HIDDEN);
1452 }
1453
1454 if (!Ext2BuildName(&Mcb->ShortName, FileName, NULL)) {
1455 goto errorout;
1456 }
1457 if (!Ext2BuildName(&Mcb->FullName, FileName, Parent)) {
1458 goto errorout;
1459 }
1460 }
1461
1462 /* initialize Mcb Extents, it will raise an expcetion if failed */
1463 _SEH2_TRY {
1464 FsRtlInitializeLargeMcb(&(Mcb->Extents), NonPagedPool);
1465 FsRtlInitializeLargeMcb(&(Mcb->MetaExts), NonPagedPool);
1466 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
1467 Status = STATUS_INSUFFICIENT_RESOURCES;
1468 DbgBreak();
1469 } _SEH2_END;
1470
1471 if (!NT_SUCCESS(Status)) {
1472 goto errorout;
1473 }
1474
1475 INC_MEM_COUNT(PS_MCB, Mcb, sizeof(EXT2_MCB));
1476 DEBUG(DL_INF, ( "Ext2AllocateMcb: Mcb %wZ created.\n", &Mcb->FullName));
1477
1478 return Mcb;
1479
1480 errorout:
1481
1482 if (Mcb) {
1483
1484 if (Mcb->ShortName.Buffer) {
1485 DEC_MEM_COUNT(PS_MCB_NAME, Mcb->ShortName.Buffer,
1486 Mcb->ShortName.MaximumLength);
1487 Ext2FreePool(Mcb->ShortName.Buffer, EXT2_FNAME_MAGIC);
1488 }
1489
1490 if (Mcb->FullName.Buffer) {
1491 DEC_MEM_COUNT(PS_MCB_NAME, Mcb->FullName.Buffer,
1492 Mcb->FullName.MaximumLength);
1493 Ext2FreePool(Mcb->FullName.Buffer, EXT2_FNAME_MAGIC);
1494 }
1495
1496 ExFreeToNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList), Mcb);
1497 }
1498
1499 return NULL;
1500 }
1501
1502 VOID
1503 Ext2FreeMcb (IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb)
1504 {
1505 #ifndef __REACTOS__
1506 PEXT2_MCB Parent = Mcb->Parent;
1507 #endif
1508 ASSERT(Mcb != NULL);
1509
1510 ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
1511 (Mcb->Identifier.Size == sizeof(EXT2_MCB)));
1512
1513 if ((Mcb->Identifier.Type != EXT2MCB) ||
1514 (Mcb->Identifier.Size != sizeof(EXT2_MCB))) {
1515 return;
1516 }
1517
1518 DEBUG(DL_INF, ( "Ext2FreeMcb: Mcb %wZ will be freed.\n", &Mcb->FullName));
1519
1520 if (IsMcbSymLink(Mcb) && Mcb->Target) {
1521 Ext2DerefMcb(Mcb->Target);
1522 }
1523
1524 if (FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)) {
1525 DEBUG(DL_EXT, ("List data extents for: %wZ\n", &Mcb->FullName));
1526 Ext2ListExtents(&Mcb->Extents);
1527 }
1528 FsRtlUninitializeLargeMcb(&(Mcb->Extents));
1529 if (FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)) {
1530 DEBUG(DL_EXT, ("List meta extents for: %wZ\n", &Mcb->FullName));
1531 Ext2ListExtents(&Mcb->MetaExts);
1532 }
1533 FsRtlUninitializeLargeMcb(&(Mcb->MetaExts));
1534 ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED);
1535
1536 if (Mcb->ShortName.Buffer) {
1537 DEC_MEM_COUNT(PS_MCB_NAME, Mcb->ShortName.Buffer,
1538 Mcb->ShortName.MaximumLength);
1539 Ext2FreePool(Mcb->ShortName.Buffer, EXT2_FNAME_MAGIC);
1540 }
1541
1542 if (Mcb->FullName.Buffer) {
1543 DEC_MEM_COUNT(PS_MCB_NAME, Mcb->FullName.Buffer,
1544 Mcb->FullName.MaximumLength);
1545 Ext2FreePool(Mcb->FullName.Buffer, EXT2_FNAME_MAGIC);
1546 }
1547
1548 /* free dentry */
1549 if (Mcb->de) {
1550 Ext2FreeEntry(Mcb->de);
1551 }
1552
1553 Mcb->Identifier.Type = 0;
1554 Mcb->Identifier.Size = 0;
1555
1556 ExFreeToNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList), Mcb);
1557 DEC_MEM_COUNT(PS_MCB, Mcb, sizeof(EXT2_MCB));
1558 }
1559
1560
1561 PEXT2_MCB
1562 Ext2SearchMcb(
1563 PEXT2_VCB Vcb,
1564 PEXT2_MCB Parent,
1565 PUNICODE_STRING FileName
1566 )
1567 {
1568 BOOLEAN LockAcquired = FALSE;
1569 PEXT2_MCB Mcb = NULL;
1570
1571 _SEH2_TRY {
1572 ExAcquireResourceSharedLite(&Vcb->McbLock, TRUE);
1573 LockAcquired = TRUE;
1574 Mcb = Ext2SearchMcbWithoutLock(Parent, FileName);
1575 } _SEH2_FINALLY {
1576 if (LockAcquired) {
1577 ExReleaseResourceLite(&Vcb->McbLock);
1578 }
1579 } _SEH2_END;
1580
1581 return Mcb;
1582 }
1583
1584
1585 PEXT2_MCB
1586 Ext2SearchMcbWithoutLock(
1587 PEXT2_MCB Parent,
1588 PUNICODE_STRING FileName
1589 )
1590 {
1591 PEXT2_MCB TmpMcb = NULL;
1592
1593 DEBUG(DL_RES, ("Ext2SearchMcb: %wZ\n", FileName));
1594
1595 _SEH2_TRY {
1596
1597 Ext2ReferMcb(Parent);
1598
1599 if (Ext2IsDot(FileName)) {
1600 TmpMcb = Parent;
1601 Ext2ReferMcb(Parent);
1602 _SEH2_LEAVE;
1603 }
1604
1605 if (Ext2IsDotDot(FileName)) {
1606 if (IsMcbRoot(Parent)) {
1607 TmpMcb = Parent;
1608 } else {
1609 TmpMcb = Parent->Parent;
1610 }
1611 if (TmpMcb) {
1612 Ext2ReferMcb(TmpMcb);
1613 }
1614 _SEH2_LEAVE;
1615 }
1616
1617 if (IsMcbSymLink(Parent)) {
1618 if (Parent->Target) {
1619 TmpMcb = Parent->Target->Child;
1620 ASSERT(!IsMcbSymLink(Parent->Target));
1621 } else {
1622 TmpMcb = NULL;
1623 _SEH2_LEAVE;
1624 }
1625 } else {
1626 TmpMcb = Parent->Child;
1627 }
1628
1629 while (TmpMcb) {
1630
1631 if (!RtlCompareUnicodeString(
1632 &(TmpMcb->ShortName),
1633 FileName, TRUE )) {
1634 Ext2ReferMcb(TmpMcb);
1635 break;
1636 }
1637
1638 TmpMcb = TmpMcb->Next;
1639 }
1640
1641 } _SEH2_FINALLY {
1642
1643 Ext2DerefMcb(Parent);
1644 } _SEH2_END;
1645
1646 return TmpMcb;
1647 }
1648
1649 VOID
1650 Ext2InsertMcb (
1651 PEXT2_VCB Vcb,
1652 PEXT2_MCB Parent,
1653 PEXT2_MCB Child
1654 )
1655 {
1656 BOOLEAN LockAcquired = FALSE;
1657 PEXT2_MCB Mcb = NULL;
1658
1659 _SEH2_TRY {
1660
1661 ExAcquireResourceExclusiveLite(
1662 &Vcb->McbLock,
1663 TRUE );
1664 LockAcquired = TRUE;
1665
1666 /* use it's target if it's a symlink */
1667 if (IsMcbSymLink(Parent)) {
1668 Parent = Parent->Target;
1669 ASSERT(!IsMcbSymLink(Parent));
1670 }
1671
1672 Mcb = Parent->Child;
1673 while (Mcb) {
1674 if (Mcb == Child) {
1675 break;
1676 }
1677 Mcb = Mcb->Next;
1678 }
1679
1680 if (Mcb) {
1681 /* already attached in the list */
1682 DEBUG(DL_ERR, ( "Ext2InsertMcb: Child Mcb is alreay attached.\n"));
1683 if (!IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
1684 SetLongFlag(Child->Flags, MCB_ENTRY_TREE);
1685 DEBUG(DL_ERR, ( "Ext2InsertMcb: Child Mcb's flag isn't set.\n"));
1686 }
1687
1688 DbgBreak();
1689
1690 } else {
1691
1692 /* insert this Mcb into the head */
1693 Child->Next = Parent->Child;
1694 Parent->Child = Child;
1695 Child->Parent = Parent;
1696 Child->de->d_parent = Parent->de;
1697 Ext2ReferMcb(Parent);
1698 SetLongFlag(Child->Flags, MCB_ENTRY_TREE);
1699 }
1700
1701 } _SEH2_FINALLY {
1702
1703 if (LockAcquired) {
1704 ExReleaseResourceLite(&Vcb->McbLock);
1705 }
1706 } _SEH2_END;
1707 }
1708
1709 BOOLEAN
1710 Ext2RemoveMcb (
1711 PEXT2_VCB Vcb,
1712 PEXT2_MCB Mcb
1713 )
1714 {
1715 PEXT2_MCB TmpMcb = NULL;
1716 BOOLEAN LockAcquired = FALSE;
1717 BOOLEAN bLinked = FALSE;
1718
1719 _SEH2_TRY {
1720
1721 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
1722 LockAcquired = TRUE;
1723
1724 if (Mcb->Parent) {
1725
1726 if (Mcb->Parent->Child == Mcb) {
1727 Mcb->Parent->Child = Mcb->Next;
1728 bLinked = TRUE;
1729 } else {
1730 TmpMcb = Mcb->Parent->Child;
1731
1732 while (TmpMcb && TmpMcb->Next != Mcb) {
1733 TmpMcb = TmpMcb->Next;
1734 }
1735
1736 if (TmpMcb) {
1737 TmpMcb->Next = Mcb->Next;
1738 bLinked = TRUE;
1739 } else {
1740 /* we got errors: link broken */
1741 }
1742 }
1743
1744 if (bLinked) {
1745 if (IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
1746 DEBUG(DL_RES, ("Mcb %p %wZ removed from Mcb %p %wZ\n", Mcb,
1747 &Mcb->FullName, Mcb->Parent, &Mcb->Parent->FullName));
1748 Ext2DerefMcb(Mcb->Parent);
1749 ClearLongFlag(Mcb->Flags, MCB_ENTRY_TREE);
1750 } else {
1751 DbgBreak();
1752 }
1753 } else {
1754 if (IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
1755 ClearLongFlag(Mcb->Flags, MCB_ENTRY_TREE);
1756 }
1757 DbgBreak();
1758 }
1759 Mcb->Parent = NULL;
1760 Mcb->de->d_parent = NULL;
1761 }
1762
1763 } _SEH2_FINALLY {
1764
1765 if (LockAcquired) {
1766 ExReleaseResourceLite(&Vcb->McbLock);
1767 }
1768 } _SEH2_END;
1769
1770 return TRUE;
1771 }
1772
1773 VOID
1774 Ext2CleanupAllMcbs(PEXT2_VCB Vcb)
1775 {
1776 BOOLEAN LockAcquired = FALSE;
1777 PEXT2_MCB Mcb = NULL;
1778
1779 _SEH2_TRY {
1780
1781 ExAcquireResourceExclusiveLite(
1782 &Vcb->McbLock,
1783 TRUE );
1784 LockAcquired = TRUE;
1785
1786 while ((Mcb = Ext2FirstUnusedMcb(Vcb, TRUE, Vcb->NumOfMcb)) != 0) {
1787 while (Mcb) {
1788 PEXT2_MCB Next = Mcb->Next;
1789 if (IsMcbSymLink(Mcb)) {
1790 Mcb->Target = NULL;
1791 }
1792 Ext2FreeMcb(Vcb, Mcb);
1793 Mcb = Next;
1794 }
1795 }
1796 Ext2FreeMcb(Vcb, Vcb->McbTree);
1797 Vcb->McbTree = NULL;
1798
1799 } _SEH2_FINALLY {
1800
1801 if (LockAcquired) {
1802 ExReleaseResourceLite(&Vcb->McbLock);
1803 }
1804 } _SEH2_END;
1805 }
1806
1807 BOOLEAN
1808 Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
1809 {
1810 PEXT2_GROUP_DESC gd;
1811 struct buffer_head *gb = NULL;
1812 struct buffer_head *bh = NULL;
1813 ULONG group, dwBlk, Length;
1814 RTL_BITMAP bitmap;
1815 BOOLEAN bModified = FALSE;
1816
1817 group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
1818 dwBlk = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
1819
1820 gd = ext4_get_group_desc(&Vcb->sb, group, &gb);
1821 if (!gd) {
1822 return FALSE;
1823 }
1824 bh = sb_getblk(&Vcb->sb, ext4_block_bitmap(&Vcb->sb, gd));
1825
1826 if (group == Vcb->sbi.s_groups_count - 1) {
1827 Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
1828
1829 /* s_blocks_count is integer multiple of s_blocks_per_group */
1830 if (Length == 0)
1831 Length = BLOCKS_PER_GROUP;
1832 } else {
1833 Length = BLOCKS_PER_GROUP;
1834 }
1835
1836 if (dwBlk >= Length) {
1837 fini_bh(&gb);
1838 fini_bh(&bh);
1839 return FALSE;
1840 }
1841
1842 RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
1843
1844 if (RtlCheckBit(&bitmap, dwBlk) == 0) {
1845 DbgBreak();
1846 RtlSetBits(&bitmap, dwBlk, 1);
1847 bModified = TRUE;
1848 mark_buffer_dirty(bh);
1849 }
1850
1851 fini_bh(&gb);
1852 fini_bh(&bh);
1853
1854 return (!bModified);
1855 }
1856
1857 BOOLEAN
1858 Ext2CheckBitmapConsistency(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
1859 {
1860 ULONG i, j, InodeBlocks;
1861
1862 for (i = 0; i < Vcb->sbi.s_groups_count; i++) {
1863
1864 PEXT2_GROUP_DESC gd;
1865 struct buffer_head *bh = NULL;
1866
1867 gd = ext4_get_group_desc(&Vcb->sb, i, &bh);
1868 if (!gd)
1869 continue;
1870 Ext2CheckSetBlock(IrpContext, Vcb, ext4_block_bitmap(&Vcb->sb, gd));
1871 Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_bitmap(&Vcb->sb, gd));
1872
1873
1874 if (i == Vcb->sbi.s_groups_count - 1) {
1875 InodeBlocks = ((INODES_COUNT % INODES_PER_GROUP) *
1876 Vcb->InodeSize + Vcb->BlockSize - 1) /
1877 (Vcb->BlockSize);
1878 } else {
1879 InodeBlocks = (INODES_PER_GROUP * Vcb->InodeSize +
1880 Vcb->BlockSize - 1) / (Vcb->BlockSize);
1881 }
1882
1883 for (j = 0; j < InodeBlocks; j++ )
1884 Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_table(&Vcb->sb, gd) + j);
1885
1886 fini_bh(&bh);
1887 }
1888
1889 return TRUE;
1890 }
1891
1892 /* Ext2Global->Resource should be already acquired */
1893 VOID
1894 Ext2InsertVcb(PEXT2_VCB Vcb)
1895 {
1896 InsertTailList(&(Ext2Global->VcbList), &Vcb->Next);
1897 }
1898
1899
1900 /* Ext2Global->Resource should be already acquired */
1901 VOID
1902 Ext2RemoveVcb(PEXT2_VCB Vcb)
1903 {
1904 RemoveEntryList(&Vcb->Next);
1905 InitializeListHead(&Vcb->Next);
1906 }
1907
1908 NTSTATUS
1909 Ext2QueryVolumeParams(IN PEXT2_VCB Vcb, IN PUNICODE_STRING Params)
1910 {
1911 NTSTATUS Status;
1912 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1913
1914 UNICODE_STRING UniName;
1915 PUSHORT UniBuffer = NULL;
1916
1917 USHORT UUID[50];
1918
1919 int i;
1920 int len = 0;
1921
1922 /* zero params */
1923 RtlZeroMemory(Params, sizeof(UNICODE_STRING));
1924
1925 /* constructing volume UUID name */
1926 memset(UUID, 0, sizeof(USHORT) * 50);
1927 for (i=0; i < 16; i++) {
1928 if (i == 0) {
1929 swprintf((wchar_t *)&UUID[len], L"{%2.2X",Vcb->SuperBlock->s_uuid[i]);
1930 len += 3;
1931 } else if (i == 15) {
1932 swprintf((wchar_t *)&UUID[len], L"-%2.2X}", Vcb->SuperBlock->s_uuid[i]);
1933 len +=4;
1934 } else {
1935 swprintf((wchar_t *)&UUID[len], L"-%2.2X", Vcb->SuperBlock->s_uuid[i]);
1936 len += 3;
1937 }
1938 }
1939
1940 /* allocating memory for UniBuffer */
1941 UniBuffer = Ext2AllocatePool(PagedPool, 1024, EXT2_PARAM_MAGIC);
1942 if (NULL == UniBuffer) {
1943 Status = STATUS_INSUFFICIENT_RESOURCES;
1944 goto errorout;
1945 }
1946 RtlZeroMemory(UniBuffer, 1024);
1947
1948 /* querying volume parameter string */
1949 RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
1950 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
1951 QueryTable[0].Name = UUID;
1952 QueryTable[0].EntryContext = &(UniName);
1953 UniName.MaximumLength = 1024;
1954 UniName.Length = 0;
1955 UniName.Buffer = UniBuffer;
1956
1957 Status = RtlQueryRegistryValues(
1958 RTL_REGISTRY_ABSOLUTE,
1959 Ext2Global->RegistryPath.Buffer,
1960 &QueryTable[0],
1961 NULL,
1962 NULL
1963 );
1964
1965 if (!NT_SUCCESS(Status)) {
1966 goto errorout;
1967 }
1968
1969 errorout:
1970
1971 if (NT_SUCCESS(Status)) {
1972 *Params = UniName;
1973 } else {
1974 if (UniBuffer) {
1975 Ext2FreePool(UniBuffer, EXT2_PARAM_MAGIC);
1976 }
1977 }
1978
1979 return Status;
1980 }
1981
1982 VOID
1983 Ext2ParseRegistryVolumeParams(
1984 IN PUNICODE_STRING Params,
1985 OUT PEXT2_VOLUME_PROPERTY2 Property
1986 )
1987 {
1988 WCHAR Codepage[CODEPAGE_MAXLEN];
1989 WCHAR Prefix[HIDINGPAT_LEN];
1990 WCHAR Suffix[HIDINGPAT_LEN];
1991 USHORT MountPoint[4];
1992 UCHAR DrvLetter[4];
1993
1994 BOOLEAN bWriteSupport = FALSE,
1995 bCheckBitmap = FALSE,
1996 bCodeName = FALSE,
1997 bMountPoint = FALSE;
1998 struct {
1999 PWCHAR Name; /* parameters name */
2000 PBOOLEAN bExist; /* is it contained in params */
2001 USHORT Length; /* parameter value length */
2002 PWCHAR uValue; /* value buffer in unicode */
2003 PCHAR aValue; /* value buffer in ansi */
2004 } ParamPattern[] = {
2005 /* writing support */
2006 {READING_ONLY, &Property->bReadonly, 0, NULL, NULL},
2007 {WRITING_SUPPORT, &bWriteSupport, 0, NULL, NULL},
2008 {EXT3_FORCEWRITING, &Property->bExt3Writable, 0, NULL, NULL},
2009
2010 /* need check bitmap */
2011 {CHECKING_BITMAP, &bCheckBitmap, 0, NULL, NULL},
2012 /* codepage */
2013 {CODEPAGE_NAME, &bCodeName, CODEPAGE_MAXLEN,
2014 &Codepage[0], Property->Codepage},
2015 /* filter prefix and suffix */
2016 {HIDING_PREFIX, &Property->bHidingPrefix, HIDINGPAT_LEN,
2017 &Prefix[0], Property->sHidingPrefix},
2018 {HIDING_SUFFIX, &Property->bHidingSuffix, HIDINGPAT_LEN,
2019 &Suffix[0], Property->sHidingSuffix},
2020 {MOUNT_POINT, &bMountPoint, 4,
2021 &MountPoint[0], &DrvLetter[0]},
2022
2023 /* end */
2024 {NULL, NULL, 0, NULL}
2025 };
2026
2027 USHORT i, j, k;
2028
2029 RtlZeroMemory(Codepage, CODEPAGE_MAXLEN);
2030 RtlZeroMemory(Prefix, HIDINGPAT_LEN);
2031 RtlZeroMemory(Suffix, HIDINGPAT_LEN);
2032 RtlZeroMemory(MountPoint, sizeof(USHORT) * 4);
2033 RtlZeroMemory(DrvLetter, sizeof(CHAR) * 4);
2034
2035 RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY2));
2036 Property->Magic = EXT2_VOLUME_PROPERTY_MAGIC;
2037 Property->Command = APP_CMD_SET_PROPERTY2;
2038
2039 for (i=0; ParamPattern[i].Name != NULL; i++) {
2040
2041 UNICODE_STRING Name1=*Params, Name2;
2042 RtlInitUnicodeString(&Name2, ParamPattern[i].Name);
2043 *ParamPattern[i].bExist = FALSE;
2044
2045 for (j=0; j * sizeof(WCHAR) + Name2.Length <= Params->Length ; j++) {
2046
2047 Name1.MaximumLength = Params->Length - j * sizeof(WCHAR);
2048 Name1.Length = Name2.Length;
2049 Name1.Buffer = &Params->Buffer[j];
2050
2051 if (!RtlCompareUnicodeString(&Name1, &Name2, TRUE)) {
2052 if (j * sizeof(WCHAR) + Name2.Length == Params->Length ||
2053 Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L';' ||
2054 Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L',' ) {
2055 *(ParamPattern[i].bExist) = TRUE;
2056 } else if ((j * 2 + Name2.Length < Params->Length + 2) ||
2057 (Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L'=' )) {
2058 j += Name2.Length/sizeof(WCHAR) + 1;
2059 k = 0;
2060 while ( j + k < Params->Length/2 &&
2061 k < ParamPattern[i].Length &&
2062 Params->Buffer[j+k] != L';' &&
2063 Params->Buffer[j+k] != L',' ) {
2064 #ifdef __REACTOS__
2065 ParamPattern[i].uValue[k] = Params->Buffer[j + k];
2066 k++;
2067 #else
2068 ParamPattern[i].uValue[k] = Params->Buffer[j + k++];
2069 #endif
2070 }
2071 if (k) {
2072 NTSTATUS status;
2073 ANSI_STRING AnsiName;
2074 AnsiName.Length = 0;
2075 AnsiName.MaximumLength =ParamPattern[i].Length;
2076 AnsiName.Buffer = ParamPattern[i].aValue;
2077
2078 Name2.Buffer = ParamPattern[i].uValue;
2079 Name2.MaximumLength = Name2.Length = k * sizeof(WCHAR);
2080 status = RtlUnicodeStringToAnsiString(
2081 &AnsiName, &Name2, FALSE);
2082 if (NT_SUCCESS(status)) {
2083 *(ParamPattern[i].bExist) = TRUE;
2084 } else {
2085 *ParamPattern[i].bExist = FALSE;
2086 }
2087 }
2088 }
2089 break;
2090 }
2091 }
2092 }
2093
2094 if (bMountPoint) {
2095 Property->DrvLetter = DrvLetter[0];
2096 Property->DrvLetter |= 0x80;
2097 }
2098 }
2099
2100 NTSTATUS
2101 Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
2102 {
2103 NTSTATUS Status;
2104 UNICODE_STRING VolumeParams;
2105
2106 Status = Ext2QueryVolumeParams(Vcb, &VolumeParams);
2107 if (NT_SUCCESS(Status)) {
2108
2109 /* set Vcb settings from registery */
2110 EXT2_VOLUME_PROPERTY2 Property;
2111 Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
2112 Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
2113
2114 } else {
2115
2116 /* don't support auto mount */
2117 if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) {
2118 Status = STATUS_SUCCESS;
2119 } else {
2120 Status = STATUS_UNSUCCESSFUL;
2121 goto errorout;
2122 }
2123
2124 /* set Vcb settings from Ext2Global */
2125 if (IsFlagOn(Ext2Global->Flags, EXT2_SUPPORT_WRITING)) {
2126 if (Vcb->IsExt3fs) {
2127 if (IsFlagOn(Ext2Global->Flags, EXT3_FORCE_WRITING)) {
2128 ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
2129 } else {
2130 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2131 }
2132 } else {
2133 ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
2134 }
2135 } else {
2136 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2137 }
2138
2139 /* set the default codepage */
2140 Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
2141 memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
2142 Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
2143
2144 if ((Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) != 0) {
2145 RtlCopyMemory( Vcb->sHidingPrefix,
2146 Ext2Global->sHidingPrefix,
2147 HIDINGPAT_LEN);
2148 } else {
2149 RtlZeroMemory( Vcb->sHidingPrefix,
2150 HIDINGPAT_LEN);
2151 }
2152
2153 if ((Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) != 0) {
2154 RtlCopyMemory( Vcb->sHidingSuffix,
2155 Ext2Global->sHidingSuffix,
2156 HIDINGPAT_LEN);
2157 } else {
2158 RtlZeroMemory( Vcb->sHidingSuffix,
2159 HIDINGPAT_LEN);
2160 }
2161 }
2162
2163 errorout:
2164
2165 if (VolumeParams.Buffer) {
2166 Ext2FreePool(VolumeParams.Buffer, EXT2_PARAM_MAGIC);
2167 }
2168
2169 return Status;
2170 }
2171
2172 NTSTATUS
2173 Ext2InitializeLabel(
2174 IN PEXT2_VCB Vcb,
2175 IN PEXT2_SUPER_BLOCK Sb
2176 )
2177 {
2178 NTSTATUS status;
2179
2180 USHORT Length;
2181 UNICODE_STRING Label;
2182 OEM_STRING OemName;
2183
2184 Label.MaximumLength = 16 * sizeof(WCHAR);
2185 Label.Length = 0;
2186 Label.Buffer = Vcb->Vpb->VolumeLabel;
2187 Vcb->Vpb->VolumeLabelLength = 0;
2188 RtlZeroMemory(Label.Buffer, Label.MaximumLength);
2189
2190 Length = 16;
2191 while ( (Length > 0) &&
2192 ((Sb->s_volume_name[Length -1] == 0x00) ||
2193 (Sb->s_volume_name[Length - 1] == 0x20) )
2194 ) {
2195 Length--;
2196 }
2197
2198 if (Length == 0) {
2199 return STATUS_SUCCESS;
2200 }
2201
2202 OemName.Buffer = Sb->s_volume_name;
2203 OemName.MaximumLength = 16;
2204 OemName.Length = Length;
2205
2206 status = Ext2OEMToUnicode(Vcb, &Label, &OemName);
2207 if (NT_SUCCESS(status)) {
2208 Vcb->Vpb->VolumeLabelLength = Label.Length;
2209 }
2210
2211 return status;
2212 }
2213
2214 static __inline BOOLEAN Ext2IsNullUuid (__u8 * uuid)
2215 {
2216 int i;
2217 for (i = 0; i < 16; i++) {
2218 if (uuid[i]) {
2219 break;
2220 }
2221 }
2222
2223 return (i >= 16);
2224 }
2225
2226 #define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
2227
2228 NTSTATUS
2229 Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
2230 IN PEXT2_VCB Vcb,
2231 IN PEXT2_SUPER_BLOCK sb,
2232 IN PDEVICE_OBJECT TargetDevice,
2233 IN PDEVICE_OBJECT VolumeDevice,
2234 IN PVPB Vpb )
2235 {
2236 NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
2237 ULONG IoctlSize;
2238 LONGLONG DiskSize;
2239 LONGLONG PartSize;
2240 UNICODE_STRING RootNode;
2241 USHORT Buffer[2];
2242 ULONG ChangeCount = 0, features;
2243 CC_FILE_SIZES FileSizes;
2244 int i, has_huge_files;
2245
2246 BOOLEAN VcbResourceInitialized = FALSE;
2247 BOOLEAN NotifySyncInitialized = FALSE;
2248 BOOLEAN ExtentsInitialized = FALSE;
2249 BOOLEAN InodeLookasideInitialized = FALSE;
2250
2251 _SEH2_TRY {
2252
2253 if (Vpb == NULL) {
2254 Status = STATUS_DEVICE_NOT_READY;
2255 _SEH2_LEAVE;
2256 }
2257
2258 /* checking in/compat features */
2259 if (IsFlagOn(sb->s_feature_compat, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
2260 Vcb->IsExt3fs = TRUE;
2261 }
2262
2263 /* don't mount any volumes with external journal devices */
2264 if (IsFlagOn(sb->s_feature_incompat, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
2265 Status = STATUS_UNRECOGNIZED_VOLUME;
2266 _SEH2_LEAVE;
2267 }
2268
2269 /* check block size */
2270 Vcb->BlockSize = (EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size);
2271 /* we cannot handle volume with block size bigger than 64k */
2272 if (Vcb->BlockSize > EXT2_MAX_USER_BLKSIZE) {
2273 Status = STATUS_UNRECOGNIZED_VOLUME;
2274 _SEH2_LEAVE;
2275 }
2276
2277 if (Vcb->BlockSize >= PAGE_SIZE) {
2278 Vcb->IoUnitBits = PAGE_SHIFT;
2279 Vcb->IoUnitSize = PAGE_SIZE;
2280 } else {
2281 Vcb->IoUnitSize = Vcb->BlockSize;
2282 Vcb->IoUnitBits = Ext2Log2(Vcb->BlockSize);
2283 }
2284
2285 /* initialize vcb header members ... */
2286 Vcb->Header.IsFastIoPossible = FastIoIsNotPossible;
2287 Vcb->Header.Resource = &(Vcb->MainResource);
2288 Vcb->Header.PagingIoResource = &(Vcb->PagingIoResource);
2289 Vcb->OpenVolumeCount = 0;
2290 Vcb->OpenHandleCount = 0;
2291 Vcb->ReferenceCount = 0;
2292
2293 /* initialize eresources */
2294 ExInitializeResourceLite(&Vcb->MainResource);
2295 ExInitializeResourceLite(&Vcb->PagingIoResource);
2296 ExInitializeResourceLite(&Vcb->MetaLock);
2297 ExInitializeResourceLite(&Vcb->McbLock);
2298 #ifndef _WIN2K_TARGET_
2299 ExInitializeFastMutex(&Vcb->Mutex);
2300 FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex);
2301 #endif
2302 VcbResourceInitialized = TRUE;
2303
2304 /* initialize Fcb list head */
2305 InitializeListHead(&Vcb->FcbList);
2306 KeInitializeSpinLock(&Vcb->FcbLock);
2307
2308 /* initialize Mcb list head */
2309 InitializeListHead(&(Vcb->McbList));
2310
2311 /* initialize directory notify list */
2312 InitializeListHead(&Vcb->NotifyList);
2313 FsRtlNotifyInitializeSync(&Vcb->NotifySync);
2314 NotifySyncInitialized = TRUE;
2315
2316 /* superblock checking */
2317 Vcb->SuperBlock = sb;
2318
2319 /* initialize Vpb and Label */
2320 Vcb->DeviceObject = VolumeDevice;
2321 Vcb->TargetDeviceObject = TargetDevice;
2322 Vcb->Vpb = Vpb;
2323 Vcb->RealDevice = Vpb->RealDevice;
2324 Vpb->DeviceObject = VolumeDevice;
2325
2326 /* set inode size */
2327 Vcb->InodeSize = (ULONG)sb->s_inode_size;
2328 if (Vcb->InodeSize == 0) {
2329 Vcb->InodeSize = EXT2_GOOD_OLD_INODE_SIZE;
2330 }
2331
2332 /* initialize inode lookaside list */
2333 ExInitializeNPagedLookasideList(&(Vcb->InodeLookasideList),
2334 NULL, NULL, 0, sizeof(EXT2_INODE),
2335 'SNIE', 0);
2336
2337 InodeLookasideInitialized = TRUE;
2338
2339 /* initialize label in Vpb */
2340 Status = Ext2InitializeLabel(Vcb, sb);
2341 if (!NT_SUCCESS(Status)) {
2342 DbgBreak();
2343 }
2344
2345 /* check device characteristics flags */
2346 if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
2347 SetLongFlag(Vcb->Flags, VCB_REMOVABLE_MEDIA);
2348 }
2349
2350 if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
2351 SetLongFlag(Vcb->Flags, VCB_FLOPPY_DISK);
2352 }
2353
2354 if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
2355 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2356 }
2357
2358 if (IsFlagOn(TargetDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
2359 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2360 }
2361
2362 /* verify device is writable ? */
2363 if (Ext2IsMediaWriteProtected(IrpContext, TargetDevice)) {
2364 SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2365 }
2366
2367 /* initialize UUID and serial number */
2368 if (Ext2IsNullUuid(sb->s_uuid)) {
2369 ExUuidCreate((UUID *)sb->s_uuid);
2370 } else {
2371 /* query parameters from registry */
2372 if (!NT_SUCCESS(Ext2PerformRegistryVolumeParams(Vcb))) {
2373 /* don't mount this volume */
2374 Status = STATUS_UNRECOGNIZED_VOLUME;
2375 _SEH2_LEAVE;
2376 }
2377 }
2378
2379 Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
2380 ((ULONG*)sb->s_uuid)[1] +
2381 ((ULONG*)sb->s_uuid)[2] +
2382 ((ULONG*)sb->s_uuid)[3];
2383
2384 /* query partition size and disk geometry parameters */
2385 DiskSize = Vcb->DiskGeometry.Cylinders.QuadPart *
2386 Vcb->DiskGeometry.TracksPerCylinder *
2387 Vcb->DiskGeometry.SectorsPerTrack *
2388 Vcb->DiskGeometry.BytesPerSector;
2389
2390 IoctlSize = sizeof(PARTITION_INFORMATION);
2391 Status = Ext2DiskIoControl(
2392 TargetDevice,
2393 IOCTL_DISK_GET_PARTITION_INFO,
2394 NULL,
2395 0,
2396 &Vcb->PartitionInformation,
2397 &IoctlSize );
2398 if (NT_SUCCESS(Status)) {
2399 PartSize = Vcb->PartitionInformation.PartitionLength.QuadPart;
2400 } else {
2401 Vcb->PartitionInformation.StartingOffset.QuadPart = 0;
2402 Vcb->PartitionInformation.PartitionLength.QuadPart = DiskSize;
2403 PartSize = DiskSize;
2404 Status = STATUS_SUCCESS;
2405 }
2406 Vcb->Header.AllocationSize.QuadPart =
2407 Vcb->Header.FileSize.QuadPart = PartSize;
2408
2409 Vcb->Header.ValidDataLength.QuadPart =
2410 Vcb->Header.FileSize.QuadPart;
2411
2412 /* verify count */
2413 IoctlSize = sizeof(ULONG);
2414 Status = Ext2DiskIoControl(
2415 TargetDevice,
2416 IOCTL_DISK_CHECK_VERIFY,
2417 NULL,
2418 0,
2419 &ChangeCount,
2420 &IoctlSize );
2421
2422 if (!NT_SUCCESS(Status)) {
2423 _SEH2_LEAVE;
2424 }
2425 Vcb->ChangeCount = ChangeCount;
2426
2427 /* create the stream object for ext2 volume */
2428 Vcb->Volume = IoCreateStreamFileObject(NULL, Vcb->Vpb->RealDevice);
2429 if (!Vcb->Volume) {
2430 Status = STATUS_UNRECOGNIZED_VOLUME;
2431 _SEH2_LEAVE;
2432 }
2433
2434 /* initialize streaming object file */
2435 Vcb->Volume->SectionObjectPointer = &(Vcb->SectionObject);
2436 Vcb->Volume->ReadAccess = TRUE;
2437 Vcb->Volume->WriteAccess = TRUE;
2438 Vcb->Volume->DeleteAccess = TRUE;
2439 Vcb->Volume->FsContext = (PVOID) Vcb;
2440 Vcb->Volume->FsContext2 = NULL;
2441 Vcb->Volume->Vpb = Vcb->Vpb;
2442
2443 FileSizes.AllocationSize.QuadPart =
2444 FileSizes.FileSize.QuadPart =
2445 FileSizes.ValidDataLength.QuadPart =
2446 Vcb->Header.AllocationSize.QuadPart;
2447
2448 CcInitializeCacheMap( Vcb->Volume,
2449 &FileSizes,
2450 TRUE,
2451 &(Ext2Global->CacheManagerNoOpCallbacks),
2452 Vcb );
2453
2454 /* initialize disk block LargetMcb and entry Mcb,
2455 it will raise an expcetion if failed */
2456 _SEH2_TRY {
2457 FsRtlInitializeLargeMcb(&(Vcb->Extents), PagedPool);
2458 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
2459 Status = STATUS_INSUFFICIENT_RESOURCES;
2460 DbgBreak();
2461 } _SEH2_END;
2462 if (!NT_SUCCESS(Status)) {
2463 _SEH2_LEAVE;
2464 }
2465 ExtentsInitialized = TRUE;
2466
2467 /* set block device */
2468 Vcb->bd.bd_dev = Vcb->RealDevice;
2469 Vcb->bd.bd_geo = Vcb->DiskGeometry;
2470 Vcb->bd.bd_part = Vcb->PartitionInformation;
2471 Vcb->bd.bd_volume = Vcb->Volume;
2472 Vcb->bd.bd_priv = (void *) Vcb;
2473 memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root));
2474 spin_lock_init(&Vcb->bd.bd_bh_lock);
2475 Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
2476 Vcb->BlockSize, 0, 0, NULL);
2477 if (!Vcb->bd.bd_bh_cache) {
2478 Status = STATUS_INSUFFICIENT_RESOURCES;
2479 _SEH2_LEAVE;
2480 }
2481
2482 Vcb->SectorBits = Ext2Log2(SECTOR_SIZE);
2483 Vcb->sb.s_magic = sb->s_magic;
2484 Vcb->sb.s_bdev = &Vcb->bd;
2485 Vcb->sb.s_blocksize = BLOCK_SIZE;
2486 Vcb->sb.s_blocksize_bits = BLOCK_BITS;
2487 Vcb->sb.s_priv = (void *) Vcb;
2488 Vcb->sb.s_fs_info = &Vcb->sbi;
2489
2490 Vcb->sbi.s_es = sb;
2491 Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
2492 Vcb->sbi.s_first_ino = sb->s_first_ino;
2493 Vcb->sbi.s_desc_size = sb->s_desc_size;
2494
2495 if (EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
2496 if (Vcb->sbi.s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
2497 Vcb->sbi.s_desc_size > EXT4_MAX_DESC_SIZE ||
2498 !is_power_of_2(Vcb->sbi.s_desc_size)) {
2499 DEBUG(DL_ERR, ("EXT4-fs: unsupported descriptor size %lu\n", Vcb->sbi.s_desc_size));
2500 Status = STATUS_DISK_CORRUPT_ERROR;
2501 _SEH2_LEAVE;
2502 }
2503 } else {
2504 Vcb->sbi.s_desc_size = EXT4_MIN_DESC_SIZE;
2505 }
2506
2507 Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
2508 Vcb->sbi.s_inodes_per_group = sb->s_inodes_per_group;
2509 if (EXT3_INODES_PER_GROUP(&Vcb->sb) == 0) {
2510 Status = STATUS_DISK_CORRUPT_ERROR;
2511 _SEH2_LEAVE;
2512 }
2513 Vcb->sbi.s_inodes_per_block = BLOCK_SIZE / Vcb->InodeSize;
2514 if (Vcb->sbi.s_inodes_per_block == 0) {
2515 Status = STATUS_DISK_CORRUPT_ERROR;
2516 _SEH2_LEAVE;
2517 }
2518 Vcb->sbi.s_itb_per_group = Vcb->sbi.s_inodes_per_group /
2519 Vcb->sbi.s_inodes_per_block;
2520
2521
2522 Vcb->sbi.s_desc_per_block = BLOCK_SIZE / GROUP_DESC_SIZE;
2523 Vcb->sbi.s_desc_per_block_bits = ilog2(Vcb->sbi.s_desc_per_block);
2524
2525 for (i=0; i < 4; i++) {
2526 Vcb->sbi.s_hash_seed[i] = sb->s_hash_seed[i];
2527 }
2528 Vcb->sbi.s_def_hash_version = sb->s_def_hash_version;
2529
2530 if (le32_to_cpu(sb->s_rev_level) == EXT3_GOOD_OLD_REV &&
2531 (EXT3_HAS_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
2532 EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
2533 EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~0U))) {
2534 printk(KERN_WARNING
2535 "EXT3-fs warning: feature flags set on rev 0 fs, "
2536 "running e2fsck is recommended\n");
2537 }
2538
2539 /*
2540 * Check feature flags regardless of the revision level, since we
2541 * previously didn't change the revision level when setting the flags,
2542 * so there is a chance incompat flags are set on a rev 0 filesystem.
2543 */
2544 features = EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
2545 if (features & EXT4_FEATURE_INCOMPAT_DIRDATA) {
2546 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2547 ClearFlag(features, EXT4_FEATURE_INCOMPAT_DIRDATA);
2548 }
2549 if (features) {
2550 printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of "
2551 "unsupported optional features (%x).\n",
2552 Vcb->sb.s_id, le32_to_cpu(features));
2553 Status = STATUS_UNRECOGNIZED_VOLUME;
2554 _SEH2_LEAVE;
2555 }
2556
2557 features = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
2558 if (features) {
2559 printk(KERN_ERR "EXT3-fs: %s: unsupported optional features in this volume: (%x).\n",
2560 Vcb->sb.s_id, le32_to_cpu(features));
2561 if (CanIWrite(Vcb)) {
2562 } else {
2563 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2564 }
2565 }
2566
2567 has_huge_files = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
2568
2569 Vcb->sb.s_maxbytes = ext3_max_size(BLOCK_BITS, has_huge_files);
2570 Vcb->max_bitmap_bytes = ext3_max_bitmap_size(BLOCK_BITS,
2571 has_huge_files);
2572 Vcb->max_bytes = ext3_max_size(BLOCK_BITS, has_huge_files);
2573
2574 /* calculate maximum file bocks ... */
2575 {
2576 ULONG dwData[EXT2_BLOCK_TYPES] = {EXT2_NDIR_BLOCKS, 1, 1, 1};
2577 ULONG i;
2578
2579 ASSERT(BLOCK_BITS == Ext2Log2(BLOCK_SIZE));
2580
2581 Vcb->sbi.s_groups_count = (ULONG)(ext3_blocks_count(sb) - sb->s_first_data_block +
2582 sb->s_blocks_per_group - 1) / sb->s_blocks_per_group;
2583
2584 Vcb->max_data_blocks = 0;
2585 for (i = 0; i < EXT2_BLOCK_TYPES; i++) {
2586 if (BLOCK_BITS >= 12 && i == (EXT2_BLOCK_TYPES - 1)) {
2587 dwData[i] = 0x40000000;
2588 } else {
2589 dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
2590 }
2591 Vcb->max_blocks_per_layer[i] = dwData[i];
2592 Vcb->max_data_blocks += Vcb->max_blocks_per_layer[i];
2593 }
2594 }
2595
2596 Vcb->sbi.s_gdb_count = (Vcb->sbi.s_groups_count + Vcb->sbi.s_desc_per_block - 1) /
2597 Vcb->sbi.s_desc_per_block;
2598 /* load all gorup desc */
2599 if (!Ext2LoadGroup(Vcb)) {
2600 Status = STATUS_UNSUCCESSFUL;
2601 _SEH2_LEAVE;
2602 }
2603
2604 /* recovery journal since it's ext3 */
2605 if (Vcb->IsExt3fs) {
2606 Ext2RecoverJournal(IrpContext, Vcb);
2607 if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) {
2608 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2609 }
2610 }
2611
2612 /* Now allocating the mcb for root ... */
2613 Buffer[0] = L'\\';
2614 Buffer[1] = 0;
2615 RootNode.Buffer = Buffer;
2616 RootNode.MaximumLength = RootNode.Length = 2;
2617 Vcb->McbTree = Ext2AllocateMcb(
2618 Vcb, &RootNode, NULL,
2619 FILE_ATTRIBUTE_DIRECTORY
2620 );
2621 if (!Vcb->McbTree) {
2622 DbgBreak();
2623 Status = STATUS_UNSUCCESSFUL;
2624 _SEH2_LEAVE;
2625 }
2626
2627 Vcb->sb.s_root = Ext2BuildEntry(Vcb, NULL, &RootNode);
2628 if (!Vcb->sb.s_root) {
2629 DbgBreak();
2630 Status = STATUS_UNSUCCESSFUL;
2631 _SEH2_LEAVE;
2632 }
2633 Vcb->sb.s_root->d_sb = &Vcb->sb;
2634 Vcb->sb.s_root->d_inode = &Vcb->McbTree->Inode;
2635 Vcb->McbTree->de = Vcb->sb.s_root;
2636
2637 /* load root inode */
2638 Vcb->McbTree->Inode.i_ino = EXT2_ROOT_INO;
2639 Vcb->McbTree->Inode.i_sb = &Vcb->sb;
2640 if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode)) {
2641 DbgBreak();
2642 Status = STATUS_CANT_WAIT;
2643 _SEH2_LEAVE;
2644 }
2645
2646 /* initializeroot node */
2647 Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
2648 Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
2649 Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
2650 Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
2651
2652 /* check bitmap if user specifies it */
2653 if (IsFlagOn(Ext2Global->Flags, EXT2_CHECKING_BITMAP)) {
2654 Ext2CheckBitmapConsistency(IrpContext, Vcb);
2655 }
2656
2657 /* get anything doen, then refer target device */
2658 ObReferenceObject(Vcb->TargetDeviceObject);
2659 SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
2660
2661 } _SEH2_FINALLY {
2662
2663 if (!NT_SUCCESS(Status)) {
2664
2665 if (Vcb->McbTree) {
2666 Ext2FreeMcb(Vcb, Vcb->McbTree);
2667 }
2668
2669 if (InodeLookasideInitialized) {
2670 ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
2671 }
2672
2673 if (ExtentsInitialized) {
2674 Ext2DropGroup(Vcb);
2675 if (Vcb->bd.bd_bh_cache)
2676 kmem_cache_destroy(Vcb->bd.bd_bh_cache);
2677 FsRtlUninitializeLargeMcb(&(Vcb->Extents));
2678 }
2679
2680 if (Vcb->Volume) {
2681 if (Vcb->Volume->PrivateCacheMap) {
2682 Ext2SyncUninitializeCacheMap(Vcb->Volume);
2683 }
2684 ObDereferenceObject(Vcb->Volume);
2685 }
2686
2687 if (NotifySyncInitialized) {
2688 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
2689 }
2690
2691 if (VcbResourceInitialized) {
2692 ExDeleteResourceLite(&Vcb->McbLock);
2693 ExDeleteResourceLite(&Vcb->MetaLock);
2694 ExDeleteResourceLite(&Vcb->MainResource);
2695 ExDeleteResourceLite(&Vcb->PagingIoResource);
2696 }
2697 }
2698 } _SEH2_END;
2699
2700 return Status;
2701 }
2702
2703
2704 VOID
2705 Ext2TearDownStream(IN PEXT2_VCB Vcb)
2706 {
2707 PFILE_OBJECT Stream = Vcb->Volume;
2708 IO_STATUS_BLOCK IoStatus;
2709
2710 ASSERT(Vcb != NULL);
2711 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2712 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2713
2714 if (Stream) {
2715
2716 Vcb->Volume = NULL;
2717
2718 if (IsFlagOn(Stream->Flags, FO_FILE_MODIFIED)) {
2719 CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
2720 ClearFlag(Stream->Flags, FO_FILE_MODIFIED);
2721 }
2722
2723 if (Stream->PrivateCacheMap) {
2724 Ext2SyncUninitializeCacheMap(Stream);
2725 }
2726
2727 ObDereferenceObject(Stream);
2728 }
2729 }
2730
2731 VOID
2732 Ext2DestroyVcb (IN PEXT2_VCB Vcb)
2733 {
2734 ASSERT(Vcb != NULL);
2735 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2736 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2737
2738 DEBUG(DL_FUN, ("Ext2DestroyVcb ...\n"));
2739
2740 if (Vcb->Volume) {
2741 Ext2TearDownStream(Vcb);
2742 }
2743 ASSERT(NULL == Vcb->Volume);
2744
2745 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
2746 Ext2ListExtents(&Vcb->Extents);
2747 FsRtlUninitializeLargeMcb(&(Vcb->Extents));
2748
2749 Ext2CleanupAllMcbs(Vcb);
2750
2751 Ext2DropGroup(Vcb);
2752
2753 if (Vcb->bd.bd_bh_cache)
2754 kmem_cache_destroy(Vcb->bd.bd_bh_cache);
2755
2756 if (Vcb->SuperBlock) {
2757 Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
2758 Vcb->SuperBlock = NULL;
2759 }
2760
2761 if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
2762 ASSERT(Vcb->Vpb2 != NULL);
2763 DEBUG(DL_DBG, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb->Vpb2));
2764 ExFreePoolWithTag(Vcb->Vpb2, TAG_VPB);
2765 DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
2766 Vcb->Vpb2 = NULL;
2767 }
2768
2769 ObDereferenceObject(Vcb->TargetDeviceObject);
2770
2771 ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
2772 ExDeleteResourceLite(&Vcb->McbLock);
2773 ExDeleteResourceLite(&Vcb->MetaLock);
2774 ExDeleteResourceLite(&Vcb->PagingIoResource);
2775 ExDeleteResourceLite(&Vcb->MainResource);
2776
2777 DEBUG(DL_DBG, ("Ext2DestroyVcb: DevObject=%p Vcb=%p\n", Vcb->DeviceObject, Vcb));
2778 IoDeleteDevice(Vcb->DeviceObject);
2779 DEC_MEM_COUNT(PS_VCB, Vcb->DeviceObject, sizeof(EXT2_VCB));
2780 }
2781
2782
2783 /* uninitialize cache map */
2784
2785 VOID
2786 Ext2SyncUninitializeCacheMap (
2787 IN PFILE_OBJECT FileObject
2788 )
2789 {
2790 CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
2791 NTSTATUS WaitStatus;
2792 LARGE_INTEGER Ext2LargeZero = {0,0};
2793
2794
2795 KeInitializeEvent( &UninitializeCompleteEvent.Event,
2796 SynchronizationEvent,
2797 FALSE);
2798
2799 CcUninitializeCacheMap( FileObject,
2800 &Ext2LargeZero,
2801 &UninitializeCompleteEvent );
2802
2803 WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
2804 Executive,
2805 KernelMode,
2806 FALSE,
2807 NULL);
2808
2809 ASSERT (NT_SUCCESS(WaitStatus));
2810 }
2811
2812 /* Link Mcb to tail of Vcb->McbList queue */
2813
2814 VOID
2815 Ext2LinkTailMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2816 {
2817 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2818 return;
2819 }
2820
2821 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2822
2823 if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2824 DEBUG(DL_RES, ( "Ext2LinkTailMcb: %wZ already linked.\n",
2825 &Mcb->FullName));
2826 } else {
2827 InsertTailList(&Vcb->McbList, &Mcb->Link);
2828 SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
2829 Ext2ReferXcb(&Vcb->NumOfMcb);
2830 }
2831
2832 ExReleaseResourceLite(&Vcb->McbLock);
2833 }
2834
2835 /* Link Mcb to head of Vcb->McbList queue */
2836
2837 VOID
2838 Ext2LinkHeadMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2839 {
2840 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2841 return;
2842 }
2843
2844 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2845
2846 if (!IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2847 InsertHeadList(&Vcb->McbList, &Mcb->Link);
2848 SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
2849 Ext2ReferXcb(&Vcb->NumOfMcb);
2850 } else {
2851 DEBUG(DL_RES, ( "Ext2LinkHeadMcb: %wZ already linked.\n",
2852 &Mcb->FullName));
2853 }
2854 ExReleaseResourceLite(&Vcb->McbLock);
2855 }
2856
2857 /* Unlink Mcb from Vcb->McbList queue */
2858
2859 VOID
2860 Ext2UnlinkMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2861 {
2862 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2863 return;
2864 }
2865
2866 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2867
2868 if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2869 RemoveEntryList(&(Mcb->Link));
2870 ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
2871 Ext2DerefXcb(&Vcb->NumOfMcb);
2872 } else {
2873 DEBUG(DL_RES, ( "Ext2UnlinkMcb: %wZ already unlinked.\n",
2874 &Mcb->FullName));
2875 }
2876 ExReleaseResourceLite(&Vcb->McbLock);
2877 }
2878
2879 /* get the first Mcb record in Vcb->McbList */
2880
2881 PEXT2_MCB
2882 Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
2883 {
2884 PEXT2_MCB Head = NULL;
2885 PEXT2_MCB Tail = NULL;
2886 PEXT2_MCB Mcb = NULL;
2887 PLIST_ENTRY List = NULL;
2888 ULONG i = 0;
2889
2890 if (!ExAcquireResourceExclusiveLite(&Vcb->McbLock, Wait)) {
2891 return NULL;
2892 }
2893
2894 while (Number--) {
2895
2896 if (!IsListEmpty(&Vcb->McbList)) {
2897
2898 while (i++ < Vcb->NumOfMcb) {
2899
2900 List = RemoveHeadList(&Vcb->McbList);
2901 Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link);
2902 ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK));
2903
2904 if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) &&
2905 Mcb->Refercount == 0 &&
2906 (Mcb->Child == NULL || IsMcbSymLink(Mcb))) {
2907
2908 Ext2RemoveMcb(Vcb, Mcb);
2909 ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
2910 Ext2DerefXcb(&Vcb->NumOfMcb);
2911
2912 /* attach all Mcb into a chain*/
2913 if (Head) {
2914 ASSERT(Tail != NULL);
2915 Tail->Next = Mcb;
2916 Tail = Mcb;
2917 } else {
2918 Head = Tail = Mcb;
2919 }
2920 Tail->Next = NULL;
2921
2922 } else {
2923
2924 InsertTailList(&Vcb->McbList, &Mcb->Link);
2925 Mcb = NULL;
2926 }
2927 }
2928 }
2929 }
2930 ExReleaseResourceLite(&Vcb->McbLock);
2931
2932 return Head;
2933 }
2934
2935
2936 /* Reaper thread to release unused Mcb blocks */
2937 VOID NTAPI
2938 Ext2ReaperThread(
2939 PVOID Context
2940 )
2941 {
2942 BOOLEAN GlobalAcquired = FALSE;
2943
2944 BOOLEAN DidNothing = TRUE;
2945 BOOLEAN LastState = TRUE;
2946 BOOLEAN WaitLock;
2947
2948 PLIST_ENTRY List = NULL;
2949 LARGE_INTEGER Timeout;
2950
2951 PEXT2_VCB Vcb = NULL;
2952 PEXT2_MCB Mcb = NULL;
2953
2954 ULONG i, NumOfMcbs;
2955
2956 _SEH2_TRY {
2957
2958 /* wake up DirverEntry */
2959 KeSetEvent(&Ext2Global->Reaper.Engine, 0, FALSE);
2960
2961 /* now process looping */
2962 while (TRUE) {
2963
2964 WaitLock = FALSE;
2965
2966 /* calculate how long we need wait */
2967 if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 128)) {
2968 Timeout.QuadPart = (LONGLONG)-1000*1000; /* 0.1 second */
2969 NumOfMcbs = Ext2Global->MaxDepth * 4;
2970 WaitLock = TRUE;
2971 } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 32)) {
2972 Timeout.QuadPart = (LONGLONG)-1000*1000*5; /* 0.5 second */
2973 NumOfMcbs = Ext2Global->MaxDepth * 2;
2974 WaitLock = TRUE;
2975 } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 8)) {
2976 Timeout.QuadPart = (LONGLONG)-1000*1000*10; /* 1 second */
2977 NumOfMcbs = Ext2Global->MaxDepth;
2978 } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 2)) {
2979 Timeout.QuadPart = (LONGLONG)-2*1000*1000*10; /* 2 second */
2980 NumOfMcbs = Ext2Global->MaxDepth / 4;
2981 } else if (Ext2Global->PerfStat.Current.Mcb > (ULONG)Ext2Global->MaxDepth) {
2982 Timeout.QuadPart = (LONGLONG)-4*1000*1000*10; /* 4 seconds */
2983 NumOfMcbs = Ext2Global->MaxDepth / 8;
2984 } else if (DidNothing) {
2985 Timeout.QuadPart = (LONGLONG)-8*1000*1000*10; /* 8 seconds */
2986 if (LastState) {
2987 Timeout.QuadPart *= 2;
2988 }
2989 NumOfMcbs = Ext2Global->MaxDepth / 16;
2990 } else {
2991 Timeout.QuadPart = (LONGLONG)-5*1000*1000*10; /* 5 seconds */
2992 if (LastState) {
2993 Timeout.QuadPart *= 2;
2994 }
2995 NumOfMcbs = Ext2Global->MaxDepth / 32;
2996 }
2997
2998 if (NumOfMcbs == 0)
2999 NumOfMcbs = 1;
3000
3001 LastState = DidNothing;
3002
3003 /* wait until it is waken or it times out */
3004 KeWaitForSingleObject(
3005 &(Ext2Global->Reaper.Wait),
3006 Executive,
3007 KernelMode,
3008 FALSE,
3009 &Timeout
3010 );
3011
3012 DidNothing = TRUE;
3013
3014 /* acquire global exclusive lock */
3015 if (!ExAcquireResourceSharedLite(&Ext2Global->Resource, WaitLock)) {
3016 continue;
3017 }
3018 GlobalAcquired = TRUE;
3019
3020 /* search all Vcb to get unused resources freed to system */
3021 for (List = Ext2Global->VcbList.Flink;
3022 List != &(Ext2Global->VcbList);
3023 List = List->Flink ) {
3024
3025 Vcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
3026
3027 Mcb = Ext2FirstUnusedMcb(Vcb, WaitLock, NumOfMcbs);
3028 while (Mcb) {
3029 PEXT2_MCB Next = Mcb->Next;
3030 DEBUG(DL_RES, ( "Ext2ReaperThread: releasing Mcb (%p): %wZ"
3031 " Total: %xh\n", Mcb, &Mcb->FullName,
3032 Ext2Global->PerfStat.Current.Mcb));
3033 Ext2FreeMcb(Vcb, Mcb);
3034 Mcb = Next;
3035 LastState = DidNothing = FALSE;
3036 }
3037 }
3038
3039 if (GlobalAcquired) {
3040 ExReleaseResourceLite(&Ext2Global->Resource);
3041 GlobalAcquired = FALSE;
3042 }
3043 }
3044
3045 } _SEH2_FINALLY {
3046
3047 if (GlobalAcquired) {
3048 ExReleaseResourceLite(&Ext2Global->Resource);
3049 }
3050 } _SEH2_END;
3051
3052 PsTerminateSystemThread(STATUS_SUCCESS);
3053 }
3054
3055
3056 NTSTATUS
3057 Ext2StartReaperThread()
3058 {
3059 NTSTATUS status = STATUS_SUCCESS;
3060 OBJECT_ATTRIBUTES oa;
3061 HANDLE handle = 0;
3062
3063 /* initialize wait event */
3064 KeInitializeEvent(
3065 &Ext2Global->Reaper.Wait,
3066 SynchronizationEvent, FALSE
3067 );
3068
3069 /* initialize oa */
3070 InitializeObjectAttributes(
3071 &oa,
3072 NULL,
3073 OBJ_CASE_INSENSITIVE |
3074 OBJ_KERNEL_HANDLE,
3075 NULL,
3076 NULL
3077 );
3078
3079 /* start a new system thread */
3080 status = PsCreateSystemThread(
3081 &handle,
3082 0,
3083 &oa,
3084 NULL,
3085 NULL,
3086 Ext2ReaperThread,
3087 NULL
3088 );
3089
3090 if (NT_SUCCESS(status)) {
3091 ZwClose(handle);
3092 }
3093
3094 return status;
3095 }