migrate substitution keywords to SVN
[reactos.git] / reactos / drivers / fs / fs_rec / udfs.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2003 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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: drivers/fs/fs_rec/udfs.c
24 * PURPOSE: Filesystem recognizer driver
25 * PROGRAMMER: Eric Kohl
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <rosrtl/string.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 #include "fs_rec.h"
37
38
39 #define UDFS_VRS_START_SECTOR 16
40 #define UDFS_AVDP_SECTOR 256
41
42 /* TYPES ********************************************************************/
43
44 #include <pshpack1.h>
45
46 typedef struct _TAG
47 {
48 USHORT Identifier;
49 USHORT Version;
50 UCHAR Checksum;
51 UCHAR Reserved;
52 USHORT SerialNumber;
53 USHORT Crc;
54 USHORT CrcLength;
55 ULONG Location;
56 } TAG, *PTAG;
57
58 typedef struct _EXTENT
59 {
60 ULONG Length;
61 ULONG Location;
62 } EXTENT, *PEXTENT;
63
64 typedef struct _AVDP
65 {
66 TAG DescriptorTag;
67 EXTENT MainVolumeDescriptorExtent;
68 EXTENT ReserveVolumeDescriptorExtent;
69 } AVDP, *PAVDP;
70
71 #include <poppack.h>
72
73
74 /* FUNCTIONS ****************************************************************/
75
76 static NTSTATUS
77 FsRecCheckVolumeRecognitionSequence(IN PDEVICE_OBJECT DeviceObject,
78 IN ULONG SectorSize)
79 {
80 PUCHAR Buffer;
81 ULONG Sector;
82 NTSTATUS Status;
83 ULONG State;
84
85 Buffer = ExAllocatePool(NonPagedPool,
86 SectorSize);
87 if (Buffer == NULL)
88 {
89 return(STATUS_INSUFFICIENT_RESOURCES);
90 }
91
92 State = 0;
93 Sector = UDFS_VRS_START_SECTOR;
94 while (TRUE)
95 {
96 Status = FsRecReadSectors(DeviceObject,
97 Sector,
98 1,
99 SectorSize,
100 Buffer);
101 if (!NT_SUCCESS(Status))
102 {
103 DPRINT ("FsRecReadSectors() failed (Status %lx)\n", Status);
104 break;
105 }
106
107 DPRINT ("Descriptor identifier: [%.5s]\n", Buffer + 1);
108
109 switch (State)
110 {
111 case 0:
112 if ((Sector == UDFS_VRS_START_SECTOR) &&
113 (Buffer[1] == 'B') &&
114 (Buffer[2] == 'E') &&
115 (Buffer[3] == 'A') &&
116 (Buffer[4] == '0') &&
117 (Buffer[5] == '1'))
118 {
119 State = 1;
120 }
121 else
122 {
123 DPRINT ("VRS start sector is not 'BEA01'\n");
124 ExFreePool(Buffer);
125 return(STATUS_UNRECOGNIZED_VOLUME);
126 }
127 break;
128
129 case 1:
130 if ((Buffer[1] == 'N') &&
131 (Buffer[2] == 'S') &&
132 (Buffer[3] == 'R') &&
133 (Buffer[4] == '0') &&
134 ((Buffer[5] == '2') || (Buffer[5] == '3')))
135 {
136 State = 2;
137 }
138 break;
139
140 case 2:
141 if ((Buffer[1] == 'T') &&
142 (Buffer[2] == 'E') &&
143 (Buffer[3] == 'A') &&
144 (Buffer[4] == '0') &&
145 (Buffer[5] == '1'))
146 {
147 DPRINT ("Found 'TEA01'\n");
148 ExFreePool(Buffer);
149 return(STATUS_SUCCESS);
150 }
151 break;
152 }
153
154 Sector++;
155 if (Sector == UDFS_AVDP_SECTOR)
156 {
157 DPRINT ("No 'TEA01' found\n");
158 ExFreePool(Buffer);
159 return(STATUS_UNRECOGNIZED_VOLUME);
160 }
161 }
162
163 ExFreePool(Buffer);
164
165 return(STATUS_UNRECOGNIZED_VOLUME);
166 }
167
168
169 static NTSTATUS
170 FsRecCheckAnchorVolumeDescriptorPointer(IN PDEVICE_OBJECT DeviceObject,
171 IN ULONG SectorSize)
172 {
173 PUCHAR Buffer;
174 ULONG Sector;
175 NTSTATUS Status;
176 PAVDP Avdp;
177
178 Buffer = ExAllocatePool(NonPagedPool,
179 SectorSize);
180 if (Buffer == NULL)
181 {
182 return(STATUS_INSUFFICIENT_RESOURCES);
183 }
184
185 Sector = UDFS_AVDP_SECTOR;
186 Status = FsRecReadSectors(DeviceObject,
187 Sector,
188 1,
189 SectorSize,
190 Buffer);
191 if (!NT_SUCCESS(Status))
192 {
193 DPRINT ("FsRecReadSectors() failed (Status %lx)\n", Status);
194 ExFreePool(Buffer);
195 return(Status);
196 }
197
198 Avdp = (PAVDP)Buffer;
199 DPRINT ("Descriptor identifier: %hu\n", Avdp->DescriptorTag.Identifier);
200
201 DPRINT ("Main volume descriptor sequence location: %lu\n",
202 Avdp->MainVolumeDescriptorExtent.Location);
203
204 DPRINT ("Main volume descriptor sequence length: %lu\n",
205 Avdp->MainVolumeDescriptorExtent.Length);
206
207 DPRINT ("Reserve volume descriptor sequence location: %lu\n",
208 Avdp->ReserveVolumeDescriptorExtent.Location);
209
210 DPRINT ("Reserve volume descriptor sequence length: %lu\n",
211 Avdp->ReserveVolumeDescriptorExtent.Length);
212
213 ExFreePool(Buffer);
214
215 // return(Status);
216 return(STATUS_SUCCESS);
217 }
218
219
220 static NTSTATUS
221 FsRecIsUdfsVolume(IN PDEVICE_OBJECT DeviceObject)
222 {
223 DISK_GEOMETRY DiskGeometry;
224 ULONG Size;
225 NTSTATUS Status;
226
227 Size = sizeof(DISK_GEOMETRY);
228 Status = FsRecDeviceIoControl(DeviceObject,
229 IOCTL_CDROM_GET_DRIVE_GEOMETRY,
230 NULL,
231 0,
232 &DiskGeometry,
233 &Size);
234 if (!NT_SUCCESS(Status))
235 {
236 DPRINT ("FsRecDeviceIoControl() failed (Status %lx)\n", Status);
237 return(Status);
238 }
239 DPRINT ("BytesPerSector: %lu\n", DiskGeometry.BytesPerSector);
240
241 /* Check the volume recognition sequence */
242 Status = FsRecCheckVolumeRecognitionSequence(DeviceObject,
243 DiskGeometry.BytesPerSector);
244 if (!NT_SUCCESS(Status))
245 return(Status);
246
247 Status = FsRecCheckAnchorVolumeDescriptorPointer(DeviceObject,
248 DiskGeometry.BytesPerSector);
249 if (!NT_SUCCESS(Status))
250 return(Status);
251
252 return(STATUS_SUCCESS);
253 }
254
255
256 NTSTATUS
257 FsRecUdfsFsControl(IN PDEVICE_OBJECT DeviceObject,
258 IN PIRP Irp)
259 {
260 PIO_STACK_LOCATION Stack;
261 UNICODE_STRING RegistryPath;
262 NTSTATUS Status;
263
264 Stack = IoGetCurrentIrpStackLocation(Irp);
265
266 switch (Stack->MinorFunction)
267 {
268 case IRP_MN_MOUNT_VOLUME:
269 DPRINT("Udfs: IRP_MN_MOUNT_VOLUME\n");
270 Status = FsRecIsUdfsVolume(Stack->Parameters.MountVolume.DeviceObject);
271 if (NT_SUCCESS(Status))
272 {
273 DPRINT("Identified UDFS volume\n");
274 Status = STATUS_FS_DRIVER_REQUIRED;
275 }
276 break;
277
278 case IRP_MN_LOAD_FILE_SYSTEM:
279 DPRINT("Udfs: IRP_MN_LOAD_FILE_SYSTEM\n");
280 RtlRosInitUnicodeStringFromLiteral(&RegistryPath,
281 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Udfs");
282 Status = ZwLoadDriver(&RegistryPath);
283 if (!NT_SUCCESS(Status))
284 {
285 DPRINT("ZwLoadDriver failed (Status %x)\n", Status);
286 }
287 else
288 {
289 IoUnregisterFileSystem(DeviceObject);
290 }
291 break;
292
293 default:
294 DPRINT("Udfs: Unknown minor function %lx\n", Stack->MinorFunction);
295 Status = STATUS_INVALID_DEVICE_REQUEST;
296 break;
297 }
298 return(Status);
299 }
300
301 /* EOF */