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