5ff4264e2ba9dbd8e21484e36ab338a25f6f22e5
[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 Status = STATUS_NOT_A_REPARSE_POINT;
1427 _SEH2_LEAVE;
1428 }
1429
1430 OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
1431 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
1432
1433 RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
1434 if (!RDB) {
1435 Status = STATUS_INVALID_PARAMETER;
1436 _SEH2_LEAVE;
1437 }
1438 if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
1439 Status = STATUS_BUFFER_OVERFLOW;
1440 _SEH2_LEAVE;
1441 }
1442
1443 OemNameLength = (ULONG)Mcb->Inode.i_size;
1444 if (OemNameLength > USHRT_MAX) {
1445 Status = STATUS_INVALID_PARAMETER;
1446 _SEH2_LEAVE;
1447 }
1448 OemName.Length = (USHORT)OemNameLength;
1449 OemName.MaximumLength = OemNameLength + 1;
1450 OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
1451 OemName.MaximumLength,
1452 'NL2E');
1453 if (!OemNameBuffer) {
1454 Status = STATUS_INSUFFICIENT_RESOURCES;
1455 _SEH2_LEAVE;
1456 }
1457
1458 Status = Ext2ReadSymlink(IrpContext,
1459 Vcb,
1460 Mcb,
1461 OemNameBuffer,
1462 OemNameLength,
1463 &BytesRead
1464 );
1465 OemName.Buffer[OemName.Length] = '\0';
1466 for (i = 0;i < OemName.Length;i++) {
1467 if (OemName.Buffer[i] == '/') {
1468 OemName.Buffer[i] = '\\';
1469 }
1470 }
1471
1472 if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
1473 UniName.Length = USHRT_MAX;
1474 } else {
1475 UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
1476 }
1477 UniName.MaximumLength = UniName.Length;
1478 UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
1479 Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
1480 if (UniName.MaximumLength < 2*UniName.Length) {
1481 Status = STATUS_BUFFER_TOO_SMALL;
1482 _SEH2_LEAVE;
1483 }
1484
1485 Ext2InitializeReparseData(RDB, UniName.Length);
1486 UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
1487 /*
1488 (PWCHAR)((PUCHAR)&
1489 + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
1490 */
1491 Ext2OEMToUnicode(Vcb, &UniName, &OemName);
1492 RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
1493 RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
1494 UniName.Buffer, UniName.Length);
1495
1496 Status = STATUS_SUCCESS;
1497
1498 } _SEH2_FINALLY {
1499
1500 if (OemNameBuffer) {
1501 Ext2FreePool(OemNameBuffer, 'NL2E');
1502 }
1503
1504 if (!_SEH2_AbnormalTermination()) {
1505 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1506 Status = Ext2QueueRequest(IrpContext);
1507 } else {
1508 Ext2CompleteIrpContext(IrpContext, Status);
1509 }
1510 }
1511 } _SEH2_END;
1512
1513 return Status;
1514 }
1515
1516
1517 NTSTATUS
1518 Ext2WriteSymlink (
1519 IN PEXT2_IRP_CONTEXT IrpContext,
1520 IN PEXT2_VCB Vcb,
1521 IN PEXT2_MCB Mcb,
1522 IN PVOID Buffer,
1523 IN ULONG Size,
1524 OUT PULONG BytesWritten
1525 )
1526 {
1527 NTSTATUS Status = STATUS_SUCCESS;
1528 PUCHAR Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
1529
1530 if (Size >= EXT2_LINKLEN_IN_INODE) {
1531
1532 /* initialize inode i_block[] */
1533 if (0 == Mcb->Inode.i_blocks) {
1534 memset(Data, 0, EXT2_LINKLEN_IN_INODE);
1535 ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
1536 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1537 }
1538
1539 Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
1540 0, Buffer, Size,
1541 FALSE, BytesWritten);
1542 if (!NT_SUCCESS(Status)) {
1543 goto out;
1544 }
1545
1546 } else {
1547
1548 /* free inode blocks before writing in line */
1549 if (Mcb->Inode.i_blocks) {
1550 LARGE_INTEGER Zero = {0, 0};
1551 Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
1552 }
1553
1554 ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
1555 memset(Data, 0, EXT2_LINKLEN_IN_INODE);
1556 RtlCopyMemory(Data, Buffer, Size);
1557 }
1558
1559 Mcb->Inode.i_size = Size;
1560 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1561
1562 if (BytesWritten) {
1563 *BytesWritten = Size;
1564 }
1565
1566 out:
1567 return Status;
1568 }
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 /* overwrite inode mode as type SYMLINK */
1677 Mcb->Inode.i_mode = S_IFLNK | S_IRWXUGO;
1678 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1679 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
1680
1681 Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
1682 OemNameLength, &BytesWritten);
1683 if (NT_SUCCESS(Status)) {
1684 Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
1685 }
1686
1687 } _SEH2_FINALLY {
1688
1689 if (MainResourceAcquired) {
1690 ExReleaseResourceLite(&Fcb->MainResource);
1691 }
1692
1693 if (OemNameBuffer) {
1694 Ext2FreePool(OemNameBuffer, 'NL2E');
1695 }
1696
1697 if (NT_SUCCESS(Status)) {
1698 Ext2NotifyReportChange(
1699 IrpContext,
1700 Vcb,
1701 Mcb,
1702 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1703 FILE_ACTION_MODIFIED );
1704 }
1705
1706 if (bNewParentDcb) {
1707 ASSERT(ParentDcb != NULL);
1708 if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
1709 Ext2FreeFcb(ParentDcb);
1710 ParentDcb = NULL;
1711 } else {
1712 DEBUG(DL_RES, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
1713 }
1714 }
1715
1716 if (!_SEH2_AbnormalTermination()) {
1717 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1718 Status = Ext2QueueRequest(IrpContext);
1719 } else {
1720 Ext2CompleteIrpContext(IrpContext, Status);
1721 }
1722 }
1723 } _SEH2_END;
1724
1725 return Status;
1726 }
1727
1728 NTSTATUS
1729 Ext2TruncateSymlink(
1730 PEXT2_IRP_CONTEXT IrpContext,
1731 PEXT2_VCB Vcb,
1732 PEXT2_MCB Mcb,
1733 ULONG Size
1734 )
1735 {
1736 NTSTATUS status = STATUS_SUCCESS;
1737 PUCHAR data = (PUCHAR)&Mcb->Inode.i_block;
1738 ULONG len = (ULONG)Mcb->Inode.i_size;
1739 LARGE_INTEGER NewSize;
1740
1741 if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
1742
1743 RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
1744 Mcb->Inode.i_size = Size;
1745 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1746
1747 } else {
1748 NewSize.QuadPart = Size;
1749 status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
1750 if (!NT_SUCCESS(status)) {
1751 goto out;
1752 }
1753 }
1754
1755 out:
1756 return status;
1757 }
1758
1759
1760 /* FIXME: We can only handle one reparse point right now. */
1761 NTSTATUS
1762 Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
1763 {
1764 PIRP Irp = NULL;
1765
1766 PDEVICE_OBJECT DeviceObject;
1767
1768 PEXT2_VCB Vcb = NULL;
1769 PEXT2_FCB Fcb = NULL;
1770 PEXT2_CCB Ccb = NULL;
1771 PEXT2_MCB Mcb = NULL;
1772
1773 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1774 BOOLEAN bNewParentDcb = FALSE;
1775 BOOLEAN bFcbAllocated = FALSE;
1776 BOOLEAN MainResourceAcquired = FALSE;
1777
1778 PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
1779 PEXT2_MCB ParentMcb = NULL;
1780
1781 _SEH2_TRY {
1782
1783 Ccb = IrpContext->Ccb;
1784 ASSERT(Ccb != NULL);
1785 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
1786 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
1787 DeviceObject = IrpContext->DeviceObject;
1788 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1789 Mcb = IrpContext->Fcb->Mcb;
1790 Irp = IrpContext->Irp;
1791
1792 ParentMcb = Mcb->Parent;
1793 ParentDcb = ParentMcb->Fcb;
1794 if (ParentDcb == NULL) {
1795 ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
1796 if (ParentDcb) {
1797 Ext2ReferXcb(&ParentDcb->ReferenceCount);
1798 bNewParentDcb = TRUE;
1799 }
1800 }
1801
1802 if (!Mcb) {
1803 Status = STATUS_NOT_A_REPARSE_POINT;
1804 _SEH2_LEAVE;
1805 }
1806
1807 Fcb = Ext2AllocateFcb (Vcb, Mcb);
1808 if (Fcb) {
1809 bFcbAllocated = TRUE;
1810 } else {
1811 Status = STATUS_INSUFFICIENT_RESOURCES;
1812 _SEH2_LEAVE;
1813 }
1814 Ext2ReferXcb(&Fcb->ReferenceCount);
1815
1816 if (!ExAcquireResourceSharedLite(
1817 &Fcb->MainResource,
1818 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
1819 Status = STATUS_PENDING;
1820 _SEH2_LEAVE;
1821 }
1822 MainResourceAcquired = TRUE;
1823
1824 Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
1825 if (!NT_SUCCESS(Status)) {
1826 _SEH2_LEAVE;
1827 }
1828 if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
1829 SetFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
1830 }
1831 ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
1832 ClearFlag(Mcb->Inode.i_flags, S_IFLNK);
1833 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1834 if (NT_SUCCESS(Status)) {
1835 Status = Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb);
1836 }
1837
1838 } _SEH2_FINALLY {
1839
1840 if (MainResourceAcquired) {
1841 ExReleaseResourceLite(&Fcb->MainResource);
1842 }
1843
1844 if (NT_SUCCESS(Status)) {
1845 Ext2NotifyReportChange(
1846 IrpContext,
1847 Vcb,
1848 Mcb,
1849 FILE_NOTIFY_CHANGE_ATTRIBUTES,
1850 FILE_ACTION_MODIFIED );
1851
1852 }
1853
1854 if (bNewParentDcb) {
1855 ASSERT(ParentDcb != NULL);
1856 if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
1857 Ext2FreeFcb(ParentDcb);
1858 ParentDcb = NULL;
1859 } else {
1860 DEBUG(DL_RES, ( "Ext2DeleteReparsePoint: ParentDcb is resued.\n"));
1861 }
1862 }
1863
1864 if (!_SEH2_AbnormalTermination()) {
1865 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
1866 Status = Ext2QueueRequest(IrpContext);
1867 } else {
1868 Ext2CompleteIrpContext(IrpContext, Status);
1869 }
1870 }
1871
1872 if (bFcbAllocated) {
1873 if (Ext2DerefXcb(&Fcb->ReferenceCount) == 0) {
1874 Ext2FreeFcb(Fcb);
1875 }
1876 }
1877 } _SEH2_END;
1878
1879 return Status;
1880 }
1881
1882 NTSTATUS
1883 Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
1884 {
1885 PIRP Irp;
1886 PIO_STACK_LOCATION IoStackLocation;
1887 ULONG FsControlCode;
1888 NTSTATUS Status;
1889
1890 ASSERT(IrpContext);
1891
1892 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
1893 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
1894
1895 Irp = IrpContext->Irp;
1896 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
1897
1898 #ifndef _GNU_NTIFS_
1899 FsControlCode =
1900 IoStackLocation->Parameters.FileSystemControl.FsControlCode;
1901 #else
1902 FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)
1903 IoStackLocation)->Parameters.FileSystemControl.FsControlCode;
1904 #endif
1905
1906 switch (FsControlCode) {
1907
1908 case FSCTL_GET_REPARSE_POINT:
1909 Status = Ext2GetReparsePoint(IrpContext);
1910 break;
1911
1912 case FSCTL_SET_REPARSE_POINT:
1913 Status = Ext2SetReparsePoint(IrpContext);
1914 break;
1915
1916 case FSCTL_DELETE_REPARSE_POINT:
1917 Status = Ext2DeleteReparsePoint(IrpContext);
1918 break;
1919
1920 case FSCTL_LOCK_VOLUME:
1921 Status = Ext2LockVolume(IrpContext);
1922 break;
1923
1924 case FSCTL_UNLOCK_VOLUME:
1925 Status = Ext2UnlockVolume(IrpContext);
1926 break;
1927
1928 case FSCTL_DISMOUNT_VOLUME:
1929 Status = Ext2DismountVolume(IrpContext);
1930 break;
1931
1932 case FSCTL_IS_VOLUME_MOUNTED:
1933 Status = Ext2IsVolumeMounted(IrpContext);
1934 break;
1935
1936 case FSCTL_INVALIDATE_VOLUMES:
1937 Status = Ext2InvalidateVolumes(IrpContext);
1938 break;
1939
1940 #if (_WIN32_WINNT >= 0x0500)
1941 case FSCTL_ALLOW_EXTENDED_DASD_IO:
1942 Status = Ext2AllowExtendedDasdIo(IrpContext);
1943 break;
1944 #endif //(_WIN32_WINNT >= 0x0500)
1945
1946 case FSCTL_REQUEST_OPLOCK_LEVEL_1:
1947 case FSCTL_REQUEST_OPLOCK_LEVEL_2:
1948 case FSCTL_REQUEST_BATCH_OPLOCK:
1949 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
1950 case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
1951 case FSCTL_OPLOCK_BREAK_NOTIFY:
1952 case FSCTL_OPLOCK_BREAK_ACK_NO_2:
1953
1954 Status = Ext2OplockRequest(IrpContext);
1955 break;
1956
1957 case FSCTL_IS_VOLUME_DIRTY:
1958 Status = Ext2IsVolumeDirty(IrpContext);
1959 break;
1960
1961 case FSCTL_QUERY_RETRIEVAL_POINTERS:
1962 Status = Ext2QueryRetrievalPointers(IrpContext);
1963 break;
1964
1965 case FSCTL_GET_RETRIEVAL_POINTERS:
1966 Status = Ext2GetRetrievalPointers(IrpContext);
1967 break;
1968
1969 case FSCTL_GET_RETRIEVAL_POINTER_BASE:
1970 Status = Ext2GetRetrievalPointerBase(IrpContext);
1971 break;
1972
1973 default:
1974
1975 DEBUG(DL_INF, ( "Ext2UserFsRequest: Invalid User Request: %xh.\n", FsControlCode));
1976 Status = STATUS_INVALID_DEVICE_REQUEST;
1977
1978 Ext2CompleteIrpContext(IrpContext, Status);
1979 }
1980
1981 return Status;
1982 }
1983
1984 BOOLEAN
1985 Ext2IsMediaWriteProtected (
1986 IN PEXT2_IRP_CONTEXT IrpContext,
1987 IN PDEVICE_OBJECT TargetDevice
1988 )
1989 {
1990 PIRP Irp;
1991 KEVENT Event;
1992 NTSTATUS Status;
1993 IO_STATUS_BLOCK IoStatus;
1994
1995 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1996
1997 Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
1998 TargetDevice,
1999 NULL,
2000 0,
2001 NULL,
2002 0,
2003 FALSE,
2004 &Event,
2005 &IoStatus );
2006
2007 if (Irp == NULL) {
2008 return FALSE;
2009 }
2010
2011 SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
2012
2013 Status = IoCallDriver(TargetDevice, Irp);
2014
2015 if (Status == STATUS_PENDING) {
2016
2017 (VOID) KeWaitForSingleObject( &Event,
2018 Executive,
2019 KernelMode,
2020 FALSE,
2021 (PLARGE_INTEGER)NULL );
2022
2023 Status = IoStatus.Status;
2024 }
2025
2026 return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
2027 }
2028
2029 NTSTATUS
2030 Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2031 {
2032 PDEVICE_OBJECT MainDeviceObject;
2033 BOOLEAN GlobalDataResourceAcquired = FALSE;
2034 PIRP Irp;
2035 PIO_STACK_LOCATION IoStackLocation;
2036 PDEVICE_OBJECT TargetDeviceObject;
2037 NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
2038 PDEVICE_OBJECT VolumeDeviceObject = NULL;
2039 PEXT2_VCB Vcb = NULL, OldVcb = NULL;
2040 PVPB OldVpb = NULL, Vpb = NULL;
2041 PEXT2_SUPER_BLOCK Ext2Sb = NULL;
2042 ULONG dwBytes;
2043 DISK_GEOMETRY DiskGeometry;
2044
2045 _SEH2_TRY {
2046
2047 ASSERT(IrpContext != NULL);
2048 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2049 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2050
2051 MainDeviceObject = IrpContext->DeviceObject;
2052
2053 //
2054 // Make sure we can wait.
2055 //
2056
2057 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
2058
2059 //
2060 // This request is only allowed on the main device object
2061 //
2062 if (!IsExt2FsDevice(MainDeviceObject)) {
2063 Status = STATUS_INVALID_DEVICE_REQUEST;
2064 _SEH2_LEAVE;
2065 }
2066
2067 if (IsFlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) {
2068 Status = STATUS_UNRECOGNIZED_VOLUME;
2069 _SEH2_LEAVE;
2070 }
2071
2072 #if 0
2073 if (IrpContext->RealDevice->Size >= sizeof(ULONG) + sizeof(DEVICE_OBJECT) &&
2074 *((PULONG)IrpContext->RealDevice->DeviceExtension) == 'DSSA') {
2075 } else {
2076 Status = STATUS_UNRECOGNIZED_VOLUME;
2077 _SEH2_LEAVE;
2078 }
2079 #endif
2080
2081 Irp = IrpContext->Irp;
2082 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
2083 TargetDeviceObject =
2084 IoStackLocation->Parameters.MountVolume.DeviceObject;
2085
2086 dwBytes = sizeof(DISK_GEOMETRY);
2087 Status = Ext2DiskIoControl(
2088 TargetDeviceObject,
2089 IOCTL_DISK_GET_DRIVE_GEOMETRY,
2090 NULL,
2091 0,
2092 &DiskGeometry,
2093 &dwBytes );
2094
2095 if (!NT_SUCCESS(Status)) {
2096 _SEH2_LEAVE;
2097 }
2098
2099 Status = IoCreateDevice(
2100 MainDeviceObject->DriverObject,
2101 sizeof(EXT2_VCB),
2102 NULL,
2103 FILE_DEVICE_DISK_FILE_SYSTEM,
2104 0,
2105 FALSE,
2106 &VolumeDeviceObject );
2107
2108 if (!NT_SUCCESS(Status)) {
2109 _SEH2_LEAVE;
2110 }
2111 INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
2112
2113 VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
2114 ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
2115
2116 /*
2117 These are for buffer-address alignment requirements.
2118 Never do this check, unless you want fail user requests :)
2119
2120 if (TargetDeviceObject->AlignmentRequirement >
2121 VolumeDeviceObject->AlignmentRequirement) {
2122
2123 VolumeDeviceObject->AlignmentRequirement =
2124 TargetDeviceObject->AlignmentRequirement;
2125 }
2126
2127 if (DiskGeometry.BytesPerSector - 1 >
2128 VolumeDeviceObject->AlignmentRequirement) {
2129 VolumeDeviceObject->AlignmentRequirement =
2130 DiskGeometry.BytesPerSector - 1;
2131 TargetDeviceObject->AlignmentRequirement =
2132 DiskGeometry.BytesPerSector - 1;
2133 }
2134 */
2135 (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
2136 VolumeDeviceObject;
2137 Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
2138
2139 Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension;
2140
2141 RtlZeroMemory(Vcb, sizeof(EXT2_VCB));
2142 Vcb->Identifier.Type = EXT2VCB;
2143 Vcb->Identifier.Size = sizeof(EXT2_VCB);
2144 Vcb->TargetDeviceObject = TargetDeviceObject;
2145 Vcb->DiskGeometry = DiskGeometry;
2146 InitializeListHead(&Vcb->Next);
2147
2148 Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb);
2149 if (!NT_SUCCESS(Status)) {
2150 Vcb = NULL;
2151 Status = STATUS_UNRECOGNIZED_VOLUME;
2152 _SEH2_LEAVE;
2153 }
2154 ASSERT (NULL != Ext2Sb);
2155
2156 /* check Linux Ext2/Ext3 volume magic */
2157 if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) {
2158 DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n"));
2159 } else {
2160 Status = STATUS_UNRECOGNIZED_VOLUME;
2161 Vcb = NULL;
2162 _SEH2_LEAVE;
2163 }
2164
2165 DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb));
2166
2167 /* initialize Vcb structure */
2168 Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb,
2169 TargetDeviceObject,
2170 VolumeDeviceObject, Vpb);
2171
2172 if (NT_SUCCESS(Status)) {
2173
2174 PLIST_ENTRY List;
2175
2176 ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE);
2177 GlobalDataResourceAcquired = TRUE;
2178
2179 for (List = Ext2Global->VcbList.Flink;
2180 List != &Ext2Global->VcbList;
2181 List = List->Flink) {
2182
2183 OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
2184 OldVpb = OldVcb->Vpb;
2185
2186 /* in case we are already in the queue, should not happen */
2187 if (OldVpb == Vpb) {
2188 continue;
2189 }
2190
2191 if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
2192 (!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) &&
2193 (OldVpb->RealDevice == TargetDeviceObject) &&
2194 (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
2195 (RtlEqualMemory(&OldVpb->VolumeLabel[0],
2196 &Vpb->VolumeLabel[0],
2197 Vpb->VolumeLabelLength)) &&
2198 (RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0],
2199 &Vcb->SuperBlock->s_uuid[0], 16)) ) {
2200 ClearFlag(OldVcb->Flags, VCB_MOUNTED);
2201 }
2202 }
2203
2204 SetLongFlag(Vcb->Flags, VCB_MOUNTED);
2205 SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED);
2206 Ext2InsertVcb(Vcb);
2207 Vcb = NULL;
2208 Vpb = NULL;
2209 ObDereferenceObject(TargetDeviceObject);
2210
2211 } else {
2212
2213 Vcb = NULL;
2214 }
2215
2216 } _SEH2_FINALLY {
2217
2218 if (GlobalDataResourceAcquired) {
2219 ExReleaseResourceLite(&Ext2Global->Resource);
2220 }
2221
2222 if (!NT_SUCCESS(Status)) {
2223
2224 if (!NT_SUCCESS(Status)) {
2225 if ( Vpb != NULL ) {
2226 Vpb->DeviceObject = NULL;
2227 }
2228 }
2229
2230 if (Vcb) {
2231 Ext2DestroyVcb(Vcb);
2232 } else {
2233 if (Ext2Sb) {
2234 Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
2235 }
2236 if (VolumeDeviceObject) {
2237 IoDeleteDevice(VolumeDeviceObject);
2238 DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
2239 }
2240 }
2241 }
2242
2243 if (!IrpContext->ExceptionInProgress) {
2244 Ext2CompleteIrpContext(IrpContext, Status);
2245 }
2246 } _SEH2_END;
2247
2248 return Status;
2249 }
2250
2251 VOID
2252 Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext,
2253 IN PEXT2_VCB Vcb )
2254 {
2255 NTSTATUS Status = STATUS_SUCCESS;
2256
2257 BOOLEAN bVerify = FALSE;
2258 ULONG ChangeCount = 0;
2259 ULONG dwBytes;
2260
2261 PIRP Irp;
2262 PEXTENDED_IO_STACK_LOCATION IrpSp;
2263
2264 _SEH2_TRY {
2265
2266 ASSERT(IrpContext != NULL);
2267
2268 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2269 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2270
2271 Irp = IrpContext->Irp;
2272 IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
2273
2274 bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2275
2276 if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) ||
2277 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) {
2278
2279 dwBytes = sizeof(ULONG);
2280 Status = Ext2DiskIoControl(
2281 Vcb->TargetDeviceObject,
2282 IOCTL_DISK_CHECK_VERIFY,
2283 NULL,
2284 0,
2285 &ChangeCount,
2286 &dwBytes );
2287
2288 if ( STATUS_VERIFY_REQUIRED == Status ||
2289 STATUS_DEVICE_NOT_READY == Status ||
2290 STATUS_NO_MEDIA_IN_DEVICE == Status ||
2291 (NT_SUCCESS(Status) &&
2292 (ChangeCount != Vcb->ChangeCount))) {
2293
2294 KIRQL Irql;
2295
2296 IoAcquireVpbSpinLock(&Irql);
2297 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
2298 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2299 }
2300 IoReleaseVpbSpinLock(Irql);
2301
2302 } else {
2303
2304 if (!NT_SUCCESS(Status)) {
2305 Ext2NormalizeAndRaiseStatus(IrpContext, Status);
2306 }
2307 }
2308 }
2309
2310 if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
2311 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
2312 Ext2NormalizeAndRaiseStatus ( IrpContext,
2313 STATUS_VERIFY_REQUIRED );
2314 }
2315
2316 if (IsMounted(Vcb)) {
2317
2318 if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
2319 (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
2320 (IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
2321 (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
2322 (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
2323 (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
2324 IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
2325 IrpSp->Parameters.FileSystemControl.FsControlCode ==
2326 FSCTL_MARK_VOLUME_DIRTY)) {
2327
2328 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
2329
2330 KIRQL Irql;
2331
2332 IoAcquireVpbSpinLock(&Irql);
2333 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
2334 SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
2335 }
2336 IoReleaseVpbSpinLock(Irql);
2337
2338 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
2339
2340 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
2341 }
2342 }
2343 }
2344
2345 } _SEH2_FINALLY {
2346
2347 } _SEH2_END;
2348
2349 }
2350
2351
2352 NTSTATUS
2353 Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2354 {
2355 PDEVICE_OBJECT DeviceObject;
2356 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2357 PEXT2_SUPER_BLOCK ext2_sb = NULL;
2358 PEXT2_VCB Vcb = NULL;
2359 BOOLEAN VcbResourceAcquired = FALSE;
2360 PIRP Irp;
2361 ULONG ChangeCount = 0;
2362 ULONG dwBytes;
2363
2364 _SEH2_TRY {
2365
2366 ASSERT(IrpContext != NULL);
2367 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2368 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2369
2370 DeviceObject = IrpContext->DeviceObject;
2371 //
2372 // This request is not allowed on the main device object
2373 //
2374 if (IsExt2FsDevice(DeviceObject)) {
2375 Status = STATUS_INVALID_DEVICE_REQUEST;
2376 _SEH2_LEAVE;
2377 }
2378
2379 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2380 ASSERT(Vcb != NULL);
2381 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2382 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2383
2384 VcbResourceAcquired =
2385 ExAcquireResourceExclusiveLite(
2386 &Vcb->MainResource,
2387 TRUE );
2388
2389 if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
2390 Status = STATUS_SUCCESS;
2391 _SEH2_LEAVE;
2392 }
2393
2394 if (!IsMounted(Vcb)) {
2395 Status = STATUS_WRONG_VOLUME;
2396 _SEH2_LEAVE;
2397 }
2398
2399 dwBytes = sizeof(ULONG);
2400 Status = Ext2DiskIoControl(
2401 Vcb->TargetDeviceObject,
2402 IOCTL_DISK_CHECK_VERIFY,
2403 NULL,
2404 0,
2405 &ChangeCount,
2406 &dwBytes );
2407
2408
2409 if (!NT_SUCCESS(Status)) {
2410 Status = STATUS_WRONG_VOLUME;
2411 _SEH2_LEAVE;
2412 } else {
2413 Vcb->ChangeCount = ChangeCount;
2414 }
2415
2416 Irp = IrpContext->Irp;
2417
2418 Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb);
2419
2420 if (!NT_SUCCESS(Status)) {
2421 _SEH2_LEAVE;
2422 }
2423
2424 ASSERT(NULL != ext2_sb);
2425 if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) &&
2426 (memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
2427 (memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) {
2428
2429 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
2430
2431 if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
2432 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2433 } else {
2434 ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
2435 }
2436
2437 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n"));
2438
2439 } else {
2440
2441 Status = STATUS_WRONG_VOLUME;
2442 if (VcbResourceAcquired) {
2443 ExReleaseResourceLite(&Vcb->MainResource);
2444 VcbResourceAcquired = FALSE;
2445 }
2446 Ext2PurgeVolume(Vcb, FALSE);
2447 VcbResourceAcquired =
2448 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
2449
2450 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
2451 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
2452
2453 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n"));
2454 }
2455
2456 } _SEH2_FINALLY {
2457
2458 if (ext2_sb)
2459 Ext2FreePool(ext2_sb, EXT2_SB_MAGIC);
2460
2461 if (VcbResourceAcquired) {
2462 ExReleaseResourceLite(&Vcb->MainResource);
2463 }
2464
2465 if (!IrpContext->ExceptionInProgress) {
2466 Ext2CompleteIrpContext(IrpContext, Status);
2467 }
2468 } _SEH2_END;
2469
2470 return Status;
2471 }
2472
2473
2474 NTSTATUS
2475 Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext)
2476 {
2477 PDEVICE_OBJECT DeviceObject;
2478 PEXT2_VCB Vcb = 0;
2479 NTSTATUS Status = STATUS_SUCCESS;
2480
2481 ASSERT(IrpContext);
2482
2483 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2484 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2485
2486
2487 DeviceObject = IrpContext->DeviceObject;
2488
2489 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2490
2491 ASSERT(IsMounted(Vcb));
2492
2493 Ext2VerifyVcb (IrpContext, Vcb);
2494
2495 Ext2CompleteIrpContext(IrpContext, Status);
2496
2497 return Status;
2498 }
2499
2500
2501 NTSTATUS
2502 Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
2503 {
2504 PDEVICE_OBJECT DeviceObject;
2505 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2506 PEXT2_VCB Vcb = NULL;
2507 BOOLEAN VcbResourceAcquired = FALSE;
2508
2509 _SEH2_TRY {
2510
2511 ASSERT(IrpContext != NULL);
2512
2513 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2514 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2515
2516 DeviceObject = IrpContext->DeviceObject;
2517
2518 //
2519 // This request is not allowed on the main device object
2520 //
2521 if (IsExt2FsDevice(DeviceObject)) {
2522 Status = STATUS_INVALID_DEVICE_REQUEST;
2523 _SEH2_LEAVE;
2524 }
2525
2526 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
2527
2528 ASSERT(Vcb != NULL);
2529
2530 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2531 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2532
2533 ASSERT(IsMounted(Vcb));
2534
2535 ExAcquireResourceExclusiveLite(
2536 &Vcb->MainResource,
2537 TRUE );
2538
2539 VcbResourceAcquired = TRUE;
2540
2541 if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
2542 Status = STATUS_VOLUME_DISMOUNTED;
2543 _SEH2_LEAVE;
2544 }
2545
2546 Ext2FlushFiles(IrpContext, Vcb, FALSE);
2547 Ext2FlushVolume(IrpContext, Vcb, FALSE);
2548
2549 ExReleaseResourceLite(&Vcb->MainResource);
2550 VcbResourceAcquired = FALSE;
2551
2552 Ext2PurgeVolume(Vcb, TRUE);
2553 Ext2CheckDismount(IrpContext, Vcb, TRUE);
2554
2555 DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n"));
2556 Status = STATUS_SUCCESS;
2557
2558 } _SEH2_FINALLY {
2559
2560 if (VcbResourceAcquired) {
2561 ExReleaseResourceLite(&Vcb->MainResource);
2562 }
2563
2564 if (!IrpContext->ExceptionInProgress) {
2565 Ext2CompleteIrpContext(IrpContext, Status);
2566 }
2567 } _SEH2_END;
2568
2569 return Status;
2570 }
2571
2572 BOOLEAN
2573 Ext2CheckDismount (
2574 IN PEXT2_IRP_CONTEXT IrpContext,
2575 IN PEXT2_VCB Vcb,
2576 IN BOOLEAN bForce )
2577 {
2578 KIRQL Irql;
2579 PVPB Vpb = Vcb->Vpb, NewVpb = NULL;
2580 BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
2581 ULONG UnCleanCount = 0;
2582
2583 NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB);
2584 if (NewVpb == NULL) {
2585 DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
2586 return FALSE;
2587 }
2588 DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb));
2589 INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
2590 memset(NewVpb, '_', VPB_SIZE);
2591 RtlZeroMemory(NewVpb, sizeof(VPB));
2592
2593 ExAcquireResourceExclusiveLite(
2594 &Ext2Global->Resource, TRUE );
2595
2596 ExAcquireResourceExclusiveLite(
2597 &Vcb->MainResource, TRUE );
2598
2599 if ((IrpContext->MajorFunction == IRP_MJ_CREATE) &&
2600 (IrpContext->RealDevice == Vcb->RealDevice)) {
2601 UnCleanCount = 2;
2602 } else {
2603 UnCleanCount = 1;
2604 }
2605
2606 IoAcquireVpbSpinLock (&Irql);
2607
2608 DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
2609 Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
2610
2611 if (Vpb->ReferenceCount <= UnCleanCount) {
2612
2613 if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
2614
2615 ClearFlag(Vpb->Flags, VPB_MOUNTED);
2616 ClearFlag(Vpb->Flags, VPB_LOCKED);
2617
2618 if ((Vcb->RealDevice != Vpb->RealDevice) &&
2619 (Vcb->RealDevice->Vpb == Vpb)) {
2620 SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING);
2621 SetFlag(Vpb->Flags, VPB_PERSISTENT );
2622 }
2623
2624 Ext2RemoveVcb(Vcb);
2625 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
2626 }
2627
2628 if (Vpb->ReferenceCount) {
2629 bTearDown = TRUE;
2630 } else {
2631 bDeleted = TRUE;
2632 Vpb->DeviceObject = NULL;
2633 }
2634
2635 DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n",
2636 Vpb, bDeleted, bTearDown));
2637
2638
2639 } else if (bForce) {
2640
2641 DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n",
2642 NewVpb, Vcb->Vpb, Vpb->RealDevice));
2643
2644 /* keep vpb president and later we'll free it */
2645 SetFlag(Vpb->Flags, VPB_PERSISTENT);
2646
2647 Vcb->Vpb2 = Vcb->Vpb;
2648 NewVpb->Type = IO_TYPE_VPB;
2649 NewVpb->Size = sizeof(VPB);
2650 NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING;
2651 NewVpb->RealDevice = Vpb->RealDevice;
2652 NewVpb->RealDevice->Vpb = NewVpb;
2653 NewVpb = NULL;
2654 ClearFlag(Vpb->Flags, VPB_MOUNTED);
2655 SetLongFlag(Vcb->Flags, VCB_NEW_VPB);
2656 ClearLongFlag(Vcb->Flags, VCB_MOUNTED);
2657 }
2658
2659 IoReleaseVpbSpinLock(Irql);
2660
2661 ExReleaseResourceLite(&Vcb->MainResource);
2662 ExReleaseResourceLite(&Ext2Global->Resource);
2663
2664 if (bTearDown) {
2665 DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb));
2666 Ext2TearDownStream(Vcb);
2667 }
2668
2669 if (bDeleted) {
2670 DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb));
2671 Ext2DestroyVcb(Vcb);
2672 }
2673
2674 if (NewVpb != NULL) {
2675 DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb));
2676 ExFreePoolWithTag(NewVpb, TAG_VPB);
2677 DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
2678 }
2679
2680 return bDeleted;
2681 }
2682
2683 NTSTATUS
2684 Ext2PurgeVolume (IN PEXT2_VCB Vcb,
2685 IN BOOLEAN FlushBeforePurge )
2686 {
2687 PEXT2_FCB Fcb;
2688 LIST_ENTRY FcbList;
2689 PLIST_ENTRY ListEntry;
2690 PFCB_LIST_ENTRY FcbListEntry;
2691 BOOLEAN VcbResourceAcquired = FALSE;
2692 _SEH2_TRY {
2693
2694 ASSERT(Vcb != NULL);
2695 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
2696 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
2697
2698 VcbResourceAcquired =
2699 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
2700
2701 if (IsVcbReadOnly(Vcb)) {
2702 FlushBeforePurge = FALSE;
2703 }
2704
2705 FcbListEntry= NULL;
2706 InitializeListHead(&FcbList);
2707
2708 for (ListEntry = Vcb->FcbList.Flink;
2709 ListEntry != &Vcb->FcbList;
2710 ListEntry = ListEntry->Flink ) {
2711
2712 Fcb = CONTAINING_RECORD(ListEntry, EXT2_FCB, Next);
2713
2714 DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n", &Fcb->Mcb->FullName, Fcb->ReferenceCount));
2715
2716 FcbListEntry = Ext2AllocatePool(
2717 PagedPool,
2718 sizeof(FCB_LIST_ENTRY),
2719 EXT2_FLIST_MAGIC
2720 );
2721
2722 if (FcbListEntry) {
2723 FcbListEntry->Fcb = Fcb;
2724 Ext2ReferXcb(&Fcb->ReferenceCount);
2725 InsertTailList(&FcbList, &FcbListEntry->Next);
2726 } else {
2727 DEBUG(DL_ERR, ( "Ext2PurgeVolume: failed to allocate FcbListEntry ...\n"));
2728 }
2729 }
2730
2731 while (!IsListEmpty(&FcbList)) {
2732
2733 ListEntry = RemoveHeadList(&FcbList);
2734
2735 FcbListEntry = CONTAINING_RECORD(ListEntry, FCB_LIST_ENTRY, Next);
2736
2737 Fcb = FcbListEntry->Fcb;
2738
2739 if (ExAcquireResourceExclusiveLite(
2740 &Fcb->MainResource,
2741 TRUE )) {
2742
2743 Ext2PurgeFile(Fcb, FlushBeforePurge);
2744
2745 if (!Fcb->OpenHandleCount && Fcb->ReferenceCount == 1) {
2746 Ext2FreeFcb(Fcb);
2747 } else {
2748 ExReleaseResourceLite(&Fcb->MainResource);
2749 }
2750 }
2751
2752 Ext2FreePool(FcbListEntry, EXT2_FLIST_MAGIC);
2753 }
2754
2755 if (FlushBeforePurge) {
2756 ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
2757 ExReleaseResourceLite(&Vcb->PagingIoResource);
2758
2759 CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
2760 }
2761
2762 if (Vcb->SectionObject.ImageSectionObject) {
2763 MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
2764 }
2765
2766 if (VcbResourceAcquired) {
2767 ExReleaseResourceLite(&Vcb->MainResource);
2768 VcbResourceAcquired = FALSE;
2769 }
2770
2771 if (Vcb->SectionObject.DataSectionObject) {
2772 CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
2773 }
2774
2775 DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n"));
2776
2777 } _SEH2_FINALLY {
2778
2779 if (VcbResourceAcquired) {
2780 ExReleaseResourceLite(&Vcb->MainResource);
2781 }
2782 } _SEH2_END;
2783
2784 return STATUS_SUCCESS;
2785 }
2786
2787 NTSTATUS
2788 Ext2PurgeFile ( IN PEXT2_FCB Fcb,
2789 IN BOOLEAN FlushBeforePurge )
2790 {
2791 IO_STATUS_BLOCK IoStatus;
2792
2793 ASSERT(Fcb != NULL);
2794
2795 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
2796 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
2797
2798
2799 if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
2800
2801 DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
2802 &Fcb->Mcb->FullName));
2803
2804 ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
2805 ExReleaseResourceLite(&Fcb->PagingIoResource);
2806
2807 CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
2808 ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
2809 }
2810
2811 if (Fcb->SectionObject.ImageSectionObject) {
2812
2813 DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
2814 &Fcb->Mcb->FullName));
2815
2816 MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
2817 }
2818
2819 if (Fcb->SectionObject.DataSectionObject) {
2820
2821 DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
2822 &Fcb->Mcb->FullName));
2823
2824 CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
2825 }
2826
2827 return STATUS_SUCCESS;
2828 }
2829
2830
2831 NTSTATUS
2832 Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext)
2833 {
2834 NTSTATUS Status;
2835
2836 ASSERT(IrpContext);
2837
2838 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
2839 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
2840
2841 switch (IrpContext->MinorFunction) {
2842
2843 case IRP_MN_USER_FS_REQUEST:
2844 Status = Ext2UserFsRequest(IrpContext);
2845 break;
2846
2847 case IRP_MN_MOUNT_VOLUME:
2848 Status = Ext2MountVolume(IrpContext);
2849 break;
2850
2851 case IRP_MN_VERIFY_VOLUME:
2852 Status = Ext2VerifyVolume(IrpContext);
2853 break;
2854
2855 default:
2856
2857 DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n"));
2858 Status = STATUS_INVALID_DEVICE_REQUEST;
2859 Ext2CompleteIrpContext(IrpContext, Status);
2860 }
2861
2862 return Status;
2863 }