Initial original import from: fuse-2.4.2-2.fc4
[captive.git] / src / libcaptive / storage / media.c
1 /* $Id$
2  * captive media (cdrom/disk) emulation for reactos
3  * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
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; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "media.h"      /* self */
23 #include "captive/storage.h"    /* self */
24 #include <glib/gmessages.h>
25 #include "reactos/ddk/class2.h" /* for DEVICE_EXTENSION */
26 #include "reactos/ddk/status.h"
27 #include "reactos/ddk/iofuncs.h"        /* for IoIsErrorUserInduced() */
28 #include "captive/macros.h"
29 #include "reactos/ddk/mmfuncs.h"        /* for MmGetMdlByteCount() */
30 #include "captive/unicode.h"
31 #include <glib/gmacros.h>
32 #include "reactos/structs.h"    /* for PREVENT_MEDIA_REMOVAL */
33 #include "captive/options.h"
34
35
36 GIOChannel *captive_image_iochannel;
37 guint64 captive_image_size;
38
39
40 static gboolean validate_DeviceObject(DEVICE_OBJECT *DeviceObject)
41 {
42 DEVICE_EXTENSION *DeviceExtension;
43 DISK_GEOMETRY *DiskGeometry;
44 IO_SCSI_CAPABILITIES *PortCapabilities;
45 struct captive_DriverObject *captive_DriverObject;
46
47         g_return_val_if_fail(DeviceObject!=NULL,FALSE);
48
49         captive_DriverObject=(struct captive_DriverObject *)DeviceObject->DriverObject;
50         DeviceExtension=DeviceObject->DeviceExtension;
51
52         DiskGeometry=DeviceExtension->DiskGeometry;
53         g_return_val_if_fail(DiskGeometry==&captive_DriverObject->DiskGeometry,FALSE);
54         g_return_val_if_fail(DiskGeometry->MediaType==captive_DriverObject->DiskGeometry_check.MediaType,FALSE);
55         g_return_val_if_fail(DiskGeometry->TracksPerCylinder==captive_DriverObject->DiskGeometry_check.TracksPerCylinder,FALSE);
56         g_return_val_if_fail(DiskGeometry->SectorsPerTrack==captive_DriverObject->DiskGeometry_check.SectorsPerTrack,FALSE);
57         g_return_val_if_fail(DiskGeometry->BytesPerSector==captive_DriverObject->DiskGeometry_check.BytesPerSector,FALSE);
58         g_return_val_if_fail(DiskGeometry->Cylinders.QuadPart==captive_DriverObject->DiskGeometry_check.Cylinders.QuadPart,FALSE);
59         g_return_val_if_fail(DeviceExtension->PartitionLength.QuadPart==(gint64)captive_image_size,FALSE);
60
61         PortCapabilities=DeviceExtension->PortCapabilities;
62         g_return_val_if_fail(PortCapabilities==&captive_DriverObject->PortCapabilities,FALSE);
63         g_return_val_if_fail(PortCapabilities->Length==captive_DriverObject->PortCapabilities_check.Length,FALSE);
64         g_return_val_if_fail(PortCapabilities->MaximumTransferLength==captive_DriverObject->PortCapabilities_check.MaximumTransferLength,FALSE);
65         g_return_val_if_fail(PortCapabilities->MaximumPhysicalPages==captive_DriverObject->PortCapabilities_check.MaximumPhysicalPages,FALSE);
66         g_return_val_if_fail(PortCapabilities->SupportedAsynchronousEvents==captive_DriverObject->PortCapabilities_check.SupportedAsynchronousEvents,FALSE);
67         g_return_val_if_fail(PortCapabilities->AlignmentMask==captive_DriverObject->PortCapabilities_check.AlignmentMask,FALSE);
68         g_return_val_if_fail(PortCapabilities->TaggedQueuing==captive_DriverObject->PortCapabilities_check.TaggedQueuing,FALSE);
69         g_return_val_if_fail(PortCapabilities->AdapterScansDown==captive_DriverObject->PortCapabilities_check.AdapterScansDown,FALSE);
70         g_return_val_if_fail(PortCapabilities->AdapterUsesPio==captive_DriverObject->PortCapabilities_check.AdapterUsesPio,FALSE);
71
72         return TRUE;
73 }
74
75
76 static NTSTATUS MajorFunction_Irp_finish(DEVICE_OBJECT *DeviceObject,IRP *Irp)
77 {
78 NTSTATUS r;
79
80         g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
81         g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
82
83         /* required for removable media only */
84         if (!NT_SUCCESS(Irp->IoStatus.Status) && IoIsErrorUserInduced(Irp->IoStatus.Status)) {
85                 g_assert(Irp->Tail.Overlay.Thread!=NULL);       /* FIXME: Error should be postponed to first !=NULL Irp later */
86                 IoSetHardErrorOrVerifyDevice(Irp,DeviceObject);
87                 Irp->IoStatus.Information=0;    /* may got set during some processing before error occured */
88                 }
89
90         /* IoCompleteRequest() will do 'IoFreeIrp(Irp);'!
91          * 'IoStatus.Status' must be saved before its invocation!
92          */
93         r=Irp->IoStatus.Status;
94         IoCompleteRequest(Irp,IO_NO_INCREMENT);
95         return r;
96 }
97
98
99 /* FIXME: We should comply with PDRIVER_DISPATCH prototype but unfortunately
100  * CAPTIVE_STDCALL prevents us to do so at least in RedHat gcc-3.2-4 (gcc bug?).
101  */
102 #define MajorFunction_DEVICE_CONTROL ((PDRIVER_DISPATCH)MajorFunction_DEVICE_CONTROL_func)
103 static NTSTATUS CAPTIVE_STDCALL MajorFunction_DEVICE_CONTROL_func(IN DEVICE_OBJECT *DeviceObject,IN IRP *Irp)
104 {
105 struct captive_DriverObject *captive_DriverObject;
106 IO_STACK_LOCATION *IrpStack;
107
108         g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
109         g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
110
111         captive_DriverObject=(struct captive_DriverObject *)DeviceObject->DriverObject;
112
113         Irp->IoStatus.Information=0;    /* request-specific, may get overriden later */
114         IrpStack=IoGetCurrentIrpStackLocation(Irp);
115         g_assert(IrpStack->MajorFunction==IRP_MJ_DEVICE_CONTROL);
116         g_assert(IrpStack->MinorFunction==0);
117
118         switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
119
120                 case IOCTL_CDROM_GET_LAST_SESSION:
121                         /* Nothing interesting to see, move along.
122                          * FIXME: This call is somehow multisession related - must we care?
123                          */
124                         /* PASSTHRU */
125
126                 case IOCTL_CDROM_READ_TOC: {
127 CDROM_TOC *CdromToc;
128
129                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(CDROM_TOC)) {
130                                 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
131                                 Irp->IoStatus.Information=sizeof(CDROM_TOC);
132                                 g_assert_not_reached();
133                                 goto done;
134                                 }
135                         CdromToc=(CDROM_TOC *)Irp->AssociatedIrp.SystemBuffer;
136                         CAPTIVE_MEMZERO(CdromToc);
137                         CdromToc->Length[0]=((sizeof(*CdromToc)-2)>>0U)&0xFFU;  /* little-endian */
138                         CdromToc->Length[1]=((sizeof(*CdromToc)-2)>>8U)&0xFFU;
139                         CdromToc->FirstTrack=0; /* one track; TOC_LAST_TRACK does not count */
140                         CdromToc->LastTrack =0; /* one track; TOC_LAST_TRACK does not count */
141                         CdromToc->TrackData[0].Control=TOC_DATA_TRACK;
142                         CdromToc->TrackData[0].Adr=0;   /* Q-subchannel subinfo */
143                         CdromToc->TrackData[0].TrackNumber=0;
144                         CdromToc->TrackData[0].Address[0]=0>>24U;       /* LBA offset; big-endian */
145                         CdromToc->TrackData[0].Address[1]=0>>16U;
146                         CdromToc->TrackData[0].Address[2]=0>> 8U;
147                         CdromToc->TrackData[0].Address[3]=0>> 0U;
148                         CdromToc->TrackData[1].Control=0;
149                         CdromToc->TrackData[1].Adr=0;   /* Q-subchannel subinfo */
150                         CdromToc->TrackData[1].TrackNumber=TOC_LAST_TRACK;
151                         /* FIXME: should we put the captive_image_size to TOC_LAST_TRACK? */
152                         CdromToc->TrackData[1].Address[0]=(captive_image_size/512)>>24U;        /* LBA offset; big-endian */
153                         CdromToc->TrackData[1].Address[1]=(captive_image_size/512)>>16U;
154                         CdromToc->TrackData[1].Address[2]=(captive_image_size/512)>> 8U;
155                         CdromToc->TrackData[1].Address[3]=(captive_image_size/512)>> 0U;
156
157                         Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
158                         Irp->IoStatus.Status=STATUS_SUCCESS;
159                         } break;
160
161                 case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
162                 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
163                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(DISK_GEOMETRY)) {
164                                 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
165                                 Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
166                                 g_assert_not_reached();
167                                 goto done;
168                                 }
169                         *(DISK_GEOMETRY *)Irp->AssociatedIrp.SystemBuffer=captive_DriverObject->DiskGeometry;
170                         Irp->IoStatus.Information=sizeof(DISK_GEOMETRY);
171                         Irp->IoStatus.Status=STATUS_SUCCESS;
172                         break;
173
174                 case IOCTL_CDROM_CHECK_VERIFY:
175                 case IOCTL_DISK_CHECK_VERIFY:
176                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength) {
177                                 if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(ULONG)) {
178                                         Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
179                                         Irp->IoStatus.Information=sizeof(ULONG);
180                                         g_assert_not_reached();
181                                         goto done;
182                                         }
183                                 *(ULONG *)Irp->AssociatedIrp.SystemBuffer=0;    /* MediaChangeCount */
184                                 Irp->IoStatus.Information=sizeof(ULONG);
185                                 }
186                         else {
187                                 Irp->IoStatus.Information=0;
188                                 }
189                         Irp->IoStatus.Status=STATUS_SUCCESS;
190                         break;
191
192                 case IOCTL_SCSI_GET_CAPABILITIES:
193                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(IO_SCSI_CAPABILITIES)) {
194                                 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
195                                 Irp->IoStatus.Information=sizeof(IO_SCSI_CAPABILITIES);
196                                 g_assert_not_reached();
197                                 goto done;
198                                 }
199                         *(IO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer=captive_DriverObject->PortCapabilities;
200                         Irp->IoStatus.Information=sizeof(IO_SCSI_CAPABILITIES);
201                         Irp->IoStatus.Status=STATUS_SUCCESS;
202                         break;
203
204                 case IOCTL_DISK_GET_PARTITION_INFO: {
205 PARTITION_INFORMATION *PartitionInformation;
206
207                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(PARTITION_INFORMATION)) {
208                                 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
209                                 Irp->IoStatus.Information=sizeof(PARTITION_INFORMATION);
210                                 g_assert_not_reached();
211                                 goto done;
212                                 }
213                         PartitionInformation=(PARTITION_INFORMATION *)Irp->AssociatedIrp.SystemBuffer;
214                         PartitionInformation->StartingOffset.QuadPart=0;
215                         PartitionInformation->PartitionLength.QuadPart=captive_image_size;      /* unit=bytes */
216                         PartitionInformation->HiddenSectors=0;  /* FIXME: real image disk offset */
217                         PartitionInformation->PartitionNumber=1;
218                         PartitionInformation->PartitionType=0;  /* FIXME: meaning? */
219                         PartitionInformation->BootIndicator=TRUE;
220                         PartitionInformation->RecognizedPartition=TRUE;
221                         PartitionInformation->RewritePartition=FALSE;   /* FIXME: meaning? */
222                         Irp->IoStatus.Information=sizeof(PARTITION_INFORMATION);
223                         Irp->IoStatus.Status=STATUS_SUCCESS;
224                         } break;
225
226                 case IOCTL_DISK_GET_PARTITION_INFO_EX: {
227 PARTITION_INFORMATION_EX *PartitionInformationEx;
228
229                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(PARTITION_INFORMATION_EX)) {
230                                 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
231                                 Irp->IoStatus.Information=sizeof(PARTITION_INFORMATION_EX);
232                                 g_assert_not_reached();
233                                 goto done;
234                                 }
235                         PartitionInformationEx=(PARTITION_INFORMATION_EX *)Irp->AssociatedIrp.SystemBuffer;
236                         PartitionInformationEx->PartitionStyle=PARTITION_STYLE_RAW;     /* not MBR or GPT */
237                         PartitionInformationEx->StartingOffset.QuadPart=0;
238                         PartitionInformationEx->PartitionLength.QuadPart=captive_image_size;    /* unit=bytes */
239                         PartitionInformationEx->PartitionNumber=0;      /* FIXME: what number? */
240                         PartitionInformationEx->RewritePartition=FALSE; /* FIXME: meaning? */
241                         Irp->IoStatus.Information=sizeof(PARTITION_INFORMATION_EX);
242                         Irp->IoStatus.Status=STATUS_SUCCESS;
243                         } break;
244
245                 case IOCTL_STORAGE_GET_HOTPLUG_INFO:
246                         Irp->IoStatus.Status=STATUS_NOT_SUPPORTED;
247                         break;
248
249                 case IOCTL_DISK_IS_WRITABLE:
250                         Irp->IoStatus.Information=0;
251                         switch (captive_options->rwmode) {
252                                 case CAPTIVE_OPTION_RWMODE_RO:    Irp->IoStatus.Status=STATUS_MEDIA_WRITE_PROTECTED; break;
253                                 case CAPTIVE_OPTION_RWMODE_BLIND: Irp->IoStatus.Status=STATUS_SUCCESS;               break;
254                                 case CAPTIVE_OPTION_RWMODE_RW:    Irp->IoStatus.Status=STATUS_SUCCESS;               break;
255                                 default: g_assert_not_reached();
256                                 }
257                         break;
258
259                 case IOCTL_DISK_MEDIA_REMOVAL: {
260 PREVENT_MEDIA_REMOVAL *PreventMediaRemoval;
261
262                         /* FIXME: ntfs.sys calls this function with empty buffer; dunno what it means.
263                          */
264                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength==0) {
265                                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: IOCTL_DISK_MEDIA_REMOVAL with empty buffer",G_STRLOC);
266                                 Irp->IoStatus.Information=0;
267                                 Irp->IoStatus.Status=STATUS_SUCCESS;
268                                 break;
269                                 }
270                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(PREVENT_MEDIA_REMOVAL)) {
271                                 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
272                                 Irp->IoStatus.Information=sizeof(PREVENT_MEDIA_REMOVAL);
273                                 g_assert_not_reached();
274                                 goto done;
275                                 }
276                         PreventMediaRemoval=(PREVENT_MEDIA_REMOVAL *)Irp->AssociatedIrp.SystemBuffer;
277                         g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: IOCTL_DISK_MEDIA_REMOVAL now %s",
278                                         G_STRLOC,(PreventMediaRemoval->PreventMediaRemoval ? "TRUE" : "FALSE"));
279
280                         Irp->IoStatus.Information=sizeof(PREVENT_MEDIA_REMOVAL);
281                         Irp->IoStatus.Status=STATUS_SUCCESS;
282                         } break;
283
284                 case IOCTL_DISK_CONTROLLER_NUMBER: {
285 DISK_CONTROLLER_NUMBER *DiskControllerNumber;
286
287                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(DISK_CONTROLLER_NUMBER)) {
288                                 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
289                                 Irp->IoStatus.Information=sizeof(DISK_CONTROLLER_NUMBER);
290                                 g_assert_not_reached();
291                                 goto done;
292                                 }
293                         DiskControllerNumber=(DISK_CONTROLLER_NUMBER *)Irp->AssociatedIrp.SystemBuffer;
294                         DiskControllerNumber->ControllerNumber=0;       /* FIXME: based on 0 or 1? */
295                         DiskControllerNumber->DiskNumber=0;     /* FIXME: based on 0 or 1? */
296
297                         Irp->IoStatus.Information=sizeof(DISK_CONTROLLER_NUMBER);
298                         Irp->IoStatus.Status=STATUS_SUCCESS;
299                         } break;
300
301                 case IOCTL_DISK_GET_LENGTH_INFO: {
302 GET_LENGTH_INFORMATION *GetLengthInformation;
303
304                         if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength<sizeof(GET_LENGTH_INFORMATION)) {
305                                 Irp->IoStatus.Status=STATUS_BUFFER_TOO_SMALL;
306                                 Irp->IoStatus.Information=sizeof(GET_LENGTH_INFORMATION);
307                                 g_assert_not_reached();
308                                 goto done;
309                                 }
310                         GetLengthInformation=(GET_LENGTH_INFORMATION *)Irp->AssociatedIrp.SystemBuffer;
311                         GetLengthInformation->Length.QuadPart=captive_image_size;
312
313                         Irp->IoStatus.Information=sizeof(GET_LENGTH_INFORMATION);
314                         Irp->IoStatus.Status=STATUS_SUCCESS;
315                         } break;
316
317                 case 0x00664016:
318                         g_error("%s: Invalid media IOCTL 0x%08lx - by NtfsFixDataError()",G_STRLOC,
319                                         (unsigned long)IrpStack->Parameters.DeviceIoControl.IoControlCode);
320                         /* FALLTHRU */
321
322                 default:
323                         g_error("%s: Invalid media IOCTL 0x%08lX",G_STRLOC,
324                                         (unsigned long)IrpStack->Parameters.DeviceIoControl.IoControlCode);
325                         Irp->IoStatus.Status=STATUS_INVALID_DEVICE_REQUEST;
326                         g_assert_not_reached();
327                         goto done;
328                 }
329         /* PASSTHRU */
330
331 done:   /* 'err:' but we flow here even during success */
332         return MajorFunction_Irp_finish(DeviceObject,Irp);
333 }
334
335
336 struct MajorFunction_READ_WRITE_func_Parameters {
337                 ULONG Length;
338                 ULONG Key;
339                 LARGE_INTEGER ByteOffset;
340                 };
341
342 /* FIXME: We should comply with PDRIVER_DISPATCH prototype but unfortunately
343  * CAPTIVE_STDCALL prevents us to do so at least in RedHat gcc-3.2-4 (gcc bug?).
344  */
345 #define MajorFunction_READ_WRITE ((PDRIVER_DISPATCH)MajorFunction_READ_WRITE_func)
346 static NTSTATUS CAPTIVE_STDCALL MajorFunction_READ_WRITE_func(IN DEVICE_OBJECT *DeviceObject,IN IRP *Irp)
347 {
348 IO_STACK_LOCATION *IrpStack;
349 gpointer buffer=NULL;
350 GIOStatus erriostatus;
351 struct captive_DriverObject *captive_DriverObject;
352 const struct MajorFunction_READ_WRITE_func_Parameters *Parameters=NULL; /* Prevent: `Parameters' might be used uninitialized */
353
354   g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
355         g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
356
357         captive_DriverObject=(struct captive_DriverObject *)DeviceObject->DriverObject;
358
359         Irp->IoStatus.Information=0;    /* request-specific, may get overriden later */
360         IrpStack=IoGetCurrentIrpStackLocation(Irp);
361         g_assert(IrpStack->MajorFunction==IRP_MJ_READ || IrpStack->MajorFunction==IRP_MJ_WRITE);
362         g_assert(IrpStack->MinorFunction==0);
363
364 #define READ_WRITE_ASSERT_PARAMETERS_OFFSET(struct_a,struct_b,member) \
365                 g_assert(G_STRUCT_OFFSET(typeof(IrpStack->Parameters.struct_a),member) \
366                                 ==G_STRUCT_OFFSET(typeof(IrpStack->Parameters.struct_b),member))
367         READ_WRITE_ASSERT_PARAMETERS_OFFSET(Read,Write,Length);
368         READ_WRITE_ASSERT_PARAMETERS_OFFSET(Read,Write,Key);
369         READ_WRITE_ASSERT_PARAMETERS_OFFSET(Read,Write,ByteOffset);
370         READ_WRITE_ASSERT_PARAMETERS_OFFSET(Read,Write,ByteOffset.QuadPart);
371 #undef READ_WRITE_ASSERT_PARAMETERS_OFFSET
372
373         switch (IrpStack->MajorFunction) {
374                 case IRP_MJ_READ:  Parameters=(const struct MajorFunction_READ_WRITE_func_Parameters *)&IrpStack->Parameters.Read; break;
375                 case IRP_MJ_WRITE: Parameters=(const struct MajorFunction_READ_WRITE_func_Parameters *)&IrpStack->Parameters.Write; break;
376                 default: g_assert_not_reached();
377                 }
378
379         /* Autodetect 'buffer' as we are !DO_BUFFERED_IO && !DO_DIRECT_IO hybrid */
380         if (Irp->UserBuffer) {
381                 g_assert(buffer==NULL);
382                 buffer=Irp->UserBuffer;
383                 }
384         /* Forbid both IRP_BUFFERED_IO and IRP_ASSOCIATED_IRP as it should be IMO invalid state. */
385         g_assert(!((Irp->Flags & IRP_BUFFERED_IO) && (Irp->Flags & IRP_ASSOCIATED_IRP)));
386         if (Irp->Flags & IRP_BUFFERED_IO && Irp->AssociatedIrp.SystemBuffer) {
387                 g_assert(buffer==NULL);
388                 buffer=Irp->AssociatedIrp.SystemBuffer;
389                 }
390         if (Irp->MdlAddress) {
391                 /* See comment at ntoskrnl/io/buildirp.c/IoBuildSynchronousFsdRequestWithMdl()
392                  * initialization of 'Irp->UserBuffer'.
393                  */
394                 g_assert(buffer==MmGetSystemAddressForMdl(Irp->MdlAddress) || buffer==NULL);
395                 g_assert(Parameters->Length<=MmGetMdlByteCount(Irp->MdlAddress));
396                 buffer=MmGetSystemAddressForMdl(Irp->MdlAddress);
397                 }
398         g_assert(buffer!=NULL);
399
400         g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: %s: ByteOffset=0x%llX,Length=0x%lX",
401                         G_STRLOC,(IrpStack->MajorFunction==IRP_MJ_READ ? "IRP_MJ_READ" : "IRP_MJ_WRITE"),
402                         (guint64)Parameters->ByteOffset.QuadPart,(gulong)Parameters->Length);
403
404         erriostatus=g_io_channel_seek_position(captive_image_iochannel,
405                         Parameters->ByteOffset.QuadPart,        /* offset */
406                         G_SEEK_SET,     /* type */
407                         NULL);  /* error */
408         g_assert(erriostatus==G_IO_STATUS_NORMAL);
409
410         switch (IrpStack->MajorFunction) {
411                 case IRP_MJ_READ: {
412 gsize bytesread;
413
414                         erriostatus=g_io_channel_read_chars(captive_image_iochannel,
415                                         buffer, /* buf */
416                                         Parameters->Length,     /* count */
417                                         &bytesread,     /* bytesread */
418                                         NULL);  /* error */
419                         g_assert(erriostatus==G_IO_STATUS_NORMAL);
420                         g_assert(bytesread==Parameters->Length);
421                         } break;
422
423                 case IRP_MJ_WRITE: {
424 gsize byteswritten;
425
426                         erriostatus=g_io_channel_write_chars(captive_image_iochannel,
427                                         buffer, /* buf */
428                                         Parameters->Length,     /* count */
429                                         &byteswritten,  /* byteswritten */
430                                         NULL);  /* error */
431                         g_assert(erriostatus==G_IO_STATUS_NORMAL);
432                         g_assert(byteswritten==Parameters->Length);
433                         } break;
434
435                 default: g_assert_not_reached();
436                 }
437
438         Irp->IoStatus.Information=Parameters->Length;
439         Irp->IoStatus.Status=STATUS_SUCCESS;
440
441         /* PASSTHRU */
442 /* done: */     /* 'err:' but we flow here even during success */
443         return MajorFunction_Irp_finish(DeviceObject,Irp);
444 }
445
446
447 /* FIXME: We should comply with PDRIVER_DISPATCH prototype but unfortunately
448  * CAPTIVE_STDCALL prevents us to do so at least in RedHat gcc-3.2-4 (gcc bug?).
449  */
450 #define MajorFunction_SHUTDOWN ((PDRIVER_DISPATCH)MajorFunction_SHUTDOWN_func)
451 static NTSTATUS CAPTIVE_STDCALL MajorFunction_SHUTDOWN_func(IN DEVICE_OBJECT *DeviceObject,IN IRP *Irp)
452 {
453 IO_STACK_LOCATION *IrpStack;
454 GIOStatus erriostatus;
455 struct captive_DriverObject *captive_DriverObject;
456
457   g_return_val_if_fail(TRUE==validate_DeviceObject(DeviceObject),STATUS_INVALID_PARAMETER);
458         g_return_val_if_fail(Irp!=NULL,STATUS_INVALID_PARAMETER);
459
460         captive_DriverObject=(struct captive_DriverObject *)DeviceObject->DriverObject;
461
462         IrpStack=IoGetCurrentIrpStackLocation(Irp);
463         g_assert(IrpStack->MajorFunction==IRP_MJ_SHUTDOWN || IrpStack->MajorFunction==IRP_MJ_FLUSH_BUFFERS);
464         g_assert(IrpStack->MinorFunction==0);
465
466         /* libcaptive is not authorized to shutdown 'captive_image_channel'. */
467         erriostatus=g_io_channel_flush(
468                         captive_image_iochannel,        /* channel */
469                         NULL);  /* error */
470         g_assert(erriostatus==G_IO_STATUS_NORMAL);
471
472         Irp->IoStatus.Information=0;
473         Irp->IoStatus.Status=STATUS_SUCCESS;
474
475         return MajorFunction_Irp_finish(DeviceObject,Irp);
476 }
477
478
479 /* FLUSH_BUFFERS has exactly the functionality for us. */
480 #define MajorFunction_FLUSH_BUFFERS MajorFunction_SHUTDOWN
481
482
483 /* similiar to drivers/storage/cdrom/cdrom.c/DriverEntry()->...
484  * ...->CdromClassCreateDeviceObject()->
485  * ->reactos/drivers/storage/class2/class2.c/ScsiClassCreateDeviceObject()
486  * We should be driving a lower layer PortDevice but currently we
487  * do not provide it, I hope W32 filesystems don't touch it.
488  */
489 NTSTATUS captive_media_DriverEntry(struct captive_DriverObject *captive_DriverObject,PUNICODE_STRING RegistryPath)
490 {
491 DRIVER_OBJECT *DriverObject;
492 DEVICE_OBJECT *DeviceObject;
493 DEVICE_EXTENSION *DeviceExtension;
494 NTSTATUS err;
495
496         g_return_val_if_fail(captive_DriverObject!=NULL,STATUS_INVALID_PARAMETER);
497         g_return_val_if_fail(RegistryPath!=NULL,STATUS_INVALID_PARAMETER);
498
499         DriverObject=(DRIVER_OBJECT *)captive_DriverObject;
500
501         err=IoCreateDevice(
502                         DriverObject,   /* DriverObject */
503                         sizeof(DEVICE_EXTENSION),       /* DeviceExtensionSize; additional storage not used */
504                         captive_utf8_to_UnicodeString_alloca(captive_DriverObject->DeviceName_utf8),    /* DeviceName */
505                         captive_DriverObject->DeviceType,       /* DeviceType */
506                         captive_DriverObject->DeviceCharacteristics,    /* DeviceCharacteristics */
507                         FALSE,  /* Exclusive */
508                         &DeviceObject); /* DeviceObject */
509         g_return_val_if_fail(NT_SUCCESS(err),FALSE);
510
511         /* Currently we are !DO_BUFFERED_IO && !DO_DIRECT_IO and we must solve
512          * being called with 'Irp->UserBuffer', 'Irp->AssociatedIrp.SystemBuffer' or 'Irp->MdlAddress'.
513          */
514         /* should be left from IoCreateDevice(DeviceCharacteristics) above: */
515         if (captive_DriverObject->DeviceCharacteristics & FILE_REMOVABLE_MEDIA)
516                 g_assert(DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA);
517         /* ignored: DeviceObject->StackSize */
518         /* ignored: DeviceObject->AlignmentRequirement */
519
520         /* from reactos/drivers/storage/scsiport/scsiport.c/ScsiPortCreatePortDevice() */
521         captive_DriverObject->PortCapabilities.Length=sizeof(captive_DriverObject->PortCapabilities);
522         captive_DriverObject->PortCapabilities.MaximumTransferLength=0x10000;   /* 64KB */
523         g_assert((captive_DriverObject->PortCapabilities.MaximumTransferLength%PAGE_SIZE)==0);
524         captive_DriverObject->PortCapabilities.MaximumPhysicalPages=captive_DriverObject->PortCapabilities.MaximumTransferLength/PAGE_SIZE;
525         captive_DriverObject->PortCapabilities.SupportedAsynchronousEvents=0;
526         captive_DriverObject->PortCapabilities.AlignmentMask=1; /* no alignment required by us; speced as "integer multiple" */
527         captive_DriverObject->PortCapabilities.TaggedQueuing=FALSE;
528         captive_DriverObject->PortCapabilities.AdapterScansDown=FALSE;
529         captive_DriverObject->PortCapabilities.AdapterUsesPio=TRUE;
530         captive_DriverObject->PortCapabilities_check=captive_DriverObject->PortCapabilities;    /* for g_assert() checking against foreign modifications */
531
532         DeviceExtension=DeviceObject->DeviceExtension;
533         DeviceExtension->MediaChangeCount=0;
534         DeviceExtension->PhysicalDevice=DeviceObject;   /* no real PhysicalDeviceObject */
535         DeviceExtension->LockCount=0;
536         DeviceExtension->DeviceNumber=0;        /* corresponds to the # in "\\Device\\CdRom0" */
537         /* ignored DeviceExtension->PortDeviceObject
538          * as we are the final driver and we don't have any PortDeviceObject
539          */
540         DeviceExtension->PortCapabilities=&captive_DriverObject->PortCapabilities;
541         DeviceExtension->StartingOffset.QuadPart=0;
542         DeviceExtension->PartitionLength.QuadPart=captive_image_size;
543         DeviceExtension->PortNumber=0;
544         DeviceExtension->PathId=0;
545         DeviceExtension->TargetId=0;
546         DeviceExtension->Lun=0;
547
548         /* expect 'captive_DriverObject->DiskGeometry.MediaType' */
549         captive_DriverObject->DiskGeometry.TracksPerCylinder=64;
550         captive_DriverObject->DiskGeometry.SectorsPerTrack=32;
551         /* expect 'captive_DriverObject->DiskGeometry.BytesPerSector' */
552         captive_DriverObject->DiskGeometry.Cylinders.QuadPart=captive_image_size
553                         /captive_DriverObject->DiskGeometry.BytesPerSector
554                         /captive_DriverObject->DiskGeometry.SectorsPerTrack
555                         /captive_DriverObject->DiskGeometry.TracksPerCylinder;
556         /* 'DeviceExtension->DiskGeometry' is NULL! */
557         captive_DriverObject->DiskGeometry_check=captive_DriverObject->DiskGeometry;    /* for g_assert() checking against foreign modifications */
558         DeviceExtension->DiskGeometry=&captive_DriverObject->DiskGeometry;
559
560         DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]=MajorFunction_DEVICE_CONTROL;
561         DriverObject->MajorFunction[IRP_MJ_READ          ]=MajorFunction_READ_WRITE;
562         DriverObject->MajorFunction[IRP_MJ_WRITE         ]=MajorFunction_READ_WRITE;
563         DriverObject->MajorFunction[IRP_MJ_SHUTDOWN      ]=MajorFunction_SHUTDOWN;
564         DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS ]=MajorFunction_FLUSH_BUFFERS;
565
566         return STATUS_SUCCESS;
567 }