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