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