Sync to trunk revision 63922.
[reactos.git] / drivers / filesystems / fs_rec / blockdev.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS File System Recognizer
4 * FILE: drivers/filesystems/fs_rec/blockdev.c
5 * PURPOSE: Generic Helper Functions
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "fs_rec.h"
13
14 #include <ntdddisk.h>
15 #include <ntddcdrm.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /* FUNCTIONS ****************************************************************/
21
22 BOOLEAN
23 NTAPI
24 FsRecGetDeviceSectors(IN PDEVICE_OBJECT DeviceObject,
25 IN ULONG SectorSize,
26 OUT PLARGE_INTEGER SectorCount)
27 {
28 PARTITION_INFORMATION PartitionInfo;
29 IO_STATUS_BLOCK IoStatusBlock;
30 KEVENT Event;
31 PIRP Irp;
32 NTSTATUS Status;
33 ULONG Remainder;
34 PAGED_CODE();
35
36 /* Only needed for disks */
37 if (DeviceObject->DeviceType != FILE_DEVICE_DISK) return FALSE;
38
39 /* Build the information IRP */
40 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
41 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
42 DeviceObject,
43 NULL,
44 0,
45 &PartitionInfo,
46 sizeof(PARTITION_INFORMATION),
47 FALSE,
48 &Event,
49 &IoStatusBlock);
50 if (!Irp) return FALSE;
51
52 /* Override verification */
53 IoGetNextIrpStackLocation(Irp)->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
54
55 /* Do the request */
56 Status = IoCallDriver(DeviceObject, Irp);
57 if (Status == STATUS_PENDING)
58 {
59 /* Wait for completion */
60 KeWaitForSingleObject(&Event,
61 Executive,
62 KernelMode,
63 FALSE,
64 NULL);
65 Status = IoStatusBlock.Status;
66 }
67
68 /* Fail if we couldn't get the data */
69 if (!NT_SUCCESS(Status)) return FALSE;
70
71 /* Otherwise, return the number of sectors */
72 *SectorCount = RtlExtendedLargeIntegerDivide(PartitionInfo.PartitionLength,
73 SectorSize,
74 &Remainder);
75 return TRUE;
76 }
77
78 BOOLEAN
79 NTAPI
80 FsRecGetDeviceSectorSize(IN PDEVICE_OBJECT DeviceObject,
81 OUT PULONG SectorSize)
82 {
83 DISK_GEOMETRY DiskGeometry;
84 IO_STATUS_BLOCK IoStatusBlock;
85 KEVENT Event;
86 PIRP Irp;
87 NTSTATUS Status;
88 ULONG ControlCode;
89 PAGED_CODE();
90
91 /* Check what device we have */
92 switch (DeviceObject->DeviceType)
93 {
94 case FILE_DEVICE_CD_ROM:
95
96 /* Use the CD IOCTL */
97 ControlCode = IOCTL_CDROM_GET_DRIVE_GEOMETRY;
98 break;
99
100 case FILE_DEVICE_DISK:
101
102 /* Use the Disk IOCTL */
103 ControlCode = IOCTL_DISK_GET_DRIVE_GEOMETRY;
104 break;
105
106 default:
107
108 /* Invalid device type */
109 return FALSE;
110 }
111
112 /* Build the information IRP */
113 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
114 Irp = IoBuildDeviceIoControlRequest(ControlCode,
115 DeviceObject,
116 NULL,
117 0,
118 &DiskGeometry,
119 sizeof(DISK_GEOMETRY),
120 FALSE,
121 &Event,
122 &IoStatusBlock);
123 if (!Irp) return FALSE;
124
125 /* Override verification */
126 IoGetNextIrpStackLocation(Irp)->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
127
128 /* Do the request */
129 Status = IoCallDriver(DeviceObject, Irp);
130 if (Status == STATUS_PENDING)
131 {
132 /* Wait for completion */
133 KeWaitForSingleObject(&Event,
134 Executive,
135 KernelMode,
136 FALSE,
137 NULL);
138 Status = IoStatusBlock.Status;
139 }
140
141 /* Fail if we couldn't get the data */
142 if (!NT_SUCCESS(Status)) return FALSE;
143
144 /* Return the sector size if it's valid */
145 if (!DiskGeometry.BytesPerSector) return FALSE;
146 *SectorSize = DiskGeometry.BytesPerSector;
147 return TRUE;
148 }
149
150 BOOLEAN
151 NTAPI
152 FsRecReadBlock(IN PDEVICE_OBJECT DeviceObject,
153 IN PLARGE_INTEGER Offset,
154 IN ULONG Length,
155 IN ULONG SectorSize,
156 IN OUT PVOID *Buffer,
157 OUT PBOOLEAN DeviceError OPTIONAL)
158 {
159 IO_STATUS_BLOCK IoStatusBlock;
160 KEVENT Event;
161 PIRP Irp;
162 NTSTATUS Status;
163 PAGED_CODE();
164
165 /* Assume failure */
166 if (DeviceError) *DeviceError = FALSE;
167
168 /* Check if the caller requested too little */
169 if (Length < SectorSize)
170 {
171 /* Read at least the sector size */
172 Length = SectorSize;
173 }
174 else
175 {
176 /* Otherwise, just round up the request to sector size */
177 Length = ROUND_UP(Length, SectorSize);
178 }
179
180 /* Check if the caller gave us a buffer */
181 if (!*Buffer)
182 {
183 /* He didn't, allocate one */
184 *Buffer = ExAllocatePoolWithTag(NonPagedPool,
185 ROUND_TO_PAGES(Length),
186 FSREC_TAG);
187 if (!*Buffer) return FALSE;
188 }
189
190 /* Build the IRP */
191 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
192 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
193 DeviceObject,
194 *Buffer,
195 Length,
196 Offset,
197 &Event,
198 &IoStatusBlock);
199 if (!Irp) return FALSE;
200
201 /* Override verification */
202 IoGetNextIrpStackLocation(Irp)->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
203
204 /* Do the request */
205 Status = IoCallDriver(DeviceObject, Irp);
206 if (Status == STATUS_PENDING)
207 {
208 /* Wait for completion */
209 KeWaitForSingleObject(&Event,
210 Executive,
211 KernelMode,
212 FALSE,
213 NULL);
214 Status = IoStatusBlock.Status;
215 }
216
217 /* Check if we couldn't get the data */
218 if (!NT_SUCCESS(Status))
219 {
220 /* Check if caller wanted to know about the device and fail */
221 if (DeviceError) *DeviceError = TRUE;
222 return FALSE;
223 }
224
225 /* All went well */
226 return TRUE;
227 }