[EXT2]
[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 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 #ifdef __REACTOS__
2081 ParamPattern[i].uValue[k] = Params->Buffer[j + k];
2082 k++;
2083 #else
2084 ParamPattern[i].uValue[k] = Params->Buffer[j + k++];
2085 #endif
2086 }
2087 if (k) {
2088 NTSTATUS status;
2089 ANSI_STRING AnsiName;
2090 AnsiName.Length = 0;
2091 AnsiName.MaximumLength =ParamPattern[i].Length;
2092 AnsiName.Buffer = ParamPattern[i].aValue;
2093
2094 Name2.Buffer = ParamPattern[i].uValue;
2095 Name2.MaximumLength = Name2.Length = k * sizeof(WCHAR);
2096 status = RtlUnicodeStringToAnsiString(
2097 &AnsiName, &Name2, FALSE);
2098 if (NT_SUCCESS(status)) {
2099 *(ParamPattern[i].bExist) = TRUE;
2100 } else {
2101 *ParamPattern[i].bExist = FALSE;
2102 }
2103 }
2104 }
2105 break;
2106 }
2107 }
2108 }
2109
2110 if (bMountPoint) {
2111 Property->DrvLetter = DrvLetter[0];
2112 Property->DrvLetter |= 0x80;
2113 }
2114 }
2115
2116 NTSTATUS
2117 Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
2118 {
2119 NTSTATUS Status;
2120 UNICODE_STRING VolumeParams;
2121
2122 Status = Ext2QueryVolumeParams(Vcb, &VolumeParams);
2123 if (NT_SUCCESS(Status)) {
2124
2125 /* set Vcb settings from registery */
2126 EXT2_VOLUME_PROPERTY2 Property;
2127 Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
2128 Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
2129
2130 } else {
2131
2132 /* don't support auto mount */
2133 if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) {
2134 Status = STATUS_SUCCESS;
2135 } else {
2136 Status = STATUS_UNSUCCESSFUL;
2137 goto errorout;
2138 }
2139
2140 /* set Vcb settings from Ext2Global */
2141 if (IsFlagOn(Ext2Global->Flags, EXT2_SUPPORT_WRITING)) {
2142 if (Vcb->IsExt3fs) {
2143 if (IsFlagOn(Ext2Global->Flags, EXT3_FORCE_WRITING)) {
2144 ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
2145 } else {
2146 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2147 }
2148 } else {
2149 ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
2150 }
2151 } else {
2152 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2153 }
2154
2155 /* set the default codepage */
2156 Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
2157 memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
2158 Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
2159
2160 if ((Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) != 0) {
2161 RtlCopyMemory( Vcb->sHidingPrefix,
2162 Ext2Global->sHidingPrefix,
2163 HIDINGPAT_LEN);
2164 } else {
2165 RtlZeroMemory( Vcb->sHidingPrefix,
2166 HIDINGPAT_LEN);
2167 }
2168
2169 if ((Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) != 0) {
2170 RtlCopyMemory( Vcb->sHidingSuffix,
2171 Ext2Global->sHidingSuffix,
2172 HIDINGPAT_LEN);
2173 } else {
2174 RtlZeroMemory( Vcb->sHidingSuffix,
2175 HIDINGPAT_LEN);
2176 }
2177 }
2178
2179 errorout:
2180
2181 if (VolumeParams.Buffer) {
2182 Ext2FreePool(VolumeParams.Buffer, EXT2_PARAM_MAGIC);
2183 }
2184
2185 return Status;
2186 }
2187
2188 NTSTATUS
2189 Ext2InitializeLabel(
2190 IN PEXT2_VCB Vcb,
2191 IN PEXT2_SUPER_BLOCK Sb
2192 )
2193 {
2194 NTSTATUS status;
2195
2196 USHORT Length;
2197 UNICODE_STRING Label;
2198 OEM_STRING OemName;
2199
2200 Label.MaximumLength = 16 * sizeof(WCHAR);
2201 Label.Length = 0;
2202 Label.Buffer = Vcb->Vpb->VolumeLabel;
2203 Vcb->Vpb->VolumeLabelLength = 0;
2204 RtlZeroMemory(Label.Buffer, Label.MaximumLength);
2205
2206 Length = 16;
2207 while ( (Length > 0) &&
2208 ((Sb->s_volume_name[Length -1] == 0x00) ||
2209 (Sb->s_volume_name[Length - 1] == 0x20) )
2210 ) {
2211 Length--;
2212 }
2213
2214 if (Length == 0) {
2215 return STATUS_SUCCESS;
2216 }
2217
2218 OemName.Buffer = Sb->s_volume_name;
2219 OemName.MaximumLength = 16;
2220 OemName.Length = Length;
2221
2222 status = Ext2OEMToUnicode(Vcb, &Label, &OemName);
2223 if (NT_SUCCESS(status)) {
2224 Vcb->Vpb->VolumeLabelLength = Label.Length;
2225 }
2226
2227 return status;
2228 }
2229
2230 static __inline BOOLEAN Ext2IsNullUuid (__u8 * uuid)
2231 {
2232 int i;
2233 for (i = 0; i < 16; i++) {
2234 if (uuid[i]) {
2235 break;
2236 }
2237 }
2238
2239 return (i >= 16);
2240 }
2241
2242 #define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
2243
2244 NTSTATUS
2245 Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
2246 IN PEXT2_VCB Vcb,
2247 IN PEXT2_SUPER_BLOCK sb,
2248 IN PDEVICE_OBJECT TargetDevice,
2249 IN PDEVICE_OBJECT VolumeDevice,
2250 IN PVPB Vpb )
2251 {
2252 NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
2253 ULONG IoctlSize;
2254 LONGLONG DiskSize;
2255 LONGLONG PartSize;
2256 UNICODE_STRING RootNode;
2257 USHORT Buffer[2];
2258 ULONG ChangeCount = 0, features;
2259 CC_FILE_SIZES FileSizes;
2260 int i, has_huge_files;
2261
2262 BOOLEAN VcbResourceInitialized = FALSE;
2263 BOOLEAN NotifySyncInitialized = FALSE;
2264 BOOLEAN ExtentsInitialized = FALSE;
2265 BOOLEAN InodeLookasideInitialized = FALSE;
2266
2267 _SEH2_TRY {
2268
2269 if (Vpb == NULL) {
2270 Status = STATUS_DEVICE_NOT_READY;
2271 _SEH2_LEAVE;
2272 }
2273
2274 /* checking in/compat features */
2275 if (IsFlagOn(sb->s_feature_compat, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
2276 Vcb->IsExt3fs = TRUE;
2277 }
2278
2279 /* don't mount any volumes with external journal devices */
2280 if (IsFlagOn(sb->s_feature_incompat, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
2281 Status = STATUS_UNRECOGNIZED_VOLUME;
2282 _SEH2_LEAVE;
2283 }
2284
2285 /* check block size */
2286 Vcb->BlockSize = (EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size);
2287 /* we cannot handle volume with block size bigger than 64k */
2288 if (Vcb->BlockSize > EXT2_MAX_USER_BLKSIZE) {
2289 Status = STATUS_UNRECOGNIZED_VOLUME;
2290 _SEH2_LEAVE;
2291 }
2292
2293 if (Vcb->BlockSize >= PAGE_SIZE) {
2294 Vcb->IoUnitBits = PAGE_SHIFT;
2295 Vcb->IoUnitSize = PAGE_SIZE;
2296 } else {
2297 Vcb->IoUnitSize = Vcb->BlockSize;
2298 Vcb->IoUnitBits = Ext2Log2(Vcb->BlockSize);
2299 }
2300
2301 /* initialize vcb header members ... */
2302 Vcb->Header.IsFastIoPossible = FastIoIsNotPossible;
2303 Vcb->Header.Resource = &(Vcb->MainResource);
2304 Vcb->Header.PagingIoResource = &(Vcb->PagingIoResource);
2305 Vcb->OpenVolumeCount = 0;
2306 Vcb->OpenHandleCount = 0;
2307 Vcb->ReferenceCount = 0;
2308
2309 /* initialize eresources */
2310 ExInitializeResourceLite(&Vcb->MainResource);
2311 ExInitializeResourceLite(&Vcb->PagingIoResource);
2312 ExInitializeResourceLite(&Vcb->MetaLock);
2313 ExInitializeResourceLite(&Vcb->McbLock);
2314 #ifndef _WIN2K_TARGET_
2315 ExInitializeFastMutex(&Vcb->Mutex);
2316 FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex);
2317 #endif
2318 VcbResourceInitialized = TRUE;
2319
2320 /* initialize Fcb list head */
2321 InitializeListHead(&Vcb->FcbList);
2322 KeInitializeSpinLock(&Vcb->FcbLock);
2323
2324 /* initialize Mcb list head */
2325 InitializeListHead(&(Vcb->McbList));
2326
2327 /* initialize directory notify list */
2328 InitializeListHead(&Vcb->NotifyList);
2329 FsRtlNotifyInitializeSync(&Vcb->NotifySync);
2330 NotifySyncInitialized = TRUE;
2331
2332 /* superblock checking */
2333 Vcb->SuperBlock = sb;
2334
2335 /* initialize Vpb and Label */
2336 Vcb->DeviceObject = VolumeDevice;
2337 Vcb->TargetDeviceObject = TargetDevice;
2338 Vcb->Vpb = Vpb;
2339 Vcb->RealDevice = Vpb->RealDevice;
2340 Vpb->DeviceObject = VolumeDevice;
2341
2342 /* set inode size */
2343 Vcb->InodeSize = (ULONG)sb->s_inode_size;
2344 if (Vcb->InodeSize == 0) {
2345 Vcb->InodeSize = EXT2_GOOD_OLD_INODE_SIZE;
2346 }
2347
2348 /* initialize inode lookaside list */
2349 ExInitializeNPagedLookasideList(&(Vcb->InodeLookasideList),
2350 NULL, NULL, 0, sizeof(EXT2_INODE),
2351 'SNIE', 0);
2352
2353 InodeLookasideInitialized = TRUE;
2354
2355 /* initialize label in Vpb */
2356 Status = Ext2InitializeLabel(Vcb, sb);
2357 if (!NT_SUCCESS(Status)) {
2358 DbgBreak();
2359 }
2360
2361 /* check device characteristics flags */
2362 if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
2363 SetLongFlag(Vcb->Flags, VCB_REMOVABLE_MEDIA);
2364 }
2365
2366 if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
2367 SetLongFlag(Vcb->Flags, VCB_FLOPPY_DISK);
2368 }
2369
2370 if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
2371 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2372 }
2373
2374 if (IsFlagOn(TargetDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
2375 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2376 }
2377
2378 /* verify device is writable ? */
2379 if (Ext2IsMediaWriteProtected(IrpContext, TargetDevice)) {
2380 SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2381 }
2382
2383 /* initialize UUID and serial number */
2384 if (Ext2IsNullUuid(sb->s_uuid)) {
2385 ExUuidCreate((UUID *)sb->s_uuid);
2386 } else {
2387 /* query parameters from registry */
2388 if (!NT_SUCCESS(Ext2PerformRegistryVolumeParams(Vcb))) {
2389 /* don't mount this volume */
2390 Status = STATUS_UNRECOGNIZED_VOLUME;
2391 _SEH2_LEAVE;
2392 }
2393 }
2394
2395 Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
2396 ((ULONG*)sb->s_uuid)[1] +
2397 ((ULONG*)sb->s_uuid)[2] +
2398 ((ULONG*)sb->s_uuid)[3];
2399
2400 /* query partition size and disk geometry parameters */
2401 DiskSize = Vcb->DiskGeometry.Cylinders.QuadPart *
2402 Vcb->DiskGeometry.TracksPerCylinder *
2403 Vcb->DiskGeometry.SectorsPerTrack *
2404 Vcb->DiskGeometry.BytesPerSector;
2405
2406 IoctlSize = sizeof(PARTITION_INFORMATION);
2407 Status = Ext2DiskIoControl(
2408 TargetDevice,
2409 IOCTL_DISK_GET_PARTITION_INFO,
2410 NULL,
2411 0,
2412 &Vcb->PartitionInformation,
2413 &IoctlSize );
2414 if (NT_SUCCESS(Status)) {
2415 PartSize = Vcb->PartitionInformation.PartitionLength.QuadPart;
2416 } else {
2417 Vcb->PartitionInformation.StartingOffset.QuadPart = 0;
2418 Vcb->PartitionInformation.PartitionLength.QuadPart = DiskSize;
2419 PartSize = DiskSize;
2420 Status = STATUS_SUCCESS;
2421 }
2422 Vcb->Header.AllocationSize.QuadPart =
2423 Vcb->Header.FileSize.QuadPart = PartSize;
2424
2425 Vcb->Header.ValidDataLength.QuadPart =
2426 Vcb->Header.FileSize.QuadPart;
2427
2428 /* verify count */
2429 IoctlSize = sizeof(ULONG);
2430 Status = Ext2DiskIoControl(
2431 TargetDevice,
2432 IOCTL_DISK_CHECK_VERIFY,
2433 NULL,
2434 0,
2435 &ChangeCount,
2436 &IoctlSize );
2437
2438 if (!NT_SUCCESS(Status)) {
2439 _SEH2_LEAVE;
2440 }
2441 Vcb->ChangeCount = ChangeCount;
2442
2443 /* create the stream object for ext2 volume */
2444 Vcb->Volume = IoCreateStreamFileObject(NULL, Vcb->Vpb->RealDevice);
2445 if (!Vcb->Volume) {
2446 Status = STATUS_UNRECOGNIZED_VOLUME;
2447 _SEH2_LEAVE;
2448 }
2449
2450 /* initialize streaming object file */
2451 Vcb->Volume->SectionObjectPointer = &(Vcb->SectionObject);
2452 Vcb->Volume->ReadAccess = TRUE;
2453 Vcb->Volume->WriteAccess = TRUE;
2454 Vcb->Volume->DeleteAccess = TRUE;
2455 Vcb->Volume->FsContext = (PVOID) Vcb;
2456 Vcb->Volume->FsContext2 = NULL;
2457 Vcb->Volume->Vpb = Vcb->Vpb;
2458
2459 FileSizes.AllocationSize.QuadPart =
2460 FileSizes.FileSize.QuadPart =
2461 FileSizes.ValidDataLength.QuadPart =
2462 Vcb->Header.AllocationSize.QuadPart;
2463
2464 CcInitializeCacheMap( Vcb->Volume,
2465 &FileSizes,
2466 TRUE,
2467 &(Ext2Global->CacheManagerNoOpCallbacks),
2468 Vcb );
2469
2470 /* initialize disk block LargetMcb and entry Mcb,
2471 it will raise an expcetion if failed */
2472 _SEH2_TRY {
2473 FsRtlInitializeLargeMcb(&(Vcb->Extents), PagedPool);
2474 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
2475 Status = STATUS_INSUFFICIENT_RESOURCES;
2476 DbgBreak();
2477 } _SEH2_END;
2478 if (!NT_SUCCESS(Status)) {
2479 _SEH2_LEAVE;
2480 }
2481 ExtentsInitialized = TRUE;
2482
2483 /* set block device */
2484 Vcb->bd.bd_dev = Vcb->RealDevice;
2485 Vcb->bd.bd_geo = Vcb->DiskGeometry;
2486 Vcb->bd.bd_part = Vcb->PartitionInformation;
2487 Vcb->bd.bd_volume = Vcb->Volume;
2488 Vcb->bd.bd_priv = (void *) Vcb;
2489 memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root));
2490 spin_lock_init(&Vcb->bd.bd_bh_lock);
2491 Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
2492 Vcb->BlockSize, 0, 0, NULL);
2493 if (!Vcb->bd.bd_bh_cache) {
2494 Status = STATUS_INSUFFICIENT_RESOURCES;
2495 _SEH2_LEAVE;
2496 }
2497
2498 Vcb->SectorBits = Ext2Log2(SECTOR_SIZE);
2499 Vcb->sb.s_magic = sb->s_magic;
2500 Vcb->sb.s_bdev = &Vcb->bd;
2501 Vcb->sb.s_blocksize = BLOCK_SIZE;
2502 Vcb->sb.s_blocksize_bits = BLOCK_BITS;
2503 Vcb->sb.s_priv = (void *) Vcb;
2504 Vcb->sb.s_fs_info = &Vcb->sbi;
2505
2506 Vcb->sbi.s_es = sb;
2507 Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
2508 Vcb->sbi.s_first_ino = sb->s_first_ino;
2509 Vcb->sbi.s_desc_size = sb->s_desc_size;
2510
2511 if (EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
2512 if (Vcb->sbi.s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
2513 Vcb->sbi.s_desc_size > EXT4_MAX_DESC_SIZE ||
2514 !is_power_of_2(Vcb->sbi.s_desc_size)) {
2515 DEBUG(DL_ERR, ("EXT4-fs: unsupported descriptor size %lu\n", Vcb->sbi.s_desc_size));
2516 Status = STATUS_DISK_CORRUPT_ERROR;
2517 _SEH2_LEAVE;
2518 }
2519 } else {
2520 Vcb->sbi.s_desc_size = EXT4_MIN_DESC_SIZE;
2521 }
2522
2523 Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
2524 Vcb->sbi.s_inodes_per_group = sb->s_inodes_per_group;
2525 if (EXT3_INODES_PER_GROUP(&Vcb->sb) == 0) {
2526 Status = STATUS_DISK_CORRUPT_ERROR;
2527 _SEH2_LEAVE;
2528 }
2529 Vcb->sbi.s_inodes_per_block = BLOCK_SIZE / Vcb->InodeSize;
2530 if (Vcb->sbi.s_inodes_per_block == 0) {
2531 Status = STATUS_DISK_CORRUPT_ERROR;
2532 _SEH2_LEAVE;
2533 }
2534 Vcb->sbi.s_itb_per_group = Vcb->sbi.s_inodes_per_group /
2535 Vcb->sbi.s_inodes_per_block;
2536
2537
2538 Vcb->sbi.s_desc_per_block = BLOCK_SIZE / GROUP_DESC_SIZE;
2539 Vcb->sbi.s_desc_per_block_bits = ilog2(Vcb->sbi.s_desc_per_block);
2540
2541 for (i=0; i < 4; i++) {
2542 Vcb->sbi.s_hash_seed[i] = sb->s_hash_seed[i];
2543 }
2544 Vcb->sbi.s_def_hash_version = sb->s_def_hash_version;
2545
2546 if (le32_to_cpu(sb->s_rev_level) == EXT3_GOOD_OLD_REV &&
2547 (EXT3_HAS_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
2548 EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
2549 EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~0U))) {
2550 printk(KERN_WARNING
2551 "EXT3-fs warning: feature flags set on rev 0 fs, "
2552 "running e2fsck is recommended\n");
2553 }
2554
2555 /*
2556 * Check feature flags regardless of the revision level, since we
2557 * previously didn't change the revision level when setting the flags,
2558 * so there is a chance incompat flags are set on a rev 0 filesystem.
2559 */
2560 features = EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
2561 if (features & EXT4_FEATURE_INCOMPAT_DIRDATA) {
2562 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2563 ClearFlag(features, EXT4_FEATURE_INCOMPAT_DIRDATA);
2564 }
2565 if (features) {
2566 printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of "
2567 "unsupported optional features (%x).\n",
2568 Vcb->sb.s_id, le32_to_cpu(features));
2569 Status = STATUS_UNRECOGNIZED_VOLUME;
2570 _SEH2_LEAVE;
2571 }
2572
2573 features = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
2574 if (features) {
2575 printk(KERN_ERR "EXT3-fs: %s: unsupported optional features in this volume: (%x).\n",
2576 Vcb->sb.s_id, le32_to_cpu(features));
2577 if (CanIWrite(Vcb)) {
2578 } else {
2579 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2580 }
2581 }
2582
2583 has_huge_files = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
2584
2585 Vcb->sb.s_maxbytes = ext3_max_size(BLOCK_BITS, has_huge_files);
2586 Vcb->max_bitmap_bytes = ext3_max_bitmap_size(BLOCK_BITS,
2587 has_huge_files);
2588 Vcb->max_bytes = ext3_max_size(BLOCK_BITS, has_huge_files);
2589
2590 /* calculate maximum file bocks ... */
2591 {
2592 ULONG dwData[EXT2_BLOCK_TYPES] = {EXT2_NDIR_BLOCKS, 1, 1, 1};
2593 ULONG i;
2594
2595 ASSERT(BLOCK_BITS == Ext2Log2(BLOCK_SIZE));
2596
2597 Vcb->sbi.s_groups_count = (ULONG)(ext3_blocks_count(sb) - sb->s_first_data_block +
2598 sb->s_blocks_per_group - 1) / sb->s_blocks_per_group;
2599
2600 Vcb->max_data_blocks = 0;
2601 for (i = 0; i < EXT2_BLOCK_TYPES; i++) {
2602 if (BLOCK_BITS >= 12 && i == (EXT2_BLOCK_TYPES - 1)) {
2603 dwData[i] = 0x40000000;
2604 } else {
2605 dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
2606 }
2607 Vcb->max_blocks_per_layer[i] = dwData[i];
2608 Vcb->max_data_blocks += Vcb->max_blocks_per_layer[i];
2609 }
2610 }
2611
2612 Vcb->sbi.s_gdb_count = (Vcb->sbi.s_groups_count + Vcb->sbi.s_desc_per_block - 1) /
2613 Vcb->sbi.s_desc_per_block;
2614 /* load all gorup desc */
2615 if (!Ext2LoadGroup(Vcb)) {
2616 Status = STATUS_UNSUCCESSFUL;
2617 _SEH2_LEAVE;
2618 }
2619
2620 /* recovery journal since it's ext3 */
2621 if (Vcb->IsExt3fs) {
2622 Ext2RecoverJournal(IrpContext, Vcb);
2623 if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) {
2624 SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
2625 }
2626 }
2627
2628 /* Now allocating the mcb for root ... */
2629 Buffer[0] = L'\\';
2630 Buffer[1] = 0;
2631 RootNode.Buffer = Buffer;
2632 RootNode.MaximumLength = RootNode.Length = 2;
2633 Vcb->McbTree = Ext2AllocateMcb(
2634 Vcb, &RootNode, NULL,
2635 FILE_ATTRIBUTE_DIRECTORY
2636 );
2637 if (!Vcb->McbTree) {
2638 DbgBreak();
2639 Status = STATUS_UNSUCCESSFUL;
2640 _SEH2_LEAVE;
2641 }
2642
2643 Vcb->sb.s_root = Ext2BuildEntry(Vcb, NULL, &RootNode);
2644 if (!Vcb->sb.s_root) {
2645 DbgBreak();
2646 Status = STATUS_UNSUCCESSFUL;
2647 _SEH2_LEAVE;
2648 }
2649 Vcb->sb.s_root->d_sb = &Vcb->sb;
2650 Vcb->sb.s_root->d_inode = &Vcb->McbTree->Inode;
2651 Vcb->McbTree->de = Vcb->sb.s_root;
2652
2653 /* load root inode */
2654 Vcb->McbTree->Inode.i_ino = EXT2_ROOT_INO;
2655 Vcb->McbTree->Inode.i_sb = &Vcb->sb;
2656 if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode)) {
2657 DbgBreak();
2658 Status = STATUS_CANT_WAIT;
2659 _SEH2_LEAVE;
2660 }
2661
2662 /* initializeroot node */
2663 Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
2664 Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
2665 Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
2666 Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
2667
2668 /* check bitmap if user specifies it */
2669 if (IsFlagOn(Ext2Global->Flags, EXT2_CHECKING_BITMAP)) {
2670 Ext2CheckBitmapConsistency(IrpContext, Vcb);
2671 }
2672
2673 /* get anything doen, then refer target device */
2674 ObReferenceObject(Vcb->TargetDeviceObject);
2675 SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
2676
2677 } _SEH2_FINALLY {
2678
2679 if (!NT_SUCCESS(Status)) {
2680
2681 if (Vcb->McbTree) {
2682 Ext2FreeMcb(Vcb, Vcb->McbTree);
2683 }
2684
2685 if (InodeLookasideInitialized) {
2686 ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
2687 }
2688
2689 if (ExtentsInitialized) {
2690 Ext2PutGroup(Vcb);
2691 if (Vcb->bd.bd_bh_cache)
2692 kmem_cache_destroy(Vcb->bd.bd_bh_cache);
2693 FsRtlUninitializeLargeMcb(&(Vcb->Extents));
2694 }
2695
2696 if (Vcb->Volume) {
2697 if (Vcb->Volume->PrivateCacheMap) {
2698 Ext2SyncUninitializeCacheMap(Vcb->Volume);
2699 }
2700 ObDereferenceObject(Vcb->Volume);
2701 }
2702
2703 if (NotifySyncInitialized) {
2704 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
2705 }
2706
2707 if (VcbResourceInitialized) {
2708 ExDeleteResourceLite(&Vcb->McbLock);
2709 ExDeleteResourceLite(&Vcb->MetaLock);
2710 ExDeleteResourceLite(&Vcb->MainResource);
2711 ExDeleteResourceLite(&Vcb->PagingIoResource);
2712 }
2713 }
2714 } _SEH2_END;
2715
2716 return Status;
2717 }
2718
2719
2720 VOID
2721 Ext2TearDownStream(IN PEXT2_VCB Vcb)
2722 {
2723 PFILE_OBJECT Stream = Vcb->Volume;
2724 IO_STATUS_BLOCK IoStatus;
2725
2726 ASSERT(Vcb != NULL);
2727 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2728 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2729
2730 if (Stream) {
2731
2732 Vcb->Volume = NULL;
2733
2734 if (IsFlagOn(Stream->Flags, FO_FILE_MODIFIED)) {
2735 CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
2736 ClearFlag(Stream->Flags, FO_FILE_MODIFIED);
2737 }
2738
2739 if (Stream->PrivateCacheMap) {
2740 Ext2SyncUninitializeCacheMap(Stream);
2741 }
2742
2743 ObDereferenceObject(Stream);
2744 }
2745 }
2746
2747 VOID
2748 Ext2DestroyVcb (IN PEXT2_VCB Vcb)
2749 {
2750 ASSERT(Vcb != NULL);
2751 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2752 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2753
2754 DEBUG(DL_FUN, ("Ext2DestroyVcb ...\n"));
2755
2756 if (Vcb->Volume) {
2757 Ext2TearDownStream(Vcb);
2758 }
2759 ASSERT(NULL == Vcb->Volume);
2760
2761 FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
2762 Ext2ListExtents(&Vcb->Extents);
2763 FsRtlUninitializeLargeMcb(&(Vcb->Extents));
2764
2765 Ext2CleanupAllMcbs(Vcb);
2766
2767 Ext2PutGroup(Vcb);
2768
2769 if (Vcb->bd.bd_bh_cache)
2770 kmem_cache_destroy(Vcb->bd.bd_bh_cache);
2771
2772 if (Vcb->SuperBlock) {
2773 Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
2774 Vcb->SuperBlock = NULL;
2775 }
2776
2777 if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
2778 ASSERT(Vcb->Vpb2 != NULL);
2779 Ext2FreePool(Vcb->Vpb2, TAG_VPB);
2780 DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
2781 Vcb->Vpb2 = NULL;
2782 }
2783
2784 ObDereferenceObject(Vcb->TargetDeviceObject);
2785
2786 ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
2787 ExDeleteResourceLite(&Vcb->McbLock);
2788 ExDeleteResourceLite(&Vcb->MetaLock);
2789 ExDeleteResourceLite(&Vcb->PagingIoResource);
2790 ExDeleteResourceLite(&Vcb->MainResource);
2791
2792 DEBUG(DL_DBG, ("Ext2DestroyVcb: DevObject=%p Vcb=%p\n", Vcb->DeviceObject, Vcb));
2793 IoDeleteDevice(Vcb->DeviceObject);
2794 DEC_MEM_COUNT(PS_VCB, Vcb->DeviceObject, sizeof(EXT2_VCB));
2795 }
2796
2797
2798 /* uninitialize cache map */
2799
2800 VOID
2801 Ext2SyncUninitializeCacheMap (
2802 IN PFILE_OBJECT FileObject
2803 )
2804 {
2805 CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
2806 NTSTATUS WaitStatus;
2807 LARGE_INTEGER Ext2LargeZero = {0,0};
2808
2809
2810 KeInitializeEvent( &UninitializeCompleteEvent.Event,
2811 SynchronizationEvent,
2812 FALSE);
2813
2814 CcUninitializeCacheMap( FileObject,
2815 &Ext2LargeZero,
2816 &UninitializeCompleteEvent );
2817
2818 WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
2819 Executive,
2820 KernelMode,
2821 FALSE,
2822 NULL);
2823
2824 ASSERT (NT_SUCCESS(WaitStatus));
2825 }
2826
2827 /* Link Mcb to tail of Vcb->McbList queue */
2828
2829 VOID
2830 Ext2LinkTailMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2831 {
2832 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2833 return;
2834 }
2835
2836 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2837
2838 if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2839 DEBUG(DL_RES, ( "Ext2LinkTailMcb: %wZ already linked.\n",
2840 &Mcb->FullName));
2841 } else {
2842 InsertTailList(&Vcb->McbList, &Mcb->Link);
2843 SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
2844 Ext2ReferXcb(&Vcb->NumOfMcb);
2845 }
2846
2847 ExReleaseResourceLite(&Vcb->McbLock);
2848 }
2849
2850 /* Link Mcb to head of Vcb->McbList queue */
2851
2852 VOID
2853 Ext2LinkHeadMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2854 {
2855 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2856 return;
2857 }
2858
2859 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2860
2861 if (!IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2862 InsertHeadList(&Vcb->McbList, &Mcb->Link);
2863 SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
2864 Ext2ReferXcb(&Vcb->NumOfMcb);
2865 } else {
2866 DEBUG(DL_RES, ( "Ext2LinkHeadMcb: %wZ already linked.\n",
2867 &Mcb->FullName));
2868 }
2869 ExReleaseResourceLite(&Vcb->McbLock);
2870 }
2871
2872 /* Unlink Mcb from Vcb->McbList queue */
2873
2874 VOID
2875 Ext2UnlinkMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
2876 {
2877 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
2878 return;
2879 }
2880
2881 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
2882
2883 if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
2884 RemoveEntryList(&(Mcb->Link));
2885 ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
2886 Ext2DerefXcb(&Vcb->NumOfMcb);
2887 } else {
2888 DEBUG(DL_RES, ( "Ext2UnlinkMcb: %wZ already unlinked.\n",
2889 &Mcb->FullName));
2890 }
2891 ExReleaseResourceLite(&Vcb->McbLock);
2892 }
2893
2894 /* get the first Mcb record in Vcb->McbList */
2895
2896 PEXT2_MCB
2897 Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
2898 {
2899 PEXT2_MCB Head = NULL;
2900 PEXT2_MCB Tail = NULL;
2901 PEXT2_MCB Mcb = NULL;
2902 PLIST_ENTRY List = NULL;
2903 ULONG i = 0;
2904
2905 if (!ExAcquireResourceExclusiveLite(&Vcb->McbLock, Wait)) {
2906 return NULL;
2907 }
2908
2909 while (Number--) {
2910
2911 if (!IsListEmpty(&Vcb->McbList)) {
2912
2913 while (i++ < Vcb->NumOfMcb) {
2914
2915 List = RemoveHeadList(&Vcb->McbList);
2916 Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link);
2917 ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK));
2918
2919 if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) &&
2920 Mcb->Refercount == 0 &&
2921 (Mcb->Child == NULL || IsMcbSymLink(Mcb))) {
2922
2923 Ext2RemoveMcb(Vcb, Mcb);
2924 ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
2925 Ext2DerefXcb(&Vcb->NumOfMcb);
2926
2927 /* attach all Mcb into a chain*/
2928 if (Head) {
2929 ASSERT(Tail != NULL);
2930 Tail->Next = Mcb;
2931 Tail = Mcb;
2932 } else {
2933 Head = Tail = Mcb;
2934 }
2935 Tail->Next = NULL;
2936
2937 } else {
2938
2939 InsertTailList(&Vcb->McbList, &Mcb->Link);
2940 Mcb = NULL;
2941 }
2942 }
2943 }
2944 }
2945 ExReleaseResourceLite(&Vcb->McbLock);
2946
2947 return Head;
2948 }
2949
2950
2951 /* Reaper thread to release unused Mcb blocks */
2952 VOID NTAPI
2953 Ext2ReaperThread(
2954 PVOID Context
2955 )
2956 {
2957 BOOLEAN GlobalAcquired = FALSE;
2958
2959 BOOLEAN DidNothing = TRUE;
2960 BOOLEAN LastState = TRUE;
2961 BOOLEAN WaitLock;
2962
2963 PLIST_ENTRY List = NULL;
2964 LARGE_INTEGER Timeout;
2965
2966 PEXT2_VCB Vcb = NULL;
2967 PEXT2_MCB Mcb = NULL;
2968
2969 ULONG i, NumOfMcbs;
2970
2971 _SEH2_TRY {
2972
2973 /* wake up DirverEntry */
2974 KeSetEvent(&Ext2Global->Reaper.Engine, 0, FALSE);
2975
2976 /* now process looping */
2977 while (TRUE) {
2978
2979 WaitLock = FALSE;
2980
2981 /* calculate how long we need wait */
2982 if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 128)) {
2983 Timeout.QuadPart = (LONGLONG)-1000*1000; /* 0.1 second */
2984 NumOfMcbs = Ext2Global->MaxDepth * 4;
2985 WaitLock = TRUE;
2986 } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 32)) {
2987 Timeout.QuadPart = (LONGLONG)-1000*1000*5; /* 0.5 second */
2988 NumOfMcbs = Ext2Global->MaxDepth * 2;
2989 WaitLock = TRUE;
2990 } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 8)) {
2991 Timeout.QuadPart = (LONGLONG)-1000*1000*10; /* 1 second */
2992 NumOfMcbs = Ext2Global->MaxDepth;
2993 } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 2)) {
2994 Timeout.QuadPart = (LONGLONG)-2*1000*1000*10; /* 2 second */
2995 NumOfMcbs = Ext2Global->MaxDepth / 4;
2996 } else if (Ext2Global->PerfStat.Current.Mcb > (ULONG)Ext2Global->MaxDepth) {
2997 Timeout.QuadPart = (LONGLONG)-4*1000*1000*10; /* 4 seconds */
2998 NumOfMcbs = Ext2Global->MaxDepth / 8;
2999 } else if (DidNothing) {
3000 Timeout.QuadPart = (LONGLONG)-8*1000*1000*10; /* 8 seconds */
3001 if (LastState) {
3002 Timeout.QuadPart *= 2;
3003 }
3004 NumOfMcbs = Ext2Global->MaxDepth / 16;
3005 } else {
3006 Timeout.QuadPart = (LONGLONG)-5*1000*1000*10; /* 5 seconds */
3007 if (LastState) {
3008 Timeout.QuadPart *= 2;
3009 }
3010 NumOfMcbs = Ext2Global->MaxDepth / 32;
3011 }
3012
3013 if (NumOfMcbs == 0)
3014 NumOfMcbs = 1;
3015
3016 LastState = DidNothing;
3017
3018 /* wait until it is waken or it times out */
3019 KeWaitForSingleObject(
3020 &(Ext2Global->Reaper.Wait),
3021 Executive,
3022 KernelMode,
3023 FALSE,
3024 &Timeout
3025 );
3026
3027 DidNothing = TRUE;
3028
3029 /* acquire global exclusive lock */
3030 if (!ExAcquireResourceSharedLite(&Ext2Global->Resource, WaitLock)) {
3031 continue;
3032 }
3033 GlobalAcquired = TRUE;
3034
3035 /* search all Vcb to get unused resources freed to system */
3036 for (List = Ext2Global->VcbList.Flink;
3037 List != &(Ext2Global->VcbList);
3038 List = List->Flink ) {
3039
3040 Vcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
3041
3042 Mcb = Ext2FirstUnusedMcb(Vcb, WaitLock, NumOfMcbs);
3043 while (Mcb) {
3044 PEXT2_MCB Next = Mcb->Next;
3045 DEBUG(DL_RES, ( "Ext2ReaperThread: releasing Mcb (%p): %wZ"
3046 " Total: %xh\n", Mcb, &Mcb->FullName,
3047 Ext2Global->PerfStat.Current.Mcb));
3048 Ext2FreeMcb(Vcb, Mcb);
3049 Mcb = Next;
3050 LastState = DidNothing = FALSE;
3051 }
3052 }
3053
3054 if (GlobalAcquired) {
3055 ExReleaseResourceLite(&Ext2Global->Resource);
3056 GlobalAcquired = FALSE;
3057 }
3058 }
3059
3060 } _SEH2_FINALLY {
3061
3062 if (GlobalAcquired) {
3063 ExReleaseResourceLite(&Ext2Global->Resource);
3064 }
3065 } _SEH2_END;
3066
3067 PsTerminateSystemThread(STATUS_SUCCESS);
3068 }
3069
3070
3071 NTSTATUS
3072 Ext2StartReaperThread()
3073 {
3074 NTSTATUS status = STATUS_SUCCESS;
3075 OBJECT_ATTRIBUTES oa;
3076 HANDLE handle = 0;
3077
3078 /* initialize wait event */
3079 KeInitializeEvent(
3080 &Ext2Global->Reaper.Wait,
3081 SynchronizationEvent, FALSE
3082 );
3083
3084 /* initialize oa */
3085 InitializeObjectAttributes(
3086 &oa,
3087 NULL,
3088 OBJ_CASE_INSENSITIVE |
3089 OBJ_KERNEL_HANDLE,
3090 NULL,
3091 NULL
3092 );
3093
3094 /* start a new system thread */
3095 status = PsCreateSystemThread(
3096 &handle,
3097 0,
3098 &oa,
3099 NULL,
3100 NULL,
3101 Ext2ReaperThread,
3102 NULL
3103 );
3104
3105 if (NT_SUCCESS(status)) {
3106 ZwClose(handle);
3107 }
3108
3109 return status;
3110 }