xref: /reactos/drivers/filesystems/ntfs/blockdev.c (revision 34593d93)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  *  ReactOS kernel
3c2c66affSColin Finck  *  Copyright (C) 2002 ReactOS Team
4c2c66affSColin Finck  *
5c2c66affSColin Finck  *  This program is free software; you can redistribute it and/or modify
6c2c66affSColin Finck  *  it under the terms of the GNU General Public License as published by
7c2c66affSColin Finck  *  the Free Software Foundation; either version 2 of the License, or
8c2c66affSColin Finck  *  (at your option) any later version.
9c2c66affSColin Finck  *
10c2c66affSColin Finck  *  This program is distributed in the hope that it will be useful,
11c2c66affSColin Finck  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12c2c66affSColin Finck  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13c2c66affSColin Finck  *  GNU General Public License for more details.
14c2c66affSColin Finck  *
15c2c66affSColin Finck  *  You should have received a copy of the GNU General Public License
16c2c66affSColin Finck  *  along with this program; if not, write to the Free Software
17c2c66affSColin Finck  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18c2c66affSColin Finck  *
19c2c66affSColin Finck  * COPYRIGHT:        See COPYING in the top level directory
20c2c66affSColin Finck  * PROJECT:          ReactOS kernel
21c2c66affSColin Finck  * FILE:             drivers/filesystem/ntfs/blockdev.c
22c2c66affSColin Finck  * PURPOSE:          NTFS filesystem driver
2358a13831STrevor Thompson  * PROGRAMMERS:      Eric Kohl
2458a13831STrevor Thompson  *                   Trevor Thompson
25c2c66affSColin Finck  */
26c2c66affSColin Finck 
27c2c66affSColin Finck /* INCLUDES *****************************************************************/
28c2c66affSColin Finck 
29c2c66affSColin Finck #include "ntfs.h"
30c2c66affSColin Finck 
31c2c66affSColin Finck #define NDEBUG
32c2c66affSColin Finck #include <debug.h>
33c2c66affSColin Finck 
34c2c66affSColin Finck /* FUNCTIONS ****************************************************************/
35c2c66affSColin Finck 
36c2c66affSColin Finck NTSTATUS
NtfsReadDisk(IN PDEVICE_OBJECT DeviceObject,IN LONGLONG StartingOffset,IN ULONG Length,IN ULONG SectorSize,IN OUT PUCHAR Buffer,IN BOOLEAN Override)37c2c66affSColin Finck NtfsReadDisk(IN PDEVICE_OBJECT DeviceObject,
38c2c66affSColin Finck              IN LONGLONG StartingOffset,
39c2c66affSColin Finck              IN ULONG Length,
40c2c66affSColin Finck              IN ULONG SectorSize,
41c2c66affSColin Finck              IN OUT PUCHAR Buffer,
42c2c66affSColin Finck              IN BOOLEAN Override)
43c2c66affSColin Finck {
44c2c66affSColin Finck     PIO_STACK_LOCATION Stack;
45c2c66affSColin Finck     IO_STATUS_BLOCK IoStatus;
46c2c66affSColin Finck     LARGE_INTEGER Offset;
47c2c66affSColin Finck     KEVENT Event;
48c2c66affSColin Finck     PIRP Irp;
49c2c66affSColin Finck     NTSTATUS Status;
50c2c66affSColin Finck     ULONGLONG RealReadOffset;
51c2c66affSColin Finck     ULONG RealLength;
52c2c66affSColin Finck     BOOLEAN AllocatedBuffer = FALSE;
53c2c66affSColin Finck     PUCHAR ReadBuffer = Buffer;
54c2c66affSColin Finck 
55*38c947b7STrevor Thompson     DPRINT("NtfsReadDisk(%p, %I64x, %lu, %lu, %p, %d)\n", DeviceObject, StartingOffset, Length, SectorSize, Buffer, Override);
56c2c66affSColin Finck 
57c2c66affSColin Finck     KeInitializeEvent(&Event,
58c2c66affSColin Finck                       NotificationEvent,
59c2c66affSColin Finck                       FALSE);
60c2c66affSColin Finck 
61c2c66affSColin Finck     RealReadOffset = (ULONGLONG)StartingOffset;
62c2c66affSColin Finck     RealLength = Length;
63c2c66affSColin Finck 
64c2c66affSColin Finck     if ((RealReadOffset % SectorSize) != 0 || (RealLength % SectorSize) != 0)
65c2c66affSColin Finck     {
66c2c66affSColin Finck         RealReadOffset = ROUND_DOWN(StartingOffset, SectorSize);
67c2c66affSColin Finck         RealLength = ROUND_UP(Length, SectorSize);
68c2c66affSColin Finck 
69c2c66affSColin Finck         ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength + SectorSize, TAG_NTFS);
70c2c66affSColin Finck         if (ReadBuffer == NULL)
71c2c66affSColin Finck         {
72c2c66affSColin Finck             DPRINT1("Not enough memory!\n");
73c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
74c2c66affSColin Finck         }
75c2c66affSColin Finck         AllocatedBuffer = TRUE;
76c2c66affSColin Finck     }
77c2c66affSColin Finck 
78c2c66affSColin Finck     Offset.QuadPart = RealReadOffset;
79c2c66affSColin Finck 
80c2c66affSColin Finck     DPRINT("Building synchronous FSD Request...\n");
81c2c66affSColin Finck     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
82c2c66affSColin Finck                                        DeviceObject,
83c2c66affSColin Finck                                        ReadBuffer,
84c2c66affSColin Finck                                        RealLength,
85c2c66affSColin Finck                                        &Offset,
86c2c66affSColin Finck                                        &Event,
87c2c66affSColin Finck                                        &IoStatus);
88c2c66affSColin Finck     if (Irp == NULL)
89c2c66affSColin Finck     {
90c2c66affSColin Finck         DPRINT("IoBuildSynchronousFsdRequest failed\n");
91c2c66affSColin Finck 
92c2c66affSColin Finck         if (AllocatedBuffer)
93c2c66affSColin Finck         {
94c2c66affSColin Finck             ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
95c2c66affSColin Finck         }
96c2c66affSColin Finck 
97c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
98c2c66affSColin Finck     }
99c2c66affSColin Finck 
100c2c66affSColin Finck     if (Override)
101c2c66affSColin Finck     {
102c2c66affSColin Finck         Stack = IoGetNextIrpStackLocation(Irp);
103c2c66affSColin Finck         Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
104c2c66affSColin Finck     }
105c2c66affSColin Finck 
106c2c66affSColin Finck     DPRINT("Calling IO Driver... with irp %p\n", Irp);
107c2c66affSColin Finck     Status = IoCallDriver(DeviceObject, Irp);
108c2c66affSColin Finck 
109c2c66affSColin Finck     DPRINT("Waiting for IO Operation for %p\n", Irp);
110c2c66affSColin Finck     if (Status == STATUS_PENDING)
111c2c66affSColin Finck     {
112c2c66affSColin Finck         DPRINT("Operation pending\n");
113c2c66affSColin Finck         KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
114c2c66affSColin Finck         DPRINT("Getting IO Status... for %p\n", Irp);
115c2c66affSColin Finck         Status = IoStatus.Status;
116c2c66affSColin Finck     }
117c2c66affSColin Finck 
118c2c66affSColin Finck     if (AllocatedBuffer)
119c2c66affSColin Finck     {
120c2c66affSColin Finck         if (NT_SUCCESS(Status))
121c2c66affSColin Finck         {
122c2c66affSColin Finck             RtlCopyMemory(Buffer, ReadBuffer + (StartingOffset - RealReadOffset), Length);
123c2c66affSColin Finck         }
124c2c66affSColin Finck 
125c2c66affSColin Finck         ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
126c2c66affSColin Finck     }
127c2c66affSColin Finck 
128c2c66affSColin Finck     DPRINT("NtfsReadDisk() done (Status %x)\n", Status);
129c2c66affSColin Finck 
130c2c66affSColin Finck     return Status;
131c2c66affSColin Finck }
132c2c66affSColin Finck 
13358a13831STrevor Thompson /**
13458a13831STrevor Thompson * @name NtfsWriteDisk
13558a13831STrevor Thompson * @implemented
13658a13831STrevor Thompson *
13758a13831STrevor Thompson * Writes data from the given buffer to the given DeviceObject.
13858a13831STrevor Thompson *
13958a13831STrevor Thompson * @param DeviceObject
14058a13831STrevor Thompson * Device to write to
14158a13831STrevor Thompson *
14258a13831STrevor Thompson * @param StartingOffset
14358a13831STrevor Thompson * Offset, in bytes, from the start of the device object where the data will be written
14458a13831STrevor Thompson *
14558a13831STrevor Thompson * @param Length
14658a13831STrevor Thompson * How much data will be written, in bytes
14758a13831STrevor Thompson *
14858a13831STrevor Thompson * @param SectorSize
14958a13831STrevor Thompson * Size of the sector on the disk that the write must be aligned to
15058a13831STrevor Thompson *
15158a13831STrevor Thompson * @param Buffer
15258a13831STrevor Thompson * The data that's being written to the device
15358a13831STrevor Thompson *
15458a13831STrevor Thompson * @return
15558a13831STrevor Thompson * STATUS_SUCCESS in case of success, STATUS_INSUFFICIENT_RESOURCES if a memory allocation failed,
15658a13831STrevor Thompson * or whatever status IoCallDriver() sets.
15758a13831STrevor Thompson *
15858a13831STrevor Thompson * @remarks Called by NtfsWriteFile(). May perform a read-modify-write operation if the
15958a13831STrevor Thompson * requested write is not sector-aligned.
16058a13831STrevor Thompson *
16158a13831STrevor Thompson */
16258a13831STrevor Thompson NTSTATUS
NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject,IN LONGLONG StartingOffset,IN ULONG Length,IN ULONG SectorSize,IN const PUCHAR Buffer)16358a13831STrevor Thompson NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject,
16458a13831STrevor Thompson               IN LONGLONG StartingOffset,
16558a13831STrevor Thompson               IN ULONG Length,
16658a13831STrevor Thompson               IN ULONG SectorSize,
16758a13831STrevor Thompson               IN const PUCHAR Buffer)
16858a13831STrevor Thompson {
16958a13831STrevor Thompson     IO_STATUS_BLOCK IoStatus;
17058a13831STrevor Thompson     LARGE_INTEGER Offset;
17158a13831STrevor Thompson     KEVENT Event;
17258a13831STrevor Thompson     PIRP Irp;
17358a13831STrevor Thompson     NTSTATUS Status;
17458a13831STrevor Thompson     ULONGLONG RealWriteOffset;
17558a13831STrevor Thompson     ULONG RealLength;
17658a13831STrevor Thompson     BOOLEAN AllocatedBuffer = FALSE;
17758a13831STrevor Thompson     PUCHAR TempBuffer = NULL;
17858a13831STrevor Thompson 
179*38c947b7STrevor Thompson     DPRINT("NtfsWriteDisk(%p, %I64x, %lu, %lu, %p)\n", DeviceObject, StartingOffset, Length, SectorSize, Buffer);
18058a13831STrevor Thompson 
18158a13831STrevor Thompson     if (Length == 0)
18258a13831STrevor Thompson         return STATUS_SUCCESS;
18358a13831STrevor Thompson 
18458a13831STrevor Thompson     RealWriteOffset = (ULONGLONG)StartingOffset;
18558a13831STrevor Thompson     RealLength = Length;
18658a13831STrevor Thompson 
18758a13831STrevor Thompson     // Does the write need to be adjusted to be sector-aligned?
18858a13831STrevor Thompson     if ((RealWriteOffset % SectorSize) != 0 || (RealLength % SectorSize) != 0)
18958a13831STrevor Thompson     {
19058a13831STrevor Thompson         ULONGLONG relativeOffset;
19158a13831STrevor Thompson 
19258a13831STrevor Thompson         // We need to do a read-modify-write. We'll start be copying the entire
19358a13831STrevor Thompson         // contents of every sector that will be overwritten.
19458a13831STrevor Thompson         // TODO: Optimize (read no more than necessary)
19558a13831STrevor Thompson 
19658a13831STrevor Thompson         RealWriteOffset = ROUND_DOWN(StartingOffset, SectorSize);
19758a13831STrevor Thompson         RealLength = ROUND_UP(Length, SectorSize);
19858a13831STrevor Thompson 
19958a13831STrevor Thompson         // Would the end of our sector-aligned write fall short of the requested write?
20058a13831STrevor Thompson         if (RealWriteOffset + RealLength < StartingOffset + Length)
20158a13831STrevor Thompson         {
20258a13831STrevor Thompson             RealLength += SectorSize;
20358a13831STrevor Thompson         }
20458a13831STrevor Thompson 
20558a13831STrevor Thompson         // Did we underestimate the memory required somehow?
20658a13831STrevor Thompson         if (RealLength + RealWriteOffset < StartingOffset + Length)
20758a13831STrevor Thompson         {
20858a13831STrevor Thompson             DPRINT1("\a\t\t\t\t\tFIXME: calculated less memory than needed!\n");
20958a13831STrevor Thompson             DPRINT1("StartingOffset: %lu\tLength: %lu\tRealWriteOffset: %lu\tRealLength: %lu\n",
21058a13831STrevor Thompson                     StartingOffset, Length, RealWriteOffset, RealLength);
21158a13831STrevor Thompson 
21258a13831STrevor Thompson             RealLength += SectorSize;
21358a13831STrevor Thompson         }
21458a13831STrevor Thompson 
21558a13831STrevor Thompson         // Allocate a buffer to copy the existing data to
21658a13831STrevor Thompson         TempBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength, TAG_NTFS);
21758a13831STrevor Thompson 
21858a13831STrevor Thompson         // Did we fail to allocate it?
21958a13831STrevor Thompson         if (TempBuffer == NULL)
22058a13831STrevor Thompson         {
22158a13831STrevor Thompson             DPRINT1("Not enough memory!\n");
22258a13831STrevor Thompson 
22358a13831STrevor Thompson             return STATUS_INSUFFICIENT_RESOURCES;
22458a13831STrevor Thompson         }
22558a13831STrevor Thompson 
22658a13831STrevor Thompson         // Read the sectors we'll be overwriting into TempBuffer
22758a13831STrevor Thompson         Status = NtfsReadDisk(DeviceObject, RealWriteOffset, RealLength, SectorSize, TempBuffer, FALSE);
22858a13831STrevor Thompson 
22958a13831STrevor Thompson         // Did we fail the read?
23058a13831STrevor Thompson         if (!NT_SUCCESS(Status))
23158a13831STrevor Thompson         {
23258a13831STrevor Thompson             RtlSecureZeroMemory(TempBuffer, RealLength);
23358a13831STrevor Thompson             ExFreePoolWithTag(TempBuffer, TAG_NTFS);
23458a13831STrevor Thompson             return Status;
23558a13831STrevor Thompson         }
23658a13831STrevor Thompson 
23758a13831STrevor Thompson         // Calculate where the new data should be written to, relative to the start of TempBuffer
23858a13831STrevor Thompson         relativeOffset = StartingOffset - RealWriteOffset;
23958a13831STrevor Thompson 
24058a13831STrevor Thompson         // Modify the tempbuffer with the data being read
24158a13831STrevor Thompson         RtlCopyMemory(TempBuffer + relativeOffset, Buffer, Length);
24258a13831STrevor Thompson 
24358a13831STrevor Thompson         AllocatedBuffer = TRUE;
24458a13831STrevor Thompson     }
24558a13831STrevor Thompson 
24658a13831STrevor Thompson     // set the destination offset
24758a13831STrevor Thompson     Offset.QuadPart = RealWriteOffset;
24858a13831STrevor Thompson 
24958a13831STrevor Thompson     // setup the notification event for the write
25058a13831STrevor Thompson     KeInitializeEvent(&Event,
25158a13831STrevor Thompson                       NotificationEvent,
25258a13831STrevor Thompson                       FALSE);
25358a13831STrevor Thompson 
25458a13831STrevor Thompson     DPRINT("Building synchronous FSD Request...\n");
25558a13831STrevor Thompson 
25658a13831STrevor Thompson     // Build an IRP requesting the lower-level [disk] driver to perform the write
25758a13831STrevor Thompson     // TODO: Forward the existing IRP instead
25858a13831STrevor Thompson     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
25958a13831STrevor Thompson                                        DeviceObject,
26058a13831STrevor Thompson                                        // if we allocated a temp buffer, use that instead of the Buffer parameter
26158a13831STrevor Thompson                                        ((AllocatedBuffer) ? TempBuffer : Buffer),
26258a13831STrevor Thompson                                        RealLength,
26358a13831STrevor Thompson                                        &Offset,
26458a13831STrevor Thompson                                        &Event,
26558a13831STrevor Thompson                                        &IoStatus);
26658a13831STrevor Thompson     // Did we fail to build the IRP?
26758a13831STrevor Thompson     if (Irp == NULL)
26858a13831STrevor Thompson     {
26958a13831STrevor Thompson         DPRINT1("IoBuildSynchronousFsdRequest failed\n");
27058a13831STrevor Thompson 
27158a13831STrevor Thompson         if (AllocatedBuffer)
27258a13831STrevor Thompson         {
27358a13831STrevor Thompson             RtlSecureZeroMemory(TempBuffer, RealLength);
27458a13831STrevor Thompson             ExFreePoolWithTag(TempBuffer, TAG_NTFS);
27558a13831STrevor Thompson         }
27658a13831STrevor Thompson 
27758a13831STrevor Thompson         return STATUS_INSUFFICIENT_RESOURCES;
27858a13831STrevor Thompson     }
27958a13831STrevor Thompson 
28058a13831STrevor Thompson     // Call the next-lower driver to perform the write
28158a13831STrevor Thompson     DPRINT("Calling IO Driver with irp %p\n", Irp);
28258a13831STrevor Thompson     Status = IoCallDriver(DeviceObject, Irp);
28358a13831STrevor Thompson 
28458a13831STrevor Thompson     // Wait until the next-lower driver has completed the IRP
28558a13831STrevor Thompson     DPRINT("Waiting for IO Operation for %p\n", Irp);
28658a13831STrevor Thompson     if (Status == STATUS_PENDING)
28758a13831STrevor Thompson     {
28858a13831STrevor Thompson         DPRINT("Operation pending\n");
28958a13831STrevor Thompson         KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
29058a13831STrevor Thompson         DPRINT("Getting IO Status... for %p\n", Irp);
29158a13831STrevor Thompson         Status = IoStatus.Status;
29258a13831STrevor Thompson     }
29358a13831STrevor Thompson 
29458a13831STrevor Thompson     if (AllocatedBuffer)
29558a13831STrevor Thompson     {
29658a13831STrevor Thompson         // zero the buffer before freeing it, so private user data can't be snooped
29758a13831STrevor Thompson         RtlSecureZeroMemory(TempBuffer, RealLength);
29858a13831STrevor Thompson 
29958a13831STrevor Thompson         ExFreePoolWithTag(TempBuffer, TAG_NTFS);
30058a13831STrevor Thompson     }
30158a13831STrevor Thompson 
30258a13831STrevor Thompson     DPRINT("NtfsWriteDisk() done (Status %x)\n", Status);
30358a13831STrevor Thompson 
30458a13831STrevor Thompson     return Status;
30558a13831STrevor Thompson }
30658a13831STrevor Thompson 
307c2c66affSColin Finck NTSTATUS
NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject,IN ULONG DiskSector,IN ULONG SectorCount,IN ULONG SectorSize,IN OUT PUCHAR Buffer,IN BOOLEAN Override)308c2c66affSColin Finck NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject,
309c2c66affSColin Finck                 IN ULONG DiskSector,
310c2c66affSColin Finck                 IN ULONG SectorCount,
311c2c66affSColin Finck                 IN ULONG SectorSize,
312c2c66affSColin Finck                 IN OUT PUCHAR Buffer,
313c2c66affSColin Finck                 IN BOOLEAN Override)
314c2c66affSColin Finck {
315c2c66affSColin Finck     LONGLONG Offset;
316c2c66affSColin Finck     ULONG BlockSize;
317c2c66affSColin Finck 
318c2c66affSColin Finck     Offset = (LONGLONG)DiskSector * (LONGLONG)SectorSize;
319c2c66affSColin Finck     BlockSize = SectorCount * SectorSize;
320c2c66affSColin Finck 
321c2c66affSColin Finck     return NtfsReadDisk(DeviceObject, Offset, BlockSize, SectorSize, Buffer, Override);
322c2c66affSColin Finck }
323c2c66affSColin Finck 
324c2c66affSColin Finck 
325c2c66affSColin Finck NTSTATUS
NtfsDeviceIoControl(IN PDEVICE_OBJECT DeviceObject,IN ULONG ControlCode,IN PVOID InputBuffer,IN ULONG InputBufferSize,IN OUT PVOID OutputBuffer,IN OUT PULONG OutputBufferSize,IN BOOLEAN Override)326c2c66affSColin Finck NtfsDeviceIoControl(IN PDEVICE_OBJECT DeviceObject,
327c2c66affSColin Finck                     IN ULONG ControlCode,
328c2c66affSColin Finck                     IN PVOID InputBuffer,
329c2c66affSColin Finck                     IN ULONG InputBufferSize,
330c2c66affSColin Finck                     IN OUT PVOID OutputBuffer,
331c2c66affSColin Finck                     IN OUT PULONG OutputBufferSize,
332c2c66affSColin Finck                     IN BOOLEAN Override)
333c2c66affSColin Finck {
334c2c66affSColin Finck     PIO_STACK_LOCATION Stack;
335c2c66affSColin Finck     IO_STATUS_BLOCK IoStatus;
336c2c66affSColin Finck     KEVENT Event;
337c2c66affSColin Finck     PIRP Irp;
338c2c66affSColin Finck     NTSTATUS Status;
339c2c66affSColin Finck 
340c2c66affSColin Finck     KeInitializeEvent(&Event, NotificationEvent, FALSE);
341c2c66affSColin Finck 
342c2c66affSColin Finck     DPRINT("Building device I/O control request ...\n");
343c2c66affSColin Finck     Irp = IoBuildDeviceIoControlRequest(ControlCode,
344c2c66affSColin Finck                                         DeviceObject,
345c2c66affSColin Finck                                         InputBuffer,
346c2c66affSColin Finck                                         InputBufferSize,
347c2c66affSColin Finck                                         OutputBuffer,
348c2c66affSColin Finck                                         (OutputBufferSize) ? *OutputBufferSize : 0,
349c2c66affSColin Finck                                         FALSE,
350c2c66affSColin Finck                                         &Event,
351c2c66affSColin Finck                                         &IoStatus);
352c2c66affSColin Finck     if (Irp == NULL)
353c2c66affSColin Finck     {
354c2c66affSColin Finck         DPRINT("IoBuildDeviceIoControlRequest() failed\n");
355c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
356c2c66affSColin Finck     }
357c2c66affSColin Finck 
358c2c66affSColin Finck     if (Override)
359c2c66affSColin Finck     {
360c2c66affSColin Finck         Stack = IoGetNextIrpStackLocation(Irp);
361c2c66affSColin Finck         Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
362c2c66affSColin Finck     }
363c2c66affSColin Finck 
364c2c66affSColin Finck     DPRINT("Calling IO Driver... with irp %p\n", Irp);
365c2c66affSColin Finck     Status = IoCallDriver(DeviceObject, Irp);
366c2c66affSColin Finck     if (Status == STATUS_PENDING)
367c2c66affSColin Finck     {
368c2c66affSColin Finck         KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
369c2c66affSColin Finck         Status = IoStatus.Status;
370c2c66affSColin Finck     }
371c2c66affSColin Finck 
372c2c66affSColin Finck     if (OutputBufferSize)
373c2c66affSColin Finck     {
374c2c66affSColin Finck         *OutputBufferSize = IoStatus.Information;
375c2c66affSColin Finck     }
376c2c66affSColin Finck 
377c2c66affSColin Finck     return Status;
378c2c66affSColin Finck }
379c2c66affSColin Finck 
380c2c66affSColin Finck /* EOF */
381