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