[EXT2]
[reactos.git] / reactos / drivers / filesystems / ext2 / src / fsctl.c
1 /*
2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
4 * FILE: fsctl.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, Ext2IsHandleCountZero)
22 #pragma alloc_text(PAGE, Ext2LockVcb)
23 #pragma alloc_text(PAGE, Ext2LockVolume)
24 #pragma alloc_text(PAGE, Ext2UnlockVcb)
25 #pragma alloc_text(PAGE, Ext2UnlockVolume)
26 #pragma alloc_text(PAGE, Ext2AllowExtendedDasdIo)
27 #pragma alloc_text(PAGE, Ext2GetRetrievalPointerBase)
28 #pragma alloc_text(PAGE, Ext2QueryExtentMappings)
29 #pragma alloc_text(PAGE, Ext2QueryRetrievalPointers)
30 #pragma alloc_text(PAGE, Ext2GetRetrievalPointers)
31 #pragma alloc_text(PAGE, Ext2UserFsRequest)
32 #pragma alloc_text(PAGE, Ext2IsMediaWriteProtected)
33 #pragma alloc_text(PAGE, Ext2MountVolume)
34 #pragma alloc_text(PAGE, Ext2PurgeVolume)
35 #pragma alloc_text(PAGE, Ext2PurgeFile)
36 #pragma alloc_text(PAGE, Ext2DismountVolume)
37 #pragma alloc_text(PAGE, Ext2IsVolumeMounted)
38 #pragma alloc_text(PAGE, Ext2VerifyVolume)
39 #pragma alloc_text(PAGE, Ext2FileSystemControl)
40 #endif
41
42
43 VOID
44 Ext2SetVpbFlag (
45 IN PVPB Vpb,
46 IN USHORT Flag )
47 {
48 KIRQL OldIrql;
49
50 IoAcquireVpbSpinLock(&OldIrql);
51 Vpb->Flags |= Flag;
52 IoReleaseVpbSpinLock(OldIrql);
53 }
54
55 VOID
56 Ext2ClearVpbFlag (
57 IN PVPB Vpb,
58 IN USHORT Flag )
59 {
60 KIRQL OldIrql;
61
62 IoAcquireVpbSpinLock(&OldIrql);
63 Vpb->Flags &= ~Flag;
64 IoReleaseVpbSpinLock(OldIrql);
65 }
66
67 BOOLEAN
68 Ext2IsHandleCountZero(IN PEXT2_VCB Vcb)
69 {
70 PEXT2_FCB Fcb;
71 PLIST_ENTRY List;
72
73 for ( List = Vcb->FcbList.Flink;
74 List != &Vcb->FcbList;
75 List = List->Flink ) {
76
77 Fcb = CONTAINING_RECORD(List, EXT2_FCB, Next);
78
79 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
80 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
81
82 DEBUG(DL_INF, ( "Ext2IsHandleCountZero: Inode:%xh File:%S OpenHandleCount=%xh\n",
83 Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer, Fcb->OpenHandleCount));
84
85 if (Fcb->OpenHandleCount) {
86 return FALSE;
87 }
88 }
89
90 return TRUE;
91 }
92
93 NTSTATUS
94 Ext2LockVcb (IN PEXT2_VCB Vcb,
95 IN PFILE_OBJECT FileObject)
96 {
97 NTSTATUS Status = STATUS_SUCCESS;
98
99 _SEH2_TRY {
100
101 if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
102 DEBUG(DL_INF, ( "Ext2LockVolume: Volume is already locked.\n"));
103 Status = STATUS_ACCESS_DENIED;
104 _SEH2_LEAVE;
105 }
106
107 if (Vcb->OpenHandleCount > (ULONG)(FileObject ? 1 : 0)) {
108 DEBUG(DL_INF, ( "Ext2LockVcb: There are still opened files.\n"));
109
110 Status = STATUS_ACCESS_DENIED;
111 _SEH2_LEAVE;
112 }
113
114 if (!Ext2IsHandleCountZero(Vcb)) {
115 DEBUG(DL_INF, ( "Ext2LockVcb: Thare are still opened files.\n"));
116
117 Status = STATUS_ACCESS_DENIED;
118 _SEH2_LEAVE;
119 }
120
121 SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
122 Ext2SetVpbFlag(Vcb->Vpb, VPB_LOCKED);
123 Vcb->LockFile = FileObject;
124
125 DEBUG(DL_INF, ( "Ext2LockVcb: Volume locked.\n"));
126
127 } _SEH2_FINALLY {
128 // Nothing
129 } _SEH2_END;
130
131 return Status;
132 }
133
134
135 NTSTATUS
136 Ext2LockVolume (IN PEXT2_IRP_CONTEXT IrpContext)
137 {
138 PIO_STACK_LOCATION IrpSp;
139 PDEVICE_OBJECT DeviceObject;
140 PEXT2_VCB Vcb = NULL;
141 NTSTATUS Status;
142 BOOLEAN VcbResourceAcquired = FALSE;
143
144 _SEH2_TRY {
145
146 ASSERT(IrpContext != NULL);
147
148 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
149 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
150
151 DeviceObject = IrpContext->DeviceObject;
152
153 Status = STATUS_UNSUCCESSFUL;
154
155 //
156 // This request is not allowed on the main device object
157 //
158 if (IsExt2FsDevice(DeviceObject)) {
159 Status = STATUS_INVALID_PARAMETER;
160 _SEH2_LEAVE;
161 }
162
163 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
164
165 ASSERT(Vcb != NULL);
166
167 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
168 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
169
170 ASSERT(IsMounted(Vcb));
171
172 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
173
174 #if (_WIN32_WINNT >= 0x0500)
175 CcWaitForCurrentLazyWriterActivity();
176 #endif
177 ExAcquireResourceExclusiveLite(
178 &Vcb->MainResource,
179 TRUE );
180
181 VcbResourceAcquired = TRUE;
182
183 /* flush dirty data before locking the volume */
184 if (!IsVcbReadOnly(Vcb)) {
185 Ext2FlushFiles(IrpContext, Vcb, FALSE);
186 Ext2FlushVolume(IrpContext, Vcb, FALSE);
187 }
188
189 Status = Ext2LockVcb(Vcb, IrpSp->FileObject);
190
191 } _SEH2_FINALLY {
192
193 if (VcbResourceAcquired) {
194 ExReleaseResourceLite(&Vcb->MainResource);
195 }
196
197 if (!IrpContext->ExceptionInProgress) {
198 Ext2CompleteIrpContext(IrpContext, Status);
199 }
200 } _SEH2_END;
201
202 return Status;
203 }
204
205 NTSTATUS
206 Ext2UnlockVcb ( IN PEXT2_VCB Vcb,
207 IN PFILE_OBJECT FileObject )
208 {
209 NTSTATUS Status;
210
211 _SEH2_TRY {
212
213 if (FileObject && FileObject->FsContext != Vcb) {
214 Status = STATUS_NOT_LOCKED;
215 _SEH2_LEAVE;
216 }
217
218 if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
219 DEBUG(DL_ERR, ( ": Ext2UnlockVcb: Volume is not locked.\n"));
220 Status = STATUS_NOT_LOCKED;
221 _SEH2_LEAVE;
222 }
223
224 if (Vcb->LockFile == FileObject) {
225 ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
226 Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
227 DEBUG(DL_INF, ( "Ext2UnlockVcb: Volume unlocked.\n"));
228 Status = STATUS_SUCCESS;
229 } else {
230 Status = STATUS_NOT_LOCKED;
231 }
232
233 } _SEH2_FINALLY {
234 // Nothing
235 } _SEH2_END;
236
237 return Status;
238 }
239
240 NTSTATUS
241 Ext2UnlockVolume (
242 IN PEXT2_IRP_CONTEXT IrpContext
243 )
244 {
245 PIO_STACK_LOCATION IrpSp = NULL;
246 PDEVICE_OBJECT DeviceObject = NULL;
247 PEXT2_VCB Vcb = NULL;
248 NTSTATUS Status;
249 BOOLEAN VcbResourceAcquired = FALSE;
250
251 _SEH2_TRY {
252
253 ASSERT(IrpContext != NULL);
254 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
255 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
256
257 DeviceObject = IrpContext->DeviceObject;
258 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
259
260 //
261 // This request is not allowed on the main device object
262 //
263 if (IsExt2FsDevice(DeviceObject)) {
264 Status = STATUS_INVALID_PARAMETER;
265 _SEH2_LEAVE;
266 }
267
268 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
269 ASSERT(Vcb != NULL);
270 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
271 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
272
273 ExAcquireResourceExclusiveLite(
274 &Vcb->MainResource,
275 TRUE );
276 VcbResourceAcquired = TRUE;
277
278 Status = Ext2UnlockVcb(Vcb, IrpSp->FileObject);
279
280 } _SEH2_FINALLY {
281
282 if (VcbResourceAcquired) {
283 ExReleaseResourceLite(&Vcb->MainResource);
284 }
285
286 if (!IrpContext->ExceptionInProgress) {
287 Ext2CompleteIrpContext(IrpContext, Status);
288 }
289 } _SEH2_END;
290
291 return Status;
292 }
293
294
295 NTSTATUS
296 Ext2InvalidateVolumes ( IN PEXT2_IRP_CONTEXT IrpContext )
297 {
298 NTSTATUS Status;
299 PIRP Irp;
300 PIO_STACK_LOCATION IrpSp;
301
302 #ifndef __REACTOS__
303 PVPB NewVpb = NULL;
304 #endif
305 HANDLE Handle;
306 PLIST_ENTRY ListEntry;
307
308 ULONG InputLength = 0;
309 PFILE_OBJECT FileObject;
310 PDEVICE_OBJECT DeviceObject;
311 BOOLEAN GlobalResourceAcquired = FALSE;
312
313 LUID Privilege = {SE_TCB_PRIVILEGE, 0};
314
315 _SEH2_TRY {
316
317 Irp = IrpContext->Irp;
318 IrpSp = IoGetCurrentIrpStackLocation(Irp);
319
320 if (!IsExt2FsDevice(IrpSp->DeviceObject)) {
321 Status = STATUS_INVALID_DEVICE_REQUEST;
322 _SEH2_LEAVE;
323 }
324
325 if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) {
326 Status = STATUS_PRIVILEGE_NOT_HELD;
327 _SEH2_LEAVE;
328 }
329
330
331 #ifndef _GNU_NTIFS_
332 InputLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
333 #else
334 InputLength = ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))->
335 Parameters.FileSystemControl.InputBufferLength;
336 #endif
337
338 #if defined(_WIN64)
339 if (IoIs32bitProcess(Irp)) {
340 if (InputLength != sizeof(UINT32)) {
341 Status = STATUS_INVALID_PARAMETER;
342 _SEH2_LEAVE;
343 }
344 Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) );
345 } else
346 #endif
347 {
348 if (InputLength != sizeof(HANDLE)) {
349 Status = STATUS_INVALID_PARAMETER;
350 _SEH2_LEAVE;
351 }
352 Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
353 }
354
355 Status = ObReferenceObjectByHandle( Handle,
356 0,
357 *IoFileObjectType,
358 KernelMode,
359 (void **)&FileObject,
360 NULL );
361
362 if (!NT_SUCCESS(Status)) {
363 _SEH2_LEAVE;
364 } else {
365 DeviceObject = FileObject->DeviceObject;
366 ObDereferenceObject(FileObject);
367 }
368
369 ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE);
370 GlobalResourceAcquired = TRUE;
371
372 ListEntry = Ext2Global->VcbList.Flink;
373 while (ListEntry != &Ext2Global->VcbList) {
374
375 PEXT2_VCB Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next);
376 ListEntry = ListEntry->Flink;
377
378 DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh "
379 "Blink = %p &Vcb->Next = %p\n",
380 Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
381
382 if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) {
383
384 DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Got Vcb=%xh Vcb->Vpb=%xh "
385 "Blink = %p &Vcb->Next = %p\n",
386 Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
387 /* dismount the volume */
388 Ext2CheckDismount(IrpContext, Vcb, FALSE);
389 }
390 }
391
392 } _SEH2_FINALLY {
393
394 if (GlobalResourceAcquired) {
395 ExReleaseResourceLite(&Ext2Global->Resource);
396 }
397
398 if (!IrpContext->ExceptionInProgress) {
399 Ext2CompleteIrpContext(IrpContext, Status);
400 }
401 } _SEH2_END;
402
403 return Status;
404 }
405
406 NTSTATUS
407 Ext2AllowExtendedDasdIo(IN PEXT2_IRP_CONTEXT IrpContext)
408 {
409 PIO_STACK_LOCATION IrpSp;
410 PEXT2_VCB Vcb;
411 PEXT2_CCB Ccb;
412 NTSTATUS status;
413
414 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
415
416 Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext;
417 Ccb = (PEXT2_CCB) IrpSp->FileObject->FsContext2;
418
419 ASSERT(Vcb != NULL);
420
421 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
422 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
423
424 ASSERT(IsMounted(Vcb));
425
426 if (Ccb) {
427 SetLongFlag(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO);
428 status = STATUS_SUCCESS;
429 } else {
430 status = STATUS_INVALID_PARAMETER;
431 }
432
433 Ext2CompleteIrpContext(IrpContext, status);
434 return status;
435 }
436
437 /*
438 * Ext2OplockRequest
439 *
440 * oplock requests handler routine
441 *
442 * Arguments:
443 * IrpContext: the ext2 irp context
444 *
445 * Return Value:
446 * NTSTATUS: The return status for the operation
447 *
448 */
449
450 NTSTATUS
451 Ext2OplockRequest (
452 IN PEXT2_IRP_CONTEXT IrpContext
453 )
454 {
455 NTSTATUS Status;
456
457 ULONG FsCtrlCode;
458 PDEVICE_OBJECT DeviceObject;
459 PFILE_OBJECT FileObject;
460
461 PIRP Irp = NULL;
462 PIO_STACK_LOCATION IrpSp;
463 PEXTENDED_IO_STACK_LOCATION EIrpSp;
464
465 PEXT2_VCB Vcb = NULL;
466 PEXT2_FCB Fcb = NULL;
467 PEXT2_CCB Ccb = NULL;
468
469 ULONG OplockCount = 0;
470
471 BOOLEAN VcbResourceAcquired = FALSE;
472 BOOLEAN FcbResourceAcquired = FALSE;
473
474 ASSERT(IrpContext);
475
476 _SEH2_TRY {
477
478 Irp = IrpContext->Irp;
479 ASSERT(Irp);
480
481 IrpSp = IoGetCurrentIrpStackLocation(Irp);
482 ASSERT(IrpSp);
483 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
484
485 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
486 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
487
488 DeviceObject = IrpContext->DeviceObject;
489
490 //
491 // This request is not allowed on the main device object
492 //
493 if (IsExt2FsDevice(DeviceObject)) {
494 Status = STATUS_INVALID_DEVICE_REQUEST;
495 _SEH2_LEAVE;
496 }
497
498 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
499
500 ASSERT(Vcb != NULL);
501
502 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
503 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
504
505 ASSERT(IsMounted(Vcb));
506
507 FileObject = IrpContext->FileObject;
508
509 Fcb = (PEXT2_FCB) FileObject->FsContext;
510
511 //
512 // This request is not allowed on volumes
513 //
514
515 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
516 Status = STATUS_INVALID_PARAMETER;
517 _SEH2_LEAVE;
518 }
519
520 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
521 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
522
523 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
524 Status = STATUS_FILE_DELETED;
525 _SEH2_LEAVE;
526 }
527
528 Ccb = (PEXT2_CCB) FileObject->FsContext2;
529 if (Ccb == NULL) {
530 Status = STATUS_INVALID_PARAMETER;
531 _SEH2_LEAVE;
532 }
533
534
535 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
536 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
537
538 FsCtrlCode = EIrpSp->Parameters.FileSystemControl.FsControlCode;
539
540 switch (FsCtrlCode) {
541
542 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
543 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
544 case FSCTL_REQUEST_BATCH_OPLOCK:
545
546 VcbResourceAcquired =
547 ExAcquireResourceSharedLite(
548 &Vcb->MainResource,
549 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
550
551 ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
552
553 FcbResourceAcquired =
554 ExAcquireResourceExclusiveLite (
555 &Fcb->MainResource,
556 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
557
558 if (FsCtrlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
559 OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks(&Fcb->FileLockAnchor);
560 } else {
561 OplockCount = Fcb->OpenHandleCount;
562 }
563
564 break;
565
566 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
567 case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
568 case FSCTL_OPLOCK_BREAK_NOTIFY:
569 case FSCTL_OPLOCK_BREAK_ACK_NO_2:
570
571 FcbResourceAcquired =
572 ExAcquireResourceSharedLite (
573 &Fcb->MainResource,
574 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
575
576 break;
577
578 default:
579
580 Ext2BugCheck(EXT2_BUGCHK_FSCTL, FsCtrlCode, 0, 0);
581 }
582
583
584 //
585 // Call the FsRtl routine to grant/acknowledge oplock.
586 //
587
588 Status = FsRtlOplockFsctrl( &Fcb->Oplock,
589 Irp,
590 OplockCount );
591
592 //
593 // Set the flag indicating if Fast I/O is possible
594 //
595
596 Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
597 IrpContext->Irp = NULL;
598
599 } _SEH2_FINALLY {
600
601 if (FcbResourceAcquired) {
602 ExReleaseResourceLite(&Fcb->MainResource);
603 }
604
605 if (VcbResourceAcquired) {
606 ExReleaseResourceLite(&Vcb->MainResource);
607 }
608
609 if (!_SEH2_AbnormalTermination()) {
610 Ext2CompleteIrpContext(IrpContext, Status);
611 }
612 } _SEH2_END;
613
614 return Status;
615 }
616
617 NTSTATUS
618 Ext2IsVolumeDirty (
619 IN PEXT2_IRP_CONTEXT IrpContext
620 )
621 {
622 NTSTATUS status = STATUS_SUCCESS;
623 PIRP Irp;
624 PEXTENDED_IO_STACK_LOCATION IrpSp;
625 PULONG VolumeState;
626
627 _SEH2_TRY {
628
629 Irp = IrpContext->Irp;
630 IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
631
632 //
633 // Get a pointer to the output buffer. Look at the system buffer field in th
634 // irp first. Then the Irp Mdl.
635 //
636
637 if (Irp->AssociatedIrp.SystemBuffer != NULL) {
638
639 VolumeState = Irp->AssociatedIrp.SystemBuffer;
640
641 } else if (Irp->MdlAddress != NULL) {
642
643 VolumeState = MmGetSystemAddressForMdl( Irp->MdlAddress );
644
645 } else {
646
647 status = STATUS_INVALID_USER_BUFFER;
648 _SEH2_LEAVE;
649 }
650
651 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
652 status = STATUS_INVALID_PARAMETER;
653 _SEH2_LEAVE;
654 }
655
656 *VolumeState = 0;
657
658 } _SEH2_FINALLY {
659
660 if (!IrpContext->ExceptionInProgress) {
661 Ext2CompleteIrpContext(IrpContext, status);
662 }
663 } _SEH2_END;
664
665 return status;
666 }
667
668
669 NTSTATUS
670 Ext2QueryExtentMappings(
671 IN PEXT2_IRP_CONTEXT IrpContext,
672 IN PEXT2_VCB Vcb,
673 IN PEXT2_FCB Fcb,
674 IN PLARGE_INTEGER RequestVbn,
675 OUT PLARGE_INTEGER * pMappedRuns
676 )
677 {
678 PLARGE_INTEGER MappedRuns = NULL;
679 PLARGE_INTEGER PartialRuns = NULL;
680
681 PEXT2_EXTENT Chain = NULL;
682 PEXT2_EXTENT Extent = NULL;
683
684 LONGLONG Vbn = 0;
685 ULONG Length = 0;
686 ULONG i = 0;
687
688 NTSTATUS Status = STATUS_SUCCESS;
689
690 _SEH2_TRY {
691
692 /* now building all the request extents */
693 while (Vbn < RequestVbn->QuadPart) {
694
695 Length = 0x80000000; /* 2g bytes */
696 if (RequestVbn->QuadPart < Vbn + Length) {
697 Length = (ULONG)(RequestVbn->QuadPart - Vbn);
698 }
699
700 /* build extents for sub-range */
701 Extent = NULL;
702 Status = Ext2BuildExtents(
703 IrpContext,
704 Vcb,
705 Fcb->Mcb,
706 Vbn,
707 Length,
708 FALSE,
709 &Extent);
710
711 if (!NT_SUCCESS(Status)) {
712 _SEH2_LEAVE;
713 }
714
715 if (Chain) {
716 Ext2JointExtents(Chain, Extent);
717 } else {
718 Chain = Extent;
719 }
720
721 /* allocate extent array */
722 PartialRuns = Ext2AllocatePool(
723 NonPagedPool,
724 (Ext2CountExtents(Chain) + 2) *
725 (2 * sizeof(LARGE_INTEGER)),
726 'RE2E');
727
728 if (PartialRuns == NULL) {
729 Status = STATUS_INSUFFICIENT_RESOURCES;
730 _SEH2_LEAVE;
731 }
732 RtlZeroMemory( PartialRuns,
733 (Ext2CountExtents(Chain) + 2) *
734 (2 * sizeof(LARGE_INTEGER)));
735
736 if (MappedRuns) {
737 RtlMoveMemory(PartialRuns,
738 MappedRuns,
739 i * 2 * sizeof(LARGE_INTEGER));
740 Ext2FreePool(MappedRuns, 'RE2E');
741 }
742 MappedRuns = PartialRuns;
743
744 /* walk all the Mcb runs in Extent */
745 for (; Extent != NULL; Extent = Extent->Next) {
746 MappedRuns[i*2 + 0].QuadPart = Vbn + Extent->Offset;
747 MappedRuns[i*2 + 1].QuadPart = Extent->Lba;
748 i = i+1;
749 }
750
751 Vbn = Vbn + Length;
752 }
753
754 *pMappedRuns = MappedRuns;
755
756 } _SEH2_FINALLY {
757
758 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) {
759 if (MappedRuns) {
760 Ext2FreePool(MappedRuns, 'RE2E');
761 }
762 *pMappedRuns = NULL;
763 }
764
765 if (Chain) {
766 Ext2DestroyExtentChain(Chain);
767 }
768 } _SEH2_END;
769
770 return Status;
771 }
772
773 NTSTATUS
774 Ext2QueryRetrievalPointers (
775 IN PEXT2_IRP_CONTEXT IrpContext
776 )
777 {
778 PIRP Irp = NULL;
779 PIO_STACK_LOCATION IrpSp;
780 PEXTENDED_IO_STACK_LOCATION EIrpSp;
781
782 PDEVICE_OBJECT DeviceObject;
783 PFILE_OBJECT FileObject;
784
785 PEXT2_VCB Vcb = NULL;
786 PEXT2_FCB Fcb = NULL;
787 PEXT2_CCB Ccb = NULL;
788
789 PLARGE_INTEGER RequestVbn;
790 PLARGE_INTEGER * pMappedRuns;
791
792 ULONG InputSize;
793 ULONG OutputSize;
794
795 NTSTATUS Status = STATUS_SUCCESS;
796
797 BOOLEAN FcbResourceAcquired = FALSE;
798
799 _SEH2_TRY {
800
801 ASSERT(IrpContext);
802 Irp = IrpContext->Irp;
803 ASSERT(Irp);
804
805 IrpSp = IoGetCurrentIrpStackLocation(Irp);
806 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
807 ASSERT(IrpSp);
808
809 InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
810 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
811
812 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
813 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
814
815 DeviceObject = IrpContext->DeviceObject;
816
817 DbgBreak();
818
819 /* This request is not allowed on the main device object */
820 if (IsExt2FsDevice(DeviceObject)) {
821 Status = STATUS_INVALID_DEVICE_REQUEST;
822 _SEH2_LEAVE;
823 }
824
825 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
826 ASSERT(Vcb != NULL);
827 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
828 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
829 ASSERT(IsMounted(Vcb));
830
831 FileObject = IrpContext->FileObject;
832 Fcb = (PEXT2_FCB) FileObject->FsContext;
833
834 /* check Fcb is valid or not */
835 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
836 Status = STATUS_INVALID_PARAMETER;
837 _SEH2_LEAVE;
838 }
839
840 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
841 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
842 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
843 Status = STATUS_FILE_DELETED;
844 _SEH2_LEAVE;
845 }
846
847 Ccb = (PEXT2_CCB) FileObject->FsContext2;
848 if (Ccb == NULL) {
849 Status = STATUS_INVALID_PARAMETER;
850 _SEH2_LEAVE;
851 }
852
853 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
854 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
855
856 /* Is requstor in kernel and Fcb a paging file ? */
857 if (Irp->RequestorMode != KernelMode ||
858 !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) ||
859 InputSize != sizeof(LARGE_INTEGER) ||
860 OutputSize != sizeof(PVOID)) {
861 Status = STATUS_INVALID_PARAMETER;
862 _SEH2_LEAVE;
863 }
864
865 if (!ExAcquireResourceExclusiveLite (
866 &Fcb->MainResource, Ext2CanIWait())) {
867 Status = STATUS_PENDING;
868 _SEH2_LEAVE;
869 }
870 FcbResourceAcquired = TRUE;
871
872 RequestVbn = EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
873 pMappedRuns = Irp->UserBuffer;
874
875 DbgBreak();
876
877 /* request size beyonds whole file size */
878 if (RequestVbn->QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
879 Status = STATUS_END_OF_FILE;
880 _SEH2_LEAVE;
881 }
882
883 Status = Ext2QueryExtentMappings(
884 IrpContext,
885 Vcb,
886 Fcb,
887 RequestVbn,
888 pMappedRuns
889 );
890
891 } _SEH2_FINALLY {
892
893 if (FcbResourceAcquired) {
894 ExReleaseResourceLite(&Fcb->MainResource);
895 }
896
897 if (!_SEH2_AbnormalTermination()) {
898 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
899 Status = Ext2QueueRequest(IrpContext);
900 } else {
901 Ext2CompleteIrpContext(IrpContext, Status);
902 }
903 }
904 } _SEH2_END;
905
906 return Status;
907 }
908
909
910 NTSTATUS
911 Ext2GetRetrievalPointers (
912 IN PEXT2_IRP_CONTEXT IrpContext
913 )
914 {
915 PIRP Irp = NULL;
916 PIO_STACK_LOCATION IrpSp;
917 PEXTENDED_IO_STACK_LOCATION EIrpSp;
918
919 PDEVICE_OBJECT DeviceObject;
920 PFILE_OBJECT FileObject;
921
922 PEXT2_VCB Vcb = NULL;
923 PEXT2_FCB Fcb = NULL;
924 PEXT2_CCB Ccb = NULL;
925
926 PSTARTING_VCN_INPUT_BUFFER SVIB;
927 PRETRIEVAL_POINTERS_BUFFER RPSB;
928
929 PEXT2_EXTENT Chain = NULL;
930 PEXT2_EXTENT Extent = NULL;
931
932 LONGLONG Vbn = 0;
933 ULONG Length = 0;
934 ULONG i = 0;
935
936 ULONG UsedSize = 0;
937 ULONG InputSize;
938 ULONG OutputSize;
939
940 NTSTATUS Status = STATUS_SUCCESS;
941
942 BOOLEAN FcbResourceAcquired = FALSE;
943
944 _SEH2_TRY {
945
946 ASSERT(IrpContext);
947 Irp = IrpContext->Irp;
948 ASSERT(Irp);
949
950 IrpSp = IoGetCurrentIrpStackLocation(Irp);
951 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
952 ASSERT(IrpSp);
953
954 InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
955 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
956
957 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
958 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
959
960 DeviceObject = IrpContext->DeviceObject;
961
962 /* This request is not allowed on the main device object */
963 if (IsExt2FsDevice(DeviceObject)) {
964 Status = STATUS_INVALID_DEVICE_REQUEST;
965 _SEH2_LEAVE;
966 }
967
968 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
969 ASSERT(Vcb != NULL);
970 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
971 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
972 ASSERT(IsMounted(Vcb));
973
974 FileObject = IrpContext->FileObject;
975 Fcb = (PEXT2_FCB) FileObject->FsContext;
976
977 /* check Fcb is valid or not */
978 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
979 Status = STATUS_INVALID_PARAMETER;
980 _SEH2_LEAVE;
981 }
982
983 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
984 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
985
986 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
987 Status = STATUS_FILE_DELETED;
988 _SEH2_LEAVE;
989 }
990
991 Ccb = (PEXT2_CCB) FileObject->FsContext2;
992 if (Ccb == NULL) {
993 Status = STATUS_INVALID_PARAMETER;
994 _SEH2_LEAVE;
995 }
996
997 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
998 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
999
1000 if (InputSize < sizeof(STARTING_VCN_INPUT_BUFFER) ||
1001 OutputSize < sizeof(RETRIEVAL_POINTERS_BUFFER) ) {
1002 Status = STATUS_BUFFER_TOO_SMALL;
1003 _SEH2_LEAVE;
1004 }
1005
1006 if (!ExAcquireResourceExclusiveLite (
1007 &Fcb->MainResource, Ext2CanIWait())) {
1008 Status = STATUS_PENDING;
1009 _SEH2_LEAVE;
1010 }
1011 FcbResourceAcquired = TRUE;
1012
1013 SVIB = (PSTARTING_VCN_INPUT_BUFFER)
1014 EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
1015 RPSB = (PRETRIEVAL_POINTERS_BUFFER) Ext2GetUserBuffer(Irp);
1016
1017 /* probe user buffer */
1018
1019 _SEH2_TRY {
1020 if (Irp->RequestorMode != KernelMode) {
1021 ProbeForRead (SVIB, InputSize, sizeof(UCHAR));
1022 ProbeForWrite(RPSB, OutputSize, sizeof(UCHAR));
1023 }
1024 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1025 Status = STATUS_INVALID_USER_BUFFER;
1026 } _SEH2_END;
1027
1028 if (!NT_SUCCESS(Status)) {
1029 _SEH2_LEAVE;
1030 }
1031
1032 UsedSize = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]);
1033
1034 /* request size beyonds whole file size ? */
1035 DEBUG(DL_DBG, ("Ext2GetRetrievalPointers: Startin from Vbn: %I64xh\n",
1036 SVIB->StartingVcn.QuadPart));
1037 Vbn = (SVIB->StartingVcn.QuadPart << BLOCK_BITS);
1038 if (Vbn >= Fcb->Header.AllocationSize.QuadPart ) {
1039 Status = STATUS_END_OF_FILE;
1040 _SEH2_LEAVE;
1041 }
1042
1043 /* now building all the request extents */
1044 while (Vbn < Fcb->Header.AllocationSize.QuadPart) {
1045
1046 ASSERT(Chain == NULL);
1047 Length = 0x80000000; /* 2g bytes */
1048 if (Fcb->Header.AllocationSize.QuadPart < Vbn + Length) {
1049 Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - Vbn);
1050 }
1051
1052 /* build extents for sub-range */
1053 Status = Ext2BuildExtents(
1054 IrpContext,
1055 Vcb,
1056 Fcb->Mcb,
1057 Vbn,
1058 Length,
1059 FALSE,
1060 &Chain);
1061
1062 if (!NT_SUCCESS(Status)) {
1063 DbgBreak();
1064 _SEH2_LEAVE;
1065 }
1066
1067 /* fill user buffer of RETRIEVAL_POINTERS_BUFFER */
1068 Extent = Chain;
1069 while (Extent) {
1070
1071 DEBUG(DL_MAP, ("Ext2GetRetrievalPointers: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
1072 &Fcb->Mcb->FullName, i,
1073 ((Vbn + Extent->Offset) >> BLOCK_BITS),
1074 Extent->Lba));
1075
1076 RPSB->Extents[i].Lcn.QuadPart = (Extent->Lba >> BLOCK_BITS);
1077 RPSB->Extents[i].NextVcn.QuadPart = ((Vbn + Extent->Offset + Extent->Length) >> BLOCK_BITS);
1078 if (i == 0) {
1079 RPSB->StartingVcn.QuadPart = ((Vbn + Extent->Offset) >> BLOCK_BITS);
1080 } else {
1081 ASSERT(RPSB->Extents[i-1].NextVcn.QuadPart == ((Vbn + Extent->Offset) >> BLOCK_BITS));
1082 }
1083 if (UsedSize + sizeof(RETRIEVAL_POINTERS_BUFFER) > OutputSize) {
1084 Status = STATUS_BUFFER_OVERFLOW;
1085 _SEH2_LEAVE;
1086 }
1087 UsedSize += sizeof(LARGE_INTEGER) * 2;
1088 Irp->IoStatus.Information = (ULONG_PTR)UsedSize;
1089 RPSB->ExtentCount = ++i;
1090 Extent = Extent->Next;
1091 }
1092
1093 if (Chain) {
1094 Ext2DestroyExtentChain(Chain);
1095 Chain = NULL;
1096 }
1097
1098 Vbn = Vbn + Length;
1099 }
1100
1101 #if 0
1102 {
1103 NTSTATUS _s;
1104 ULONG _i = 0;
1105 LARGE_INTEGER RequestVbn = Fcb->Header.AllocationSize;
1106 PLARGE_INTEGER MappedRuns = NULL;
1107
1108 _s = Ext2QueryExtentMappings(
1109 IrpContext,
1110 Vcb,
1111 Fcb,
1112 &RequestVbn,
1113 &MappedRuns
1114 );
1115 if (!NT_SUCCESS(_s) || NULL == MappedRuns) {
1116 DbgBreak();
1117 goto exit_to_get_rps;
1118 }
1119
1120 while (MappedRuns[_i*2 + 0].QuadPart != 0 ||
1121 MappedRuns[_i*2 + 1].QuadPart != 0 ) {
1122 DEBUG(DL_MAP, ("Ext2QueryExtentMappings: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
1123 &Fcb->Mcb->FullName, _i,
1124 MappedRuns[_i*2 + 0].QuadPart,
1125 MappedRuns[_i*2 + 1].QuadPart));
1126 _i++;
1127 }
1128
1129 exit_to_get_rps:
1130
1131 if (MappedRuns) {
1132 Ext2FreePool(MappedRuns, 'RE2E');
1133 }
1134 }
1135 #endif
1136
1137 } _SEH2_FINALLY {
1138
1139 if (FcbResourceAcquired) {
1140 ExReleaseResourceLite(&Fcb->MainResource);
1141 }
1142
1143 if (Chain) {
1144 Ext2DestroyExtentChain(Chain);
1145 }
1146
1147 if (!_SEH2_AbnormalTermination()) {
1148 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1149 Status = Ext2QueueRequest(IrpContext);
1150 } else {
1151 Ext2CompleteIrpContext(IrpContext, Status);
1152 }
1153 }
1154 } _SEH2_END;
1155
1156 return Status;
1157 }
1158
1159 NTSTATUS
1160 Ext2GetRetrievalPointerBase (
1161 IN PEXT2_IRP_CONTEXT IrpContext
1162 )
1163 {
1164 PIRP Irp = NULL;
1165 PIO_STACK_LOCATION IrpSp;
1166 PEXTENDED_IO_STACK_LOCATION EIrpSp;
1167
1168 PDEVICE_OBJECT DeviceObject;
1169 PFILE_OBJECT FileObject;
1170
1171 PEXT2_VCB Vcb = NULL;
1172 PEXT2_FCB Fcb = NULL;
1173 PEXT2_CCB Ccb = NULL;
1174
1175 PLARGE_INTEGER FileAreaOffset;
1176
1177 ULONG OutputSize;
1178
1179 NTSTATUS Status = STATUS_SUCCESS;
1180
1181 BOOLEAN FcbResourceAcquired = FALSE;
1182
1183 _SEH2_TRY {
1184
1185 ASSERT(IrpContext);
1186 Irp = IrpContext->Irp;
1187 ASSERT(Irp);
1188
1189 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1190 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
1191 ASSERT(IrpSp);
1192
1193 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
1194
1195 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1196 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1197
1198 DeviceObject = IrpContext->DeviceObject;
1199
1200 /* This request is not allowed on the main device object */
1201 if (IsExt2FsDevice(DeviceObject)) {
1202 Status = STATUS_INVALID_DEVICE_REQUEST;
1203 _SEH2_LEAVE;
1204 }
1205
1206 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1207 ASSERT(Vcb != NULL);
1208 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
1209 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
1210 ASSERT(IsMounted(Vcb));
1211
1212 FileObject = IrpContext->FileObject;
1213 Fcb = (PEXT2_FCB) FileObject->FsContext;
1214
1215 /* check Fcb is valid or not */
1216 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
1217 Status = STATUS_INVALID_PARAMETER;
1218 _SEH2_LEAVE;
1219 }
1220
1221 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
1222 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
1223
1224 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
1225 Status = STATUS_FILE_DELETED;
1226 _SEH2_LEAVE;
1227 }
1228
1229 Ccb = (PEXT2_CCB) FileObject->FsContext2;
1230 if (Ccb == NULL) {
1231 Status = STATUS_INVALID_PARAMETER;
1232 _SEH2_LEAVE;
1233 }
1234
1235 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1236 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1237
1238 if (OutputSize < sizeof(LARGE_INTEGER)) {
1239 Status = STATUS_BUFFER_TOO_SMALL;
1240 _SEH2_LEAVE;
1241 }
1242
1243 if (!ExAcquireResourceExclusiveLite (
1244 &Fcb->MainResource, Ext2CanIWait())) {
1245 Status = STATUS_PENDING;
1246 _SEH2_LEAVE;
1247 }
1248 FcbResourceAcquired = TRUE;
1249
1250 FileAreaOffset = (PLARGE_INTEGER) Ext2GetUserBuffer(Irp);
1251
1252 /* probe user buffer */
1253
1254 _SEH2_TRY {
1255 if (Irp->RequestorMode != KernelMode) {
1256 ProbeForWrite(FileAreaOffset, OutputSize, sizeof(UCHAR));
1257 }
1258
1259 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1260
1261 Status = STATUS_INVALID_USER_BUFFER;
1262 } _SEH2_END;
1263
1264 if (!NT_SUCCESS(Status)) {
1265 _SEH2_LEAVE;
1266 }
1267
1268 DEBUG(DL_DBG, ("Ext2GetRetrievalPointerBase: FileAreaOffset is 0.\n"));
1269
1270 FileAreaOffset->QuadPart = 0; // sector offset to the first allocatable unit on the filesystem
1271
1272 Irp->IoStatus.Information = sizeof(LARGE_INTEGER);
1273
1274 } _SEH2_FINALLY {
1275
1276 if (FcbResourceAcquired) {
1277 ExReleaseResourceLite(&Fcb->MainResource);
1278 }
1279
1280 if (!_SEH2_AbnormalTermination()) {
1281 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1282 Status = Ext2QueueRequest(IrpContext);
1283 } else {
1284 Ext2CompleteIrpContext(IrpContext, Status);
1285 }
1286 }
1287 } _SEH2_END;
1288
1289 return Status;
1290 }
1291
1292 NTSTATUS
1293 Ext2InspectReparseData(
1294 IN PREPARSE_DATA_BUFFER RDB,
1295 IN ULONG InputBufferLength
1296 )
1297 {
1298 NTSTATUS Status = STATUS_SUCCESS;
1299
1300 if (!RDB) {
1301 Status = STATUS_INVALID_PARAMETER;
1302 goto out;
1303 }
1304
1305 if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
1306 Status = STATUS_BUFFER_OVERFLOW;
1307 goto out;
1308 }
1309
1310 if (InputBufferLength < RDB->ReparseDataLength) {
1311 Status = STATUS_BUFFER_OVERFLOW;
1312 goto out;
1313 }
1314
1315 if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
1316 Status = STATUS_NOT_IMPLEMENTED;
1317 goto out;
1318 }
1319
1320 if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
1321 + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset
1322 + RDB->SymbolicLinkReparseBuffer.SubstituteNameLength
1323 > (PUCHAR)RDB + InputBufferLength ) {
1324 Status = STATUS_BUFFER_OVERFLOW;
1325 goto out;
1326 }
1327
1328 if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
1329 + RDB->SymbolicLinkReparseBuffer.PrintNameOffset
1330 + RDB->SymbolicLinkReparseBuffer.PrintNameLength
1331 > (PUCHAR)RDB + InputBufferLength) {
1332 Status = STATUS_BUFFER_OVERFLOW;
1333 goto out;
1334 }
1335
1336 if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) {
1337 Status = STATUS_NOT_IMPLEMENTED;
1338 goto out;
1339 }
1340
1341 out:
1342 return Status;
1343 }
1344
1345 VOID
1346 Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength)
1347 {
1348 ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) ==
1349 REPARSE_DATA_BUFFER_HEADER_SIZE);
1350 RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK;
1351 RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
1352 FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
1353 PathBufferLength * sizeof(WCHAR);
1354 RDB->Reserved = 0;
1355 RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength;
1356 RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength;
1357 RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
1358 RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength;
1359 RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
1360 RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2);
1361 }
1362
1363 NTSTATUS
1364 Ext2ReadSymlink (
1365 IN PEXT2_IRP_CONTEXT IrpContext,
1366 IN PEXT2_VCB Vcb,
1367 IN PEXT2_MCB Mcb,
1368 IN PVOID Buffer,
1369 IN ULONG Size,
1370 OUT PULONG BytesRead
1371 )
1372 {
1373 return Ext2ReadInode ( IrpContext,
1374 Vcb,
1375 Mcb,
1376 0,
1377 Buffer,
1378 Size,
1379 FALSE,
1380 BytesRead);
1381 }
1382
1383
1384
1385 NTSTATUS
1386 Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
1387 {
1388 PIRP Irp = NULL;
1389 PIO_STACK_LOCATION IrpSp;
1390 PEXTENDED_IO_STACK_LOCATION EIrpSp;
1391
1392 PDEVICE_OBJECT DeviceObject;
1393
1394 PEXT2_VCB Vcb = NULL;
1395 PEXT2_CCB Ccb = NULL;
1396 PEXT2_MCB Mcb = NULL;
1397
1398 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1399 BOOLEAN MainResourceAcquired = FALSE;
1400
1401 PVOID OutputBuffer;
1402 ULONG OutputBufferLength;
1403 ULONG BytesRead = 0;
1404
1405 PREPARSE_DATA_BUFFER RDB;
1406
1407 UNICODE_STRING UniName;
1408 OEM_STRING OemName;
1409
1410 PCHAR OemNameBuffer = NULL;
1411 int OemNameLength = 0, i;
1412
1413 Ccb = IrpContext->Ccb;
1414 ASSERT(Ccb != NULL);
1415 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1416 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1417 DeviceObject = IrpContext->DeviceObject;
1418 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1419 Mcb = IrpContext->Fcb->Mcb;
1420 Irp = IrpContext->Irp;
1421 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1422
1423 _SEH2_TRY {
1424
1425 if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
1426 !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
1427 Status = STATUS_NOT_A_REPARSE_POINT;
1428 _SEH2_LEAVE;
1429 }
1430
1431 OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
1432 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
1433
1434 RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
1435 if (!RDB) {
1436 Status = STATUS_INVALID_PARAMETER;
1437 _SEH2_LEAVE;
1438 }
1439 if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
1440 Status = STATUS_BUFFER_OVERFLOW;
1441 _SEH2_LEAVE;
1442 }
1443
1444 OemNameLength = (ULONG)Mcb->Inode.i_size;
1445 if (OemNameLength > USHRT_MAX) {
1446 Status = STATUS_INVALID_PARAMETER;
1447 _SEH2_LEAVE;
1448 }
1449 OemName.Length = (USHORT)OemNameLength;
1450 OemName.MaximumLength = OemNameLength + 1;
1451 OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
1452 OemName.MaximumLength,
1453 'NL2E');
1454 if (!OemNameBuffer) {
1455 Status = STATUS_INSUFFICIENT_RESOURCES;
1456 _SEH2_LEAVE;
1457 }
1458
1459 Status = Ext2ReadSymlink(IrpContext,
1460 Vcb,
1461 Mcb,
1462 OemNameBuffer,
1463 OemNameLength,
1464 &BytesRead
1465 );
1466 OemName.Buffer[OemName.Length] = '\0';
1467 for (i = 0;i < OemName.Length;i++) {
1468 if (OemName.Buffer[i] == '/') {
1469 OemName.Buffer[i] = '\\';
1470 }
1471 }
1472
1473 if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
1474 UniName.Length = USHRT_MAX;
1475 } else {
1476 UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
1477 }
1478 UniName.MaximumLength = UniName.Length;
1479 UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
1480 Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
1481 if (UniName.MaximumLength < 2*UniName.Length) {
1482 Status = STATUS_BUFFER_TOO_SMALL;
1483 _SEH2_LEAVE;
1484 }
1485
1486 Ext2InitializeReparseData(RDB, UniName.Length);
1487 UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
1488 /*
1489 (PWCHAR)((PUCHAR)&
1490 + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
1491 */
1492 Ext2OEMToUnicode(Vcb, &UniName, &OemName);
1493 RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
1494 RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
1495 UniName.Buffer, UniName.Length);
1496
1497 Status = STATUS_SUCCESS;
1498
1499 } _SEH2_FINALLY {
1500
1501 if (OemNameBuffer) {
1502 Ext2FreePool(OemNameBuffer, 'NL2E');
1503 }
1504
1505 if (!_SEH2_AbnormalTermination()) {
1506 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1507 Status = Ext2QueueRequest(IrpContext);
1508 } else {
1509 Ext2CompleteIrpContext(IrpContext, Status);
1510 }
1511 }
1512 } _SEH2_END;
1513
1514 return Status;
1515 }
1516
1517
1518 NTSTATUS
1519 Ext2WriteSymlink (
1520 IN PEXT2_IRP_CONTEXT IrpContext,
1521 IN PEXT2_VCB Vcb,
1522 IN PEXT2_MCB Mcb,
1523 IN PVOID Buffer,
1524 IN ULONG Size,
1525 OUT PULONG BytesWritten
1526 )
1527 {
1528 NTSTATUS Status = STATUS_SUCCESS;
1529 PUCHAR Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
1530
1531 if (Size >= EXT2_LINKLEN_IN_INODE) {
1532
1533 /* initialize inode i_block[] */
1534 if (0 == Mcb->Inode.i_blocks) {
1535 memset(Data, 0, EXT2_LINKLEN_IN_INODE);
1536 ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
1537 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1538 }
1539
1540 Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
1541 0, Buffer, Size,
1542 FALSE, BytesWritten);
1543 if (!NT_SUCCESS(Status)) {
1544 goto out;
1545 }
1546
1547 } else {
1548
1549 /* free inode blocks before writing in line */
1550 if (Mcb->Inode.i_blocks) {
1551 LARGE_INTEGER Zero = {0, 0};
1552 Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
1553 }
1554
1555 ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
1556 memset(Data, 0, EXT2_LINKLEN_IN_INODE);
1557 RtlCopyMemory(Data, Buffer, Size);
1558 }
1559
1560 Mcb->Inode.i_size = Size;
1561 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1562
1563 if (BytesWritten) {
1564 *BytesWritten = Size;
1565 }
1566
1567 out:
1568 return Status;
1569 }
1570
1571 NTSTATUS
1572 Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
1573 {
1574 PIRP Irp = NULL;
1575 PIO_STACK_LOCATION IrpSp;
1576
1577 PDEVICE_OBJECT DeviceObject;
1578
1579 PEXT2_VCB Vcb = NULL;
1580 PEXT2_FCB Fcb = NULL;
1581 PEXT2_CCB Ccb = NULL;
1582 PEXT2_MCB Mcb = NULL;
1583
1584 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1585 BOOLEAN bNewParentDcb = FALSE;
1586 BOOLEAN MainResourceAcquired = FALSE;
1587
1588 PVOID InputBuffer;
1589 ULONG InputBufferLength;
1590 ULONG BytesWritten = 0;
1591
1592 PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
1593 PEXT2_MCB ParentMcb = NULL;
1594
1595 PREPARSE_DATA_BUFFER RDB;
1596
1597 UNICODE_STRING UniName;
1598 OEM_STRING OemName;
1599
1600 PCHAR OemNameBuffer = NULL;
1601 int OemNameLength = 0, i;
1602
1603
1604 _SEH2_TRY {
1605
1606 Ccb = IrpContext->Ccb;
1607 ASSERT(Ccb != NULL);
1608 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1609 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1610 DeviceObject = IrpContext->DeviceObject;
1611 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1612 Fcb = IrpContext->Fcb;
1613 Mcb = Fcb->Mcb;
1614 Irp = IrpContext->Irp;
1615 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1616
1617 ParentMcb = Mcb->Parent;
1618 ParentDcb = ParentMcb->Fcb;
1619 if (ParentDcb == NULL) {
1620 ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
1621 if (ParentDcb) {
1622 Ext2ReferXcb(&ParentDcb->ReferenceCount);
1623 bNewParentDcb = TRUE;
1624 }
1625 }
1626
1627 if (!Mcb)
1628 _SEH2_LEAVE;
1629
1630 if (!ExAcquireResourceSharedLite(
1631 &Fcb->MainResource,
1632 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
1633 Status = STATUS_PENDING;
1634 _SEH2_LEAVE;
1635 }
1636 MainResourceAcquired = TRUE;
1637
1638 InputBuffer = Irp->AssociatedIrp.SystemBuffer;
1639 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
1640
1641 RDB = (PREPARSE_DATA_BUFFER)InputBuffer;
1642 Status = Ext2InspectReparseData(RDB, InputBufferLength);
1643 if (!NT_SUCCESS(Status)) {
1644 _SEH2_LEAVE;
1645 }
1646
1647 UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength;
1648 UniName.MaximumLength = UniName.Length;
1649 UniName.Buffer =
1650 (PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer
1651 + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
1652
1653 OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName);
1654 if (OemNameLength > USHRT_MAX) {
1655 Status = STATUS_INVALID_PARAMETER;
1656 _SEH2_LEAVE;
1657 }
1658 OemName.Length = (USHORT)OemNameLength;
1659 OemName.MaximumLength = OemNameLength + 1;
1660 OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool,
1661 OemName.MaximumLength,
1662 'NL2E');
1663 if (!OemNameBuffer) {
1664 Status = STATUS_INSUFFICIENT_RESOURCES;
1665 _SEH2_LEAVE;
1666 }
1667
1668 Ext2UnicodeToOEM(Vcb, &OemName, &UniName);
1669 OemName.Buffer[OemName.Length] = '\0';
1670 for (i = 0;i < OemName.Length;i++) {
1671 if (OemName.Buffer[i] == '\\') {
1672 OemName.Buffer[i] = '/';
1673 }
1674 }
1675
1676 /* free all data blocks of the inode (to be set as symlink) */
1677 {
1678 LARGE_INTEGER zero = {0};
1679 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &zero);
1680 }
1681
1682 /* decrease dir count of group desc and vcb stat */
1683 if (S_ISDIR(Mcb->Inode.i_mode)) {
1684
1685 ULONG group = (Mcb->Inode.i_ino - 1) / INODES_PER_GROUP;
1686 Ext2UpdateGroupDirStat(IrpContext, Vcb, group);
1687
1688 /* drop extra reference for dir inode */
1689 ext3_dec_count(&Mcb->Inode);
1690 }
1691
1692 /* overwrite inode mode as type SYMLINK */
1693 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1694 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
1695
1696 Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
1697 OemNameLength, &BytesWritten);
1698 if (NT_SUCCESS(Status)) {
1699 Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb,
1700 S_IFLNK | S_IRWXUGO);
1701 }
1702
1703 } _SEH2_FINALLY {
1704
1705 if (MainResourceAcquired) {
1706 ExReleaseResourceLite(&Fcb->MainResource);
1707 }
1708
1709 if (OemNameBuffer) {
1710 Ext2FreePool(OemNameBuffer, 'NL2E');
1711 }
1712
1713 if (NT_SUCCESS(Status)) {
1714 Ext2NotifyReportChange(
1715 IrpContext,
1716 Vcb,
1717 Mcb,
1718 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1719 FILE_ACTION_MODIFIED );
1720 }
1721
1722 if (bNewParentDcb) {
1723 ASSERT(ParentDcb != NULL);
1724 if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
1725 Ext2FreeFcb(ParentDcb);
1726 ParentDcb = NULL;
1727 } else {
1728 DEBUG(DL_RES, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
1729 }
1730 }
1731
1732 if (!_SEH2_AbnormalTermination()) {
1733 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1734 Status = Ext2QueueRequest(IrpContext);
1735 } else {
1736 Ext2CompleteIrpContext(IrpContext, Status);
1737 }
1738 }
1739 } _SEH2_END;
1740
1741 return Status;
1742 }
1743
1744 NTSTATUS
1745 Ext2TruncateSymlink(
1746 PEXT2_IRP_CONTEXT IrpContext,
1747 PEXT2_VCB Vcb,
1748 PEXT2_MCB Mcb,
1749 ULONG Size
1750 )
1751 {
1752 NTSTATUS status = STATUS_SUCCESS;
1753 PUCHAR data = (PUCHAR)&Mcb->Inode.i_block;
1754 ULONG len = (ULONG)Mcb->Inode.i_size;
1755 LARGE_INTEGER NewSize;
1756
1757 if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
1758
1759 RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
1760 Mcb->Inode.i_size = Size;
1761 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1762
1763 } else {
1764 NewSize.QuadPart = Size;
1765 status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
1766 if (!NT_SUCCESS(status)) {
1767 goto out;
1768 }
1769 }
1770
1771 out:
1772 return status;
1773 }
1774
1775
1776 /* FIXME: We can only handle one reparse point right now. */
1777 NTSTATUS
1778 Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
1779 {
1780 PIRP Irp = NULL;
1781
1782 PDEVICE_OBJECT DeviceObject;
1783
1784 PEXT2_VCB Vcb = NULL;
1785 PEXT2_FCB Fcb = NULL;
1786 PEXT2_CCB Ccb = NULL;
1787 PEXT2_MCB Mcb = NULL;
1788
1789 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1790 BOOLEAN bNewParentDcb = FALSE;
1791 BOOLEAN bFcbAllocated = FALSE;
1792 BOOLEAN MainResourceAcquired = FALSE;
1793
1794 PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
1795 PEXT2_MCB ParentMcb = NULL;
1796
1797 _SEH2_TRY {
1798
1799 Ccb = IrpContext->Ccb;
1800 ASSERT(Ccb != NULL);
1801 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1802 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1803 DeviceObject = IrpContext->DeviceObject;
1804 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1805 Mcb = IrpContext->Fcb->Mcb;
1806 Irp = IrpContext->Irp;
1807
1808 ParentMcb = Mcb->Parent;
1809 ParentDcb = ParentMcb->Fcb;
1810 if (ParentDcb == NULL) {
1811 ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
1812 if (ParentDcb) {
1813 Ext2ReferXcb(&ParentDcb->ReferenceCount);
1814 bNewParentDcb = TRUE;
1815 }
1816 }
1817
1818 if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
1819 !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
1820 Status = STATUS_NOT_A_REPARSE_POINT;
1821 _SEH2_LEAVE;
1822 }
1823
1824 Fcb = Ext2AllocateFcb (Vcb, Mcb);
1825 if (Fcb) {
1826 bFcbAllocated = TRUE;
1827 } else {
1828 Status = STATUS_INSUFFICIENT_RESOURCES;
1829 _SEH2_LEAVE;
1830 }
1831 Ext2ReferXcb(&Fcb->ReferenceCount);
1832
1833 if (!ExAcquireResourceSharedLite(
1834 &Fcb->MainResource,
1835 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
1836 Status = STATUS_PENDING;
1837 _SEH2_LEAVE;
1838 }
1839 MainResourceAcquired = TRUE;
1840
1841 Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
1842 if (!NT_SUCCESS(Status)) {
1843 _SEH2_LEAVE;
1844 }
1845
1846 /* inode is to be removed */
1847 SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE);
1848
1849 } _SEH2_FINALLY {
1850
1851 if (MainResourceAcquired) {
1852 ExReleaseResourceLite(&Fcb->MainResource);
1853 }
1854
1855 if (NT_SUCCESS(Status)) {
1856 Ext2NotifyReportChange(
1857 IrpContext,
1858 Vcb,
1859 Mcb,
1860 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1861 FILE_ACTION_MODIFIED );
1862
1863 }
1864
1865 if (bNewParentDcb) {
1866 ASSERT(ParentDcb != NULL);
1867 if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
1868 Ext2FreeFcb(ParentDcb);
1869 ParentDcb = NULL;
1870 } else {
1871 DEBUG(DL_RES, ( "Ext2DeleteReparsePoint: ParentDcb is resued.\n"));
1872 }
1873 }
1874
1875 if (!_SEH2_AbnormalTermination()) {
1876 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1877 Status = Ext2QueueRequest(IrpContext);
1878 } else {
1879 Ext2CompleteIrpContext(IrpContext, Status);
1880 }
1881 }
1882
1883 if (bFcbAllocated) {
1884 if (Ext2DerefXcb(&Fcb->ReferenceCount) == 0) {
1885 Ext2FreeFcb(Fcb);
1886 }
1887 }
1888 } _SEH2_END;
1889
1890 return Status;
1891 }
1892
1893 NTSTATUS
1894 Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
1895 {
1896 PIRP Irp;
1897 PIO_STACK_LOCATION IoStackLocation;
1898 ULONG FsControlCode;
1899 NTSTATUS Status;
1900
1901 ASSERT(IrpContext);
1902
1903 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1904 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1905
1906 Irp = IrpContext->Irp;
1907 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1908
1909 #ifndef _GNU_NTIFS_
1910 FsControlCode =
1911 IoStackLocation->Parameters.FileSystemControl.FsControlCode;
1912 #else
1913 FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)
1914 IoStackLocation)->Parameters.FileSystemControl.FsControlCode;
1915 #endif
1916
1917 switch (FsControlCode) {
1918
1919 case FSCTL_GET_REPARSE_POINT:
1920 Status = Ext2GetReparsePoint(IrpContext);
1921 break;
1922
1923 case FSCTL_SET_REPARSE_POINT:
1924 Status = Ext2SetReparsePoint(IrpContext);
1925 break;
1926
1927 case FSCTL_DELETE_REPARSE_POINT:
1928 Status = Ext2DeleteReparsePoint(IrpContext);
1929 break;
1930
1931 case FSCTL_LOCK_VOLUME:
1932 Status = Ext2LockVolume(IrpContext);
1933 break;
1934
1935 case FSCTL_UNLOCK_VOLUME:
1936 Status = Ext2UnlockVolume(IrpContext);
1937 break;
1938
1939 case FSCTL_DISMOUNT_VOLUME:
1940 Status = Ext2DismountVolume(IrpContext);
1941 break;
1942
1943 case FSCTL_IS_VOLUME_MOUNTED:
1944 Status = Ext2IsVolumeMounted(IrpContext);
1945 break;
1946
1947 case FSCTL_INVALIDATE_VOLUMES:
1948 Status = Ext2InvalidateVolumes(IrpContext);
1949 break;
1950
1951 #if (_WIN32_WINNT >= 0x0500)
1952 case FSCTL_ALLOW_EXTENDED_DASD_IO:
1953 Status = Ext2AllowExtendedDasdIo(IrpContext);
1954 break;
1955 #endif //(_WIN32_WINNT >= 0x0500)
1956
1957 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
1958 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
1959 case FSCTL_REQUEST_BATCH_OPLOCK:
1960 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
1961 case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
1962 case FSCTL_OPLOCK_BREAK_NOTIFY:
1963 case FSCTL_OPLOCK_BREAK_ACK_NO_2:
1964
1965 Status = Ext2OplockRequest(IrpContext);
1966 break;
1967
1968 case FSCTL_IS_VOLUME_DIRTY:
1969 Status = Ext2IsVolumeDirty(IrpContext);
1970 break;
1971
1972 case FSCTL_QUERY_RETRIEVAL_POINTERS:
1973 Status = Ext2QueryRetrievalPointers(IrpContext);
1974 break;
1975
1976 case FSCTL_GET_RETRIEVAL_POINTERS:
1977 Status = Ext2GetRetrievalPointers(IrpContext);
1978 break;
1979
1980 case FSCTL_GET_RETRIEVAL_POINTER_BASE:
1981 Status = Ext2GetRetrievalPointerBase(IrpContext);
1982 break;
1983
1984 default:
1985
1986 DEBUG(DL_INF, ( "Ext2UserFsRequest: Invalid User Request: %xh.\n", FsControlCode));
1987 Status = STATUS_INVALID_DEVICE_REQUEST;
1988
1989 Ext2CompleteIrpContext(IrpContext, Status);
1990 }
1991
1992 return Status;
1993 }
1994
1995 BOOLEAN
1996 Ext2IsMediaWriteProtected (
1997 IN PEXT2_IRP_CONTEXT IrpContext,
1998 IN PDEVICE_OBJECT TargetDevice
1999 )
2000 {
2001 PIRP Irp;
2002 KEVENT Event;
2003 NTSTATUS Status;
2004 IO_STATUS_BLOCK IoStatus;
2005
2006 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2007
2008 Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
2009 TargetDevice,
2010 NULL,
2011 0,
2012 NULL,
2013 0,
2014 FALSE,
2015 &Event,
2016 &IoStatus );
2017
2018 if (Irp == NULL) {
2019 return FALSE;
2020 }
2021
2022 SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
2023
2024 Status = IoCallDriver(TargetDevice, Irp);
2025
2026 if (Status == STATUS_PENDING) {
2027
2028 (VOID) KeWaitForSingleObject( &Event,
2029 Executive,
2030 KernelMode,
2031 FALSE,
2032 (PLARGE_INTEGER)NULL );
2033
2034 Status = IoStatus.Status;
2035 }
2036
2037 return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
2038 }
2039
2040 NTSTATUS
2041 Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2042 {
2043 PDEVICE_OBJECT MainDeviceObject;
2044 BOOLEAN GlobalDataResourceAcquired = FALSE;
2045 PIRP Irp;
2046 PIO_STACK_LOCATION IoStackLocation;
2047 PDEVICE_OBJECT TargetDeviceObject;
2048 NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
2049 PDEVICE_OBJECT VolumeDeviceObject = NULL;
2050 PEXT2_VCB Vcb = NULL, OldVcb = NULL;
2051 PVPB OldVpb = NULL, Vpb = NULL;
2052 PEXT2_SUPER_BLOCK Ext2Sb = NULL;
2053 ULONG dwBytes;
2054 DISK_GEOMETRY DiskGeometry;
2055
2056 _SEH2_TRY {
2057
2058 ASSERT(IrpContext != NULL);
2059 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2060 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2061
2062 MainDeviceObject = IrpContext->DeviceObject;
2063
2064 //
2065 // Make sure we can wait.
2066 //
2067
2068 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2069
2070 //
2071 // This request is only allowed on the main device object
2072 //
2073 if (!IsExt2FsDevice(MainDeviceObject)) {
2074 Status = STATUS_INVALID_DEVICE_REQUEST;
2075 _SEH2_LEAVE;
2076 }
2077
2078 if (IsFlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) {
2079 Status = STATUS_UNRECOGNIZED_VOLUME;
2080 _SEH2_LEAVE;
2081 }
2082
2083 #if 0
2084 if (IrpContext->RealDevice->Size >= sizeof(ULONG) + sizeof(DEVICE_OBJECT) &&
2085 *((PULONG)IrpContext->RealDevice->DeviceExtension) == 'DSSA') {
2086 } else {
2087 Status = STATUS_UNRECOGNIZED_VOLUME;
2088 _SEH2_LEAVE;
2089 }
2090 #endif
2091
2092 Irp = IrpContext->Irp;
2093 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
2094 TargetDeviceObject =
2095 IoStackLocation->Parameters.MountVolume.DeviceObject;
2096
2097 dwBytes = sizeof(DISK_GEOMETRY);
2098 Status = Ext2DiskIoControl(
2099 TargetDeviceObject,
2100 IOCTL_DISK_GET_DRIVE_GEOMETRY,
2101 NULL,
2102 0,
2103 &DiskGeometry,
2104 &dwBytes );
2105
2106 if (!NT_SUCCESS(Status)) {
2107 _SEH2_LEAVE;
2108 }
2109
2110 Status = IoCreateDevice(
2111 MainDeviceObject->DriverObject,
2112 sizeof(EXT2_VCB),
2113 NULL,
2114 FILE_DEVICE_DISK_FILE_SYSTEM,
2115 0,
2116 FALSE,
2117 &VolumeDeviceObject );
2118
2119 if (!NT_SUCCESS(Status)) {
2120 _SEH2_LEAVE;
2121 }
2122 INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
2123
2124 VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
2125 ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
2126
2127 /*
2128 These are for buffer-address alignment requirements.
2129 Never do this check, unless you want fail user requests :)
2130
2131 if (TargetDeviceObject->AlignmentRequirement >
2132 VolumeDeviceObject->AlignmentRequirement) {
2133
2134 VolumeDeviceObject->AlignmentRequirement =
2135 TargetDeviceObject->AlignmentRequirement;
2136 }
2137
2138 if (DiskGeometry.BytesPerSector - 1 >
2139 VolumeDeviceObject->AlignmentRequirement) {
2140 VolumeDeviceObject->AlignmentRequirement =
2141 DiskGeometry.BytesPerSector - 1;
2142 TargetDeviceObject->AlignmentRequirement =
2143 DiskGeometry.BytesPerSector - 1;
2144 }
2145 */
2146 (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
2147 VolumeDeviceObject;
2148 Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
2149
2150 Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension;
2151
2152 RtlZeroMemory(Vcb, sizeof(EXT2_VCB));
2153 Vcb->Identifier.Type = EXT2VCB;
2154 Vcb->Identifier.Size = sizeof(EXT2_VCB);
2155 Vcb->TargetDeviceObject = TargetDeviceObject;
2156 Vcb->DiskGeometry = DiskGeometry;
2157 InitializeListHead(&Vcb->Next);
2158
2159 Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb);
2160 if (!NT_SUCCESS(Status)) {
2161 Vcb = NULL;
2162 Status = STATUS_UNRECOGNIZED_VOLUME;
2163 _SEH2_LEAVE;
2164 }
2165 ASSERT (NULL != Ext2Sb);
2166
2167 /* check Linux Ext2/Ext3 volume magic */
2168 if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) {
2169 DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n"));
2170 } else {
2171 Status = STATUS_UNRECOGNIZED_VOLUME;
2172 Vcb = NULL;
2173 _SEH2_LEAVE;
2174 }
2175
2176 DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb));
2177
2178 /* initialize Vcb structure */
2179 Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb,
2180 TargetDeviceObject,
2181 VolumeDeviceObject, Vpb);
2182
2183 if (NT_SUCCESS(Status)) {
2184
2185 PLIST_ENTRY List;
2186
2187 ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE);
2188 GlobalDataResourceAcquired = TRUE;
2189
2190 for (List = Ext2Global->VcbList.Flink;
2191 List != &Ext2Global->VcbList;
2192 List = List->Flink) {
2193
2194 OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
2195 OldVpb = OldVcb->Vpb;
2196
2197 /* in case we are already in the queue, should not happen */
2198 if (OldVpb == Vpb) {
2199 continue;
2200 }
2201
2202 if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
2203 (!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) &&
2204 (OldVpb->RealDevice == TargetDeviceObject) &&
2205 (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
2206 (RtlEqualMemory(&OldVpb->VolumeLabel[0],
2207 &Vpb->VolumeLabel[0],
2208 Vpb->VolumeLabelLength)) &&
2209 (RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0],
2210 &Vcb->SuperBlock->s_uuid[0], 16)) ) {
2211 ClearFlag(OldVcb->Flags, VCB_MOUNTED);
2212 }
2213 }
2214
2215 SetLongFlag(Vcb->Flags, VCB_MOUNTED);
2216 SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED);
2217 Ext2InsertVcb(Vcb);
2218 Vcb = NULL;
2219 Vpb = NULL;
2220 ObDereferenceObject(TargetDeviceObject);
2221
2222 } else {
2223
2224 Vcb = NULL;
2225 }
2226
2227 } _SEH2_FINALLY {
2228
2229 if (GlobalDataResourceAcquired) {
2230 ExReleaseResourceLite(&Ext2Global->Resource);
2231 }
2232
2233 if (!NT_SUCCESS(Status)) {
2234
2235 if (!NT_SUCCESS(Status)) {
2236 if ( Vpb != NULL ) {
2237 Vpb->DeviceObject = NULL;
2238 }
2239 }
2240
2241 if (Vcb) {
2242 Ext2DestroyVcb(Vcb);
2243 } else {
2244 if (Ext2Sb) {
2245 Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
2246 }
2247 if (VolumeDeviceObject) {
2248 IoDeleteDevice(VolumeDeviceObject);
2249 DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
2250 }
2251 }
2252 }
2253
2254 if (!IrpContext->ExceptionInProgress) {
2255 Ext2CompleteIrpContext(IrpContext, Status);
2256 }
2257 } _SEH2_END;
2258
2259 return Status;
2260 }
2261
2262 VOID
2263 Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext,
2264 IN PEXT2_VCB Vcb )
2265 {
2266 NTSTATUS Status = STATUS_SUCCESS;
2267
2268 BOOLEAN bVerify = FALSE;
2269 ULONG ChangeCount = 0;
2270 ULONG dwBytes;
2271
2272 PIRP Irp;
2273 PEXTENDED_IO_STACK_LOCATION IrpSp;
2274
2275 _SEH2_TRY {
2276
2277 ASSERT(IrpContext != NULL);
2278
2279 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2280 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2281
2282 Irp = IrpContext->Irp;
2283 IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
2284
2285 bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2286
2287 if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) ||
2288 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) {
2289
2290 dwBytes = sizeof(ULONG);
2291 Status = Ext2DiskIoControl(
2292 Vcb->TargetDeviceObject,
2293 IOCTL_DISK_CHECK_VERIFY,
2294 NULL,
2295 0,
2296 &ChangeCount,
2297 &dwBytes );
2298
2299 if ( STATUS_VERIFY_REQUIRED == Status ||
2300 STATUS_DEVICE_NOT_READY == Status ||
2301 STATUS_NO_MEDIA_IN_DEVICE == Status ||
2302 (NT_SUCCESS(Status) &&
2303 (ChangeCount != Vcb->ChangeCount))) {
2304
2305 KIRQL Irql;
2306
2307 IoAcquireVpbSpinLock(&Irql);
2308 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
2309 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2310 }
2311 IoReleaseVpbSpinLock(Irql);
2312
2313 } else {
2314
2315 if (!NT_SUCCESS(Status)) {
2316 Ext2NormalizeAndRaiseStatus(IrpContext, Status);
2317 }
2318 }
2319 }
2320
2321 if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
2322 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
2323 Ext2NormalizeAndRaiseStatus ( IrpContext,
2324 STATUS_VERIFY_REQUIRED );
2325 }
2326
2327 if (IsMounted(Vcb)) {
2328
2329 if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
2330 (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
2331 (IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
2332 (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
2333 (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
2334 (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
2335 IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
2336 IrpSp->Parameters.FileSystemControl.FsControlCode ==
2337 FSCTL_MARK_VOLUME_DIRTY)) {
2338
2339 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
2340
2341 KIRQL Irql;
2342
2343 IoAcquireVpbSpinLock(&Irql);
2344 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
2345 SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2346 }
2347 IoReleaseVpbSpinLock(Irql);
2348
2349 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
2350
2351 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
2352 }
2353 }
2354 }
2355
2356 } _SEH2_FINALLY {
2357
2358 } _SEH2_END;
2359
2360 }
2361
2362
2363 NTSTATUS
2364 Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2365 {
2366 PDEVICE_OBJECT DeviceObject;
2367 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2368 PEXT2_SUPER_BLOCK ext2_sb = NULL;
2369 PEXT2_VCB Vcb = NULL;
2370 BOOLEAN VcbResourceAcquired = FALSE;
2371 PIRP Irp;
2372 ULONG ChangeCount = 0;
2373 ULONG dwBytes;
2374
2375 _SEH2_TRY {
2376
2377 ASSERT(IrpContext != NULL);
2378 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2379 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2380
2381 DeviceObject = IrpContext->DeviceObject;
2382 //
2383 // This request is not allowed on the main device object
2384 //
2385 if (IsExt2FsDevice(DeviceObject)) {
2386 Status = STATUS_INVALID_DEVICE_REQUEST;
2387 _SEH2_LEAVE;
2388 }
2389
2390 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2391 ASSERT(Vcb != NULL);
2392 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2393 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2394
2395 VcbResourceAcquired =
2396 ExAcquireResourceExclusiveLite(
2397 &Vcb->MainResource,
2398 TRUE );
2399
2400 if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
2401 Status = STATUS_SUCCESS;
2402 _SEH2_LEAVE;
2403 }
2404
2405 if (!IsMounted(Vcb)) {
2406 Status = STATUS_WRONG_VOLUME;
2407 _SEH2_LEAVE;
2408 }
2409
2410 dwBytes = sizeof(ULONG);
2411 Status = Ext2DiskIoControl(
2412 Vcb->TargetDeviceObject,
2413 IOCTL_DISK_CHECK_VERIFY,
2414 NULL,
2415 0,
2416 &ChangeCount,
2417 &dwBytes );
2418
2419
2420 if (!NT_SUCCESS(Status)) {
2421 Status = STATUS_WRONG_VOLUME;
2422 _SEH2_LEAVE;
2423 } else {
2424 Vcb->ChangeCount = ChangeCount;
2425 }
2426
2427 Irp = IrpContext->Irp;
2428
2429 Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb);
2430
2431 if (!NT_SUCCESS(Status)) {
2432 _SEH2_LEAVE;
2433 }
2434
2435 ASSERT(NULL != ext2_sb);
2436 if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) &&
2437 (memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
2438 (memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) {
2439
2440 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
2441
2442 if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
2443 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2444 } else {
2445 ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2446 }
2447
2448 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n"));
2449
2450 } else {
2451
2452 Status = STATUS_WRONG_VOLUME;
2453 if (VcbResourceAcquired) {
2454 ExReleaseResourceLite(&Vcb->MainResource);
2455 VcbResourceAcquired = FALSE;
2456 }
2457 Ext2PurgeVolume(Vcb, FALSE);
2458 VcbResourceAcquired =
2459 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
2460
2461 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
2462 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
2463
2464 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n"));
2465 }
2466
2467 } _SEH2_FINALLY {
2468
2469 if (ext2_sb)
2470 Ext2FreePool(ext2_sb, EXT2_SB_MAGIC);
2471
2472 if (VcbResourceAcquired) {
2473 ExReleaseResourceLite(&Vcb->MainResource);
2474 }
2475
2476 if (!IrpContext->ExceptionInProgress) {
2477 Ext2CompleteIrpContext(IrpContext, Status);
2478 }
2479 } _SEH2_END;
2480
2481 return Status;
2482 }
2483
2484
2485 NTSTATUS
2486 Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext)
2487 {
2488 PDEVICE_OBJECT DeviceObject;
2489 PEXT2_VCB Vcb = 0;
2490 NTSTATUS Status = STATUS_SUCCESS;
2491
2492 ASSERT(IrpContext);
2493
2494 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2495 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2496
2497
2498 DeviceObject = IrpContext->DeviceObject;
2499
2500 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2501
2502 ASSERT(IsMounted(Vcb));
2503
2504 Ext2VerifyVcb (IrpContext, Vcb);
2505
2506 Ext2CompleteIrpContext(IrpContext, Status);
2507
2508 return Status;
2509 }
2510
2511
2512 NTSTATUS
2513 Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2514 {
2515 PDEVICE_OBJECT DeviceObject;
2516 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2517 PEXT2_VCB Vcb = NULL;
2518 BOOLEAN VcbResourceAcquired = FALSE;
2519
2520 _SEH2_TRY {
2521
2522 ASSERT(IrpContext != NULL);
2523
2524 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2525 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2526
2527 DeviceObject = IrpContext->DeviceObject;
2528
2529 //
2530 // This request is not allowed on the main device object
2531 //
2532 if (IsExt2FsDevice(DeviceObject)) {
2533 Status = STATUS_INVALID_DEVICE_REQUEST;
2534 _SEH2_LEAVE;
2535 }
2536
2537 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2538
2539 ASSERT(Vcb != NULL);
2540
2541 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2542 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2543
2544 ASSERT(IsMounted(Vcb));
2545
2546 ExAcquireResourceExclusiveLite(
2547 &Vcb->MainResource,
2548 TRUE );
2549
2550 VcbResourceAcquired = TRUE;
2551
2552 if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
2553 Status = STATUS_VOLUME_DISMOUNTED;
2554 _SEH2_LEAVE;
2555 }
2556
2557 Ext2FlushFiles(IrpContext, Vcb, FALSE);
2558 Ext2FlushVolume(IrpContext, Vcb, FALSE);
2559
2560 ExReleaseResourceLite(&Vcb->MainResource);
2561 VcbResourceAcquired = FALSE;
2562
2563 Ext2PurgeVolume(Vcb, TRUE);
2564 Ext2CheckDismount(IrpContext, Vcb, TRUE);
2565
2566 DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n"));
2567 Status = STATUS_SUCCESS;
2568
2569 } _SEH2_FINALLY {
2570
2571 if (VcbResourceAcquired) {
2572 ExReleaseResourceLite(&Vcb->MainResource);
2573 }
2574
2575 if (!IrpContext->ExceptionInProgress) {
2576 Ext2CompleteIrpContext(IrpContext, Status);
2577 }
2578 } _SEH2_END;
2579
2580 return Status;
2581 }
2582
2583 BOOLEAN
2584 Ext2CheckDismount (
2585 IN PEXT2_IRP_CONTEXT IrpContext,
2586 IN PEXT2_VCB Vcb,
2587 IN BOOLEAN bForce )
2588 {
2589 KIRQL Irql;
2590 PVPB Vpb = Vcb->Vpb, NewVpb = NULL;
2591 BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
2592 ULONG UnCleanCount = 0;
2593
2594 NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB);
2595 if (NewVpb == NULL) {
2596 DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
2597 return FALSE;
2598 }
2599 DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb));
2600 INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
2601 memset(NewVpb, '_', VPB_SIZE);
2602 RtlZeroMemory(NewVpb, sizeof(VPB));
2603
2604 ExAcquireResourceExclusiveLite(
2605 &Ext2Global->Resource, TRUE );
2606
2607 ExAcquireResourceExclusiveLite(
2608 &Vcb->MainResource, TRUE );
2609
2610 if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
2611 (IrpContext->RealDevice == Vcb->RealDevice)) {
2612 UnCleanCount = 2;
2613 } else {
2614 UnCleanCount = 1;
2615 }
2616
2617 IoAcquireVpbSpinLock (&Irql);
2618
2619 DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
2620 Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
2621
2622 if (Vpb->ReferenceCount <= UnCleanCount) {
2623
2624 if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
2625
2626 ClearFlag(Vpb->Flags, VPB_MOUNTED);
2627 ClearFlag(Vpb->Flags, VPB_LOCKED);
2628
2629 if ((Vcb->RealDevice != Vpb->RealDevice) &&
2630 (Vcb->RealDevice->Vpb == Vpb)) {
2631 SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING);
2632 SetFlag(Vpb->Flags, VPB_PERSISTENT );
2633 }
2634
2635 Ext2RemoveVcb(Vcb);
2636 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
2637 }
2638
2639 if (Vpb->ReferenceCount) {
2640 bTearDown = TRUE;
2641 } else {
2642 bDeleted = TRUE;
2643 Vpb->DeviceObject = NULL;
2644 }
2645
2646 DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n",
2647 Vpb, bDeleted, bTearDown));
2648
2649
2650 } else if (bForce) {
2651
2652 DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n",
2653 NewVpb, Vcb->Vpb, Vpb->RealDevice));
2654
2655 /* keep vpb president and later we'll free it */
2656 SetFlag(Vpb->Flags, VPB_PERSISTENT);
2657
2658 Vcb->Vpb2 = Vcb->Vpb;
2659 NewVpb->Type = IO_TYPE_VPB;
2660 NewVpb->Size = sizeof(VPB);
2661 NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING;
2662 NewVpb->RealDevice = Vpb->RealDevice;
2663 NewVpb->RealDevice->Vpb = NewVpb;
2664 NewVpb = NULL;
2665 ClearFlag(Vpb->Flags, VPB_MOUNTED);
2666 SetLongFlag(Vcb->Flags, VCB_NEW_VPB);
2667 ClearLongFlag(Vcb->Flags, VCB_MOUNTED);
2668 }
2669
2670 IoReleaseVpbSpinLock(Irql);
2671
2672 ExReleaseResourceLite(&Vcb->MainResource);
2673 ExReleaseResourceLite(&Ext2Global->Resource);
2674
2675 if (bTearDown) {
2676 DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb));
2677 Ext2TearDownStream(Vcb);
2678 }
2679
2680 if (bDeleted) {
2681 DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb));
2682 Ext2DestroyVcb(Vcb);
2683 }
2684
2685 if (NewVpb != NULL) {
2686 DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb));
2687 ExFreePoolWithTag(NewVpb, TAG_VPB);
2688 DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
2689 }
2690
2691 return bDeleted;
2692 }
2693
2694 NTSTATUS
2695 Ext2PurgeVolume (IN PEXT2_VCB Vcb,
2696 IN BOOLEAN FlushBeforePurge )
2697 {
2698 PEXT2_FCB Fcb;
2699 LIST_ENTRY FcbList;
2700 PLIST_ENTRY ListEntry;
2701 PFCB_LIST_ENTRY FcbListEntry;
2702 BOOLEAN VcbResourceAcquired = FALSE;
2703 _SEH2_TRY {
2704
2705 ASSERT(Vcb != NULL);
2706 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2707 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2708
2709 VcbResourceAcquired =
2710 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
2711
2712 if (IsVcbReadOnly(Vcb)) {
2713 FlushBeforePurge = FALSE;
2714 }
2715
2716 /* discard buffer_headers for group_desc */
2717 Ext2DropGroup(Vcb);
2718
2719 FcbListEntry= NULL;
2720 InitializeListHead(&FcbList);
2721
2722 for (ListEntry = Vcb->FcbList.Flink;
2723 ListEntry != &Vcb->FcbList;
2724 ListEntry = ListEntry->Flink ) {
2725
2726 Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next);
2727
2728 DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n", &Fcb->Mcb->FullName, Fcb->ReferenceCount));
2729
2730 FcbListEntry = Ext2AllocatePool(
2731 PagedPool,
2732 sizeof(FCB_LIST_ENTRY),
2733 EXT2_FLIST_MAGIC
2734 );
2735
2736 if (FcbListEntry) {
2737 FcbListEntry->Fcb = Fcb;
2738 Ext2ReferXcb(&Fcb->ReferenceCount);
2739 InsertTailList(&FcbList, &FcbListEntry->Next);
2740 } else {
2741 DEBUG(DL_ERR, ( "Ext2PurgeVolume: failed to allocate FcbListEntry ...\n"));
2742 }
2743 }
2744
2745 while (!IsListEmpty(&FcbList)) {
2746
2747 ListEntry = RemoveHeadList(&FcbList);
2748
2749 FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next);
2750
2751 Fcb = FcbListEntry->Fcb;
2752
2753 if (ExAcquireResourceExclusiveLite(
2754 &Fcb->MainResource,
2755 TRUE )) {
2756
2757 Ext2PurgeFile(Fcb, FlushBeforePurge);
2758
2759 if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) {
2760 Ext2FreeFcb(Fcb);
2761 } else {
2762 ExReleaseResourceLite(&Fcb->MainResource);
2763 }
2764 }
2765
2766 Ext2FreePool(FcbListEntry, EXT2_FLIST_MAGIC);
2767 }
2768
2769 if (FlushBeforePurge) {
2770 ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
2771 ExReleaseResourceLite(&Vcb->PagingIoResource);
2772
2773 CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
2774 }
2775
2776 if (Vcb->SectionObject.ImageSectionObject) {
2777 MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
2778 }
2779
2780 if (VcbResourceAcquired) {
2781 ExReleaseResourceLite(&Vcb->MainResource);
2782 VcbResourceAcquired = FALSE;
2783 }
2784
2785 if (Vcb->SectionObject.DataSectionObject) {
2786 CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
2787 }
2788
2789 DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n"));
2790
2791 } _SEH2_FINALLY {
2792
2793 if (VcbResourceAcquired) {
2794 ExReleaseResourceLite(&Vcb->MainResource);
2795 }
2796 } _SEH2_END;
2797
2798 return STATUS_SUCCESS;
2799 }
2800
2801 NTSTATUS
2802 Ext2PurgeFile ( IN PEXT2_FCB Fcb,
2803 IN BOOLEAN FlushBeforePurge )
2804 {
2805 IO_STATUS_BLOCK IoStatus;
2806
2807 ASSERT(Fcb != NULL);
2808
2809 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
2810 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
2811
2812
2813 if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
2814
2815 DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
2816 &Fcb->Mcb->FullName));
2817
2818 ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
2819 ExReleaseResourceLite(&Fcb->PagingIoResource);
2820
2821 CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
2822 ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
2823 }
2824
2825 if (Fcb->SectionObject.ImageSectionObject) {
2826
2827 DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
2828 &Fcb->Mcb->FullName));
2829
2830 MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
2831 }
2832
2833 if (Fcb->SectionObject.DataSectionObject) {
2834
2835 DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
2836 &Fcb->Mcb->FullName));
2837
2838 CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
2839 }
2840
2841 return STATUS_SUCCESS;
2842 }
2843
2844
2845 NTSTATUS
2846 Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext)
2847 {
2848 NTSTATUS Status;
2849
2850 ASSERT(IrpContext);
2851
2852 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2853 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2854
2855 switch (IrpContext->MinorFunction) {
2856
2857 case IRP_MN_USER_FS_REQUEST:
2858 Status = Ext2UserFsRequest(IrpContext);
2859 break;
2860
2861 case IRP_MN_MOUNT_VOLUME:
2862 Status = Ext2MountVolume(IrpContext);
2863 break;
2864
2865 case IRP_MN_VERIFY_VOLUME:
2866 Status = Ext2VerifyVolume(IrpContext);
2867 break;
2868
2869 default:
2870
2871 DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n"));
2872 Status = STATUS_INVALID_DEVICE_REQUEST;
2873 Ext2CompleteIrpContext(IrpContext, Status);
2874 }
2875
2876 return Status;
2877 }