3 * Copyright (C) 2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/blockdev.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMERS: Eric Kohl
27 /* INCLUDES *****************************************************************/
34 /* FUNCTIONS ****************************************************************/
37 NtfsReadDisk(IN PDEVICE_OBJECT DeviceObject
,
38 IN LONGLONG StartingOffset
,
44 PIO_STACK_LOCATION Stack
;
45 IO_STATUS_BLOCK IoStatus
;
50 ULONGLONG RealReadOffset
;
52 BOOLEAN AllocatedBuffer
= FALSE
;
53 PUCHAR ReadBuffer
= Buffer
;
55 DPRINT("NtfsReadDisk(%p, %I64x, %lu, %lu, %p, %d)\n", DeviceObject
, StartingOffset
, Length
, SectorSize
, Buffer
, Override
);
57 KeInitializeEvent(&Event
,
61 RealReadOffset
= (ULONGLONG
)StartingOffset
;
64 if ((RealReadOffset
% SectorSize
) != 0 || (RealLength
% SectorSize
) != 0)
66 RealReadOffset
= ROUND_DOWN(StartingOffset
, SectorSize
);
67 RealLength
= ROUND_UP(Length
, SectorSize
);
69 ReadBuffer
= ExAllocatePoolWithTag(NonPagedPool
, RealLength
+ SectorSize
, TAG_NTFS
);
70 if (ReadBuffer
== NULL
)
72 DPRINT1("Not enough memory!\n");
73 return STATUS_INSUFFICIENT_RESOURCES
;
75 AllocatedBuffer
= TRUE
;
78 Offset
.QuadPart
= RealReadOffset
;
80 DPRINT("Building synchronous FSD Request...\n");
81 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_READ
,
90 DPRINT("IoBuildSynchronousFsdRequest failed\n");
94 ExFreePoolWithTag(ReadBuffer
, TAG_NTFS
);
97 return STATUS_INSUFFICIENT_RESOURCES
;
102 Stack
= IoGetNextIrpStackLocation(Irp
);
103 Stack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
106 DPRINT("Calling IO Driver... with irp %p\n", Irp
);
107 Status
= IoCallDriver(DeviceObject
, Irp
);
109 DPRINT("Waiting for IO Operation for %p\n", Irp
);
110 if (Status
== STATUS_PENDING
)
112 DPRINT("Operation pending\n");
113 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
114 DPRINT("Getting IO Status... for %p\n", Irp
);
115 Status
= IoStatus
.Status
;
120 if (NT_SUCCESS(Status
))
122 RtlCopyMemory(Buffer
, ReadBuffer
+ (StartingOffset
- RealReadOffset
), Length
);
125 ExFreePoolWithTag(ReadBuffer
, TAG_NTFS
);
128 DPRINT("NtfsReadDisk() done (Status %x)\n", Status
);
134 * @name NtfsWriteDisk
137 * Writes data from the given buffer to the given DeviceObject.
139 * @param DeviceObject
142 * @param StartingOffset
143 * Offset, in bytes, from the start of the device object where the data will be written
146 * How much data will be written, in bytes
149 * Size of the sector on the disk that the write must be aligned to
152 * The data that's being written to the device
155 * STATUS_SUCCESS in case of success, STATUS_INSUFFICIENT_RESOURCES if a memory allocation failed,
156 * or whatever status IoCallDriver() sets.
158 * @remarks Called by NtfsWriteFile(). May perform a read-modify-write operation if the
159 * requested write is not sector-aligned.
163 NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject
,
164 IN LONGLONG StartingOffset
,
167 IN
const PUCHAR Buffer
)
169 IO_STATUS_BLOCK IoStatus
;
170 LARGE_INTEGER Offset
;
174 ULONGLONG RealWriteOffset
;
176 BOOLEAN AllocatedBuffer
= FALSE
;
177 PUCHAR TempBuffer
= NULL
;
179 DPRINT("NtfsWriteDisk(%p, %I64x, %lu, %lu, %p)\n", DeviceObject
, StartingOffset
, Length
, SectorSize
, Buffer
);
182 return STATUS_SUCCESS
;
184 RealWriteOffset
= (ULONGLONG
)StartingOffset
;
187 // Does the write need to be adjusted to be sector-aligned?
188 if ((RealWriteOffset
% SectorSize
) != 0 || (RealLength
% SectorSize
) != 0)
190 ULONGLONG relativeOffset
;
192 // We need to do a read-modify-write. We'll start be copying the entire
193 // contents of every sector that will be overwritten.
194 // TODO: Optimize (read no more than necessary)
196 RealWriteOffset
= ROUND_DOWN(StartingOffset
, SectorSize
);
197 RealLength
= ROUND_UP(Length
, SectorSize
);
199 // Would the end of our sector-aligned write fall short of the requested write?
200 if (RealWriteOffset
+ RealLength
< StartingOffset
+ Length
)
202 RealLength
+= SectorSize
;
205 // Did we underestimate the memory required somehow?
206 if (RealLength
+ RealWriteOffset
< StartingOffset
+ Length
)
208 DPRINT1("\a\t\t\t\t\tFIXME: calculated less memory than needed!\n");
209 DPRINT1("StartingOffset: %lu\tLength: %lu\tRealWriteOffset: %lu\tRealLength: %lu\n",
210 StartingOffset
, Length
, RealWriteOffset
, RealLength
);
212 RealLength
+= SectorSize
;
215 // Allocate a buffer to copy the existing data to
216 TempBuffer
= ExAllocatePoolWithTag(NonPagedPool
, RealLength
, TAG_NTFS
);
218 // Did we fail to allocate it?
219 if (TempBuffer
== NULL
)
221 DPRINT1("Not enough memory!\n");
223 return STATUS_INSUFFICIENT_RESOURCES
;
226 // Read the sectors we'll be overwriting into TempBuffer
227 Status
= NtfsReadDisk(DeviceObject
, RealWriteOffset
, RealLength
, SectorSize
, TempBuffer
, FALSE
);
229 // Did we fail the read?
230 if (!NT_SUCCESS(Status
))
232 RtlSecureZeroMemory(TempBuffer
, RealLength
);
233 ExFreePoolWithTag(TempBuffer
, TAG_NTFS
);
237 // Calculate where the new data should be written to, relative to the start of TempBuffer
238 relativeOffset
= StartingOffset
- RealWriteOffset
;
240 // Modify the tempbuffer with the data being read
241 RtlCopyMemory(TempBuffer
+ relativeOffset
, Buffer
, Length
);
243 AllocatedBuffer
= TRUE
;
246 // set the destination offset
247 Offset
.QuadPart
= RealWriteOffset
;
249 // setup the notification event for the write
250 KeInitializeEvent(&Event
,
254 DPRINT("Building synchronous FSD Request...\n");
256 // Build an IRP requesting the lower-level [disk] driver to perform the write
257 // TODO: Forward the existing IRP instead
258 Irp
= IoBuildSynchronousFsdRequest(IRP_MJ_WRITE
,
260 // if we allocated a temp buffer, use that instead of the Buffer parameter
261 ((AllocatedBuffer
) ? TempBuffer
: Buffer
),
266 // Did we fail to build the IRP?
269 DPRINT1("IoBuildSynchronousFsdRequest failed\n");
273 RtlSecureZeroMemory(TempBuffer
, RealLength
);
274 ExFreePoolWithTag(TempBuffer
, TAG_NTFS
);
277 return STATUS_INSUFFICIENT_RESOURCES
;
280 // Call the next-lower driver to perform the write
281 DPRINT("Calling IO Driver with irp %p\n", Irp
);
282 Status
= IoCallDriver(DeviceObject
, Irp
);
284 // Wait until the next-lower driver has completed the IRP
285 DPRINT("Waiting for IO Operation for %p\n", Irp
);
286 if (Status
== STATUS_PENDING
)
288 DPRINT("Operation pending\n");
289 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
290 DPRINT("Getting IO Status... for %p\n", Irp
);
291 Status
= IoStatus
.Status
;
296 // zero the buffer before freeing it, so private user data can't be snooped
297 RtlSecureZeroMemory(TempBuffer
, RealLength
);
299 ExFreePoolWithTag(TempBuffer
, TAG_NTFS
);
302 DPRINT("NtfsWriteDisk() done (Status %x)\n", Status
);
308 NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject
,
310 IN ULONG SectorCount
,
312 IN OUT PUCHAR Buffer
,
318 Offset
= (LONGLONG
)DiskSector
* (LONGLONG
)SectorSize
;
319 BlockSize
= SectorCount
* SectorSize
;
321 return NtfsReadDisk(DeviceObject
, Offset
, BlockSize
, SectorSize
, Buffer
, Override
);
326 NtfsDeviceIoControl(IN PDEVICE_OBJECT DeviceObject
,
327 IN ULONG ControlCode
,
328 IN PVOID InputBuffer
,
329 IN ULONG InputBufferSize
,
330 IN OUT PVOID OutputBuffer
,
331 IN OUT PULONG OutputBufferSize
,
334 PIO_STACK_LOCATION Stack
;
335 IO_STATUS_BLOCK IoStatus
;
340 KeInitializeEvent(&Event
, NotificationEvent
, FALSE
);
342 DPRINT("Building device I/O control request ...\n");
343 Irp
= IoBuildDeviceIoControlRequest(ControlCode
,
348 (OutputBufferSize
) ? *OutputBufferSize
: 0,
354 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
355 return STATUS_INSUFFICIENT_RESOURCES
;
360 Stack
= IoGetNextIrpStackLocation(Irp
);
361 Stack
->Flags
|= SL_OVERRIDE_VERIFY_VOLUME
;
364 DPRINT("Calling IO Driver... with irp %p\n", Irp
);
365 Status
= IoCallDriver(DeviceObject
, Irp
);
366 if (Status
== STATUS_PENDING
)
368 KeWaitForSingleObject(&Event
, Suspended
, KernelMode
, FALSE
, NULL
);
369 Status
= IoStatus
.Status
;
372 if (OutputBufferSize
)
374 *OutputBufferSize
= IoStatus
.Information
;