[BTRFS] Fix booting with runtime checks
[reactos.git] / drivers / filesystems / ntfs / blockdev.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 *
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
24 * Trevor Thompson
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "ntfs.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* FUNCTIONS ****************************************************************/
35
36 NTSTATUS
37 NtfsReadDisk(IN PDEVICE_OBJECT DeviceObject,
38 IN LONGLONG StartingOffset,
39 IN ULONG Length,
40 IN ULONG SectorSize,
41 IN OUT PUCHAR Buffer,
42 IN BOOLEAN Override)
43 {
44 PIO_STACK_LOCATION Stack;
45 IO_STATUS_BLOCK IoStatus;
46 LARGE_INTEGER Offset;
47 KEVENT Event;
48 PIRP Irp;
49 NTSTATUS Status;
50 ULONGLONG RealReadOffset;
51 ULONG RealLength;
52 BOOLEAN AllocatedBuffer = FALSE;
53 PUCHAR ReadBuffer = Buffer;
54
55 DPRINT("NtfsReadDisk(%p, %I64x, %lu, %lu, %p, %d)\n", DeviceObject, StartingOffset, Length, SectorSize, Buffer, Override);
56
57 KeInitializeEvent(&Event,
58 NotificationEvent,
59 FALSE);
60
61 RealReadOffset = (ULONGLONG)StartingOffset;
62 RealLength = Length;
63
64 if ((RealReadOffset % SectorSize) != 0 || (RealLength % SectorSize) != 0)
65 {
66 RealReadOffset = ROUND_DOWN(StartingOffset, SectorSize);
67 RealLength = ROUND_UP(Length, SectorSize);
68
69 ReadBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength + SectorSize, TAG_NTFS);
70 if (ReadBuffer == NULL)
71 {
72 DPRINT1("Not enough memory!\n");
73 return STATUS_INSUFFICIENT_RESOURCES;
74 }
75 AllocatedBuffer = TRUE;
76 }
77
78 Offset.QuadPart = RealReadOffset;
79
80 DPRINT("Building synchronous FSD Request...\n");
81 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
82 DeviceObject,
83 ReadBuffer,
84 RealLength,
85 &Offset,
86 &Event,
87 &IoStatus);
88 if (Irp == NULL)
89 {
90 DPRINT("IoBuildSynchronousFsdRequest failed\n");
91
92 if (AllocatedBuffer)
93 {
94 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
95 }
96
97 return STATUS_INSUFFICIENT_RESOURCES;
98 }
99
100 if (Override)
101 {
102 Stack = IoGetNextIrpStackLocation(Irp);
103 Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
104 }
105
106 DPRINT("Calling IO Driver... with irp %p\n", Irp);
107 Status = IoCallDriver(DeviceObject, Irp);
108
109 DPRINT("Waiting for IO Operation for %p\n", Irp);
110 if (Status == STATUS_PENDING)
111 {
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;
116 }
117
118 if (AllocatedBuffer)
119 {
120 if (NT_SUCCESS(Status))
121 {
122 RtlCopyMemory(Buffer, ReadBuffer + (StartingOffset - RealReadOffset), Length);
123 }
124
125 ExFreePoolWithTag(ReadBuffer, TAG_NTFS);
126 }
127
128 DPRINT("NtfsReadDisk() done (Status %x)\n", Status);
129
130 return Status;
131 }
132
133 /**
134 * @name NtfsWriteDisk
135 * @implemented
136 *
137 * Writes data from the given buffer to the given DeviceObject.
138 *
139 * @param DeviceObject
140 * Device to write to
141 *
142 * @param StartingOffset
143 * Offset, in bytes, from the start of the device object where the data will be written
144 *
145 * @param Length
146 * How much data will be written, in bytes
147 *
148 * @param SectorSize
149 * Size of the sector on the disk that the write must be aligned to
150 *
151 * @param Buffer
152 * The data that's being written to the device
153 *
154 * @return
155 * STATUS_SUCCESS in case of success, STATUS_INSUFFICIENT_RESOURCES if a memory allocation failed,
156 * or whatever status IoCallDriver() sets.
157 *
158 * @remarks Called by NtfsWriteFile(). May perform a read-modify-write operation if the
159 * requested write is not sector-aligned.
160 *
161 */
162 NTSTATUS
163 NtfsWriteDisk(IN PDEVICE_OBJECT DeviceObject,
164 IN LONGLONG StartingOffset,
165 IN ULONG Length,
166 IN ULONG SectorSize,
167 IN const PUCHAR Buffer)
168 {
169 IO_STATUS_BLOCK IoStatus;
170 LARGE_INTEGER Offset;
171 KEVENT Event;
172 PIRP Irp;
173 NTSTATUS Status;
174 ULONGLONG RealWriteOffset;
175 ULONG RealLength;
176 BOOLEAN AllocatedBuffer = FALSE;
177 PUCHAR TempBuffer = NULL;
178
179 DPRINT("NtfsWriteDisk(%p, %I64x, %lu, %lu, %p)\n", DeviceObject, StartingOffset, Length, SectorSize, Buffer);
180
181 if (Length == 0)
182 return STATUS_SUCCESS;
183
184 RealWriteOffset = (ULONGLONG)StartingOffset;
185 RealLength = Length;
186
187 // Does the write need to be adjusted to be sector-aligned?
188 if ((RealWriteOffset % SectorSize) != 0 || (RealLength % SectorSize) != 0)
189 {
190 ULONGLONG relativeOffset;
191
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)
195
196 RealWriteOffset = ROUND_DOWN(StartingOffset, SectorSize);
197 RealLength = ROUND_UP(Length, SectorSize);
198
199 // Would the end of our sector-aligned write fall short of the requested write?
200 if (RealWriteOffset + RealLength < StartingOffset + Length)
201 {
202 RealLength += SectorSize;
203 }
204
205 // Did we underestimate the memory required somehow?
206 if (RealLength + RealWriteOffset < StartingOffset + Length)
207 {
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);
211
212 RealLength += SectorSize;
213 }
214
215 // Allocate a buffer to copy the existing data to
216 TempBuffer = ExAllocatePoolWithTag(NonPagedPool, RealLength, TAG_NTFS);
217
218 // Did we fail to allocate it?
219 if (TempBuffer == NULL)
220 {
221 DPRINT1("Not enough memory!\n");
222
223 return STATUS_INSUFFICIENT_RESOURCES;
224 }
225
226 // Read the sectors we'll be overwriting into TempBuffer
227 Status = NtfsReadDisk(DeviceObject, RealWriteOffset, RealLength, SectorSize, TempBuffer, FALSE);
228
229 // Did we fail the read?
230 if (!NT_SUCCESS(Status))
231 {
232 RtlSecureZeroMemory(TempBuffer, RealLength);
233 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
234 return Status;
235 }
236
237 // Calculate where the new data should be written to, relative to the start of TempBuffer
238 relativeOffset = StartingOffset - RealWriteOffset;
239
240 // Modify the tempbuffer with the data being read
241 RtlCopyMemory(TempBuffer + relativeOffset, Buffer, Length);
242
243 AllocatedBuffer = TRUE;
244 }
245
246 // set the destination offset
247 Offset.QuadPart = RealWriteOffset;
248
249 // setup the notification event for the write
250 KeInitializeEvent(&Event,
251 NotificationEvent,
252 FALSE);
253
254 DPRINT("Building synchronous FSD Request...\n");
255
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,
259 DeviceObject,
260 // if we allocated a temp buffer, use that instead of the Buffer parameter
261 ((AllocatedBuffer) ? TempBuffer : Buffer),
262 RealLength,
263 &Offset,
264 &Event,
265 &IoStatus);
266 // Did we fail to build the IRP?
267 if (Irp == NULL)
268 {
269 DPRINT1("IoBuildSynchronousFsdRequest failed\n");
270
271 if (AllocatedBuffer)
272 {
273 RtlSecureZeroMemory(TempBuffer, RealLength);
274 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
275 }
276
277 return STATUS_INSUFFICIENT_RESOURCES;
278 }
279
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);
283
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)
287 {
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;
292 }
293
294 if (AllocatedBuffer)
295 {
296 // zero the buffer before freeing it, so private user data can't be snooped
297 RtlSecureZeroMemory(TempBuffer, RealLength);
298
299 ExFreePoolWithTag(TempBuffer, TAG_NTFS);
300 }
301
302 DPRINT("NtfsWriteDisk() done (Status %x)\n", Status);
303
304 return Status;
305 }
306
307 NTSTATUS
308 NtfsReadSectors(IN PDEVICE_OBJECT DeviceObject,
309 IN ULONG DiskSector,
310 IN ULONG SectorCount,
311 IN ULONG SectorSize,
312 IN OUT PUCHAR Buffer,
313 IN BOOLEAN Override)
314 {
315 LONGLONG Offset;
316 ULONG BlockSize;
317
318 Offset = (LONGLONG)DiskSector * (LONGLONG)SectorSize;
319 BlockSize = SectorCount * SectorSize;
320
321 return NtfsReadDisk(DeviceObject, Offset, BlockSize, SectorSize, Buffer, Override);
322 }
323
324
325 NTSTATUS
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,
332 IN BOOLEAN Override)
333 {
334 PIO_STACK_LOCATION Stack;
335 IO_STATUS_BLOCK IoStatus;
336 KEVENT Event;
337 PIRP Irp;
338 NTSTATUS Status;
339
340 KeInitializeEvent(&Event, NotificationEvent, FALSE);
341
342 DPRINT("Building device I/O control request ...\n");
343 Irp = IoBuildDeviceIoControlRequest(ControlCode,
344 DeviceObject,
345 InputBuffer,
346 InputBufferSize,
347 OutputBuffer,
348 (OutputBufferSize) ? *OutputBufferSize : 0,
349 FALSE,
350 &Event,
351 &IoStatus);
352 if (Irp == NULL)
353 {
354 DPRINT("IoBuildDeviceIoControlRequest() failed\n");
355 return STATUS_INSUFFICIENT_RESOURCES;
356 }
357
358 if (Override)
359 {
360 Stack = IoGetNextIrpStackLocation(Irp);
361 Stack->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
362 }
363
364 DPRINT("Calling IO Driver... with irp %p\n", Irp);
365 Status = IoCallDriver(DeviceObject, Irp);
366 if (Status == STATUS_PENDING)
367 {
368 KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
369 Status = IoStatus.Status;
370 }
371
372 if (OutputBufferSize)
373 {
374 *OutputBufferSize = IoStatus.Information;
375 }
376
377 return Status;
378 }
379
380 /* EOF */