[httpdisk] Add success debug message to DriverEntry()
[people/sha0/winvblock.git] / src / httpdisk / httpdisk.c
1 /*
2     HTTP Virtual Disk.
3     Copyright (C) 2006 Bo Brantén.
4     Portions copyright (C) 2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
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     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     You should have received a copy of the GNU General Public License
14     along with this program; if not, write to the Free Software
15     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 */
17
18 #include <ntddk.h>
19 #include <ntdddisk.h>
20 #include <ntddcdrm.h>
21 #include <ntverp.h>
22 #include "ksocket.h"
23
24 //
25 // We include some stuff from newer DDK:s here so that one
26 // version of the driver for all versions of Windows can
27 // be compiled with the Windows NT 4.0 DDK.
28 //
29 #if (VER_PRODUCTBUILD < 2195)
30
31 #define FILE_DEVICE_MASS_STORAGE            0x0000002d
32 #define IOCTL_STORAGE_CHECK_VERIFY2         CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS)
33
34 #endif // (VER_PRODUCTBUILD < 2195)
35
36 #if (VER_PRODUCTBUILD < 2600)
37
38 #define IOCTL_DISK_GET_PARTITION_INFO_EX    CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS)
39 #define IOCTL_DISK_GET_LENGTH_INFO          CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
40
41 typedef enum _PARTITION_STYLE {
42     PARTITION_STYLE_MBR,
43     PARTITION_STYLE_GPT
44 } PARTITION_STYLE;
45
46 typedef unsigned __int64 ULONG64, *PULONG64;
47
48 typedef struct _PARTITION_INFORMATION_MBR {
49     UCHAR   PartitionType;
50     BOOLEAN BootIndicator;
51     BOOLEAN RecognizedPartition;
52     ULONG   HiddenSectors;
53 } PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR;
54
55 typedef struct _PARTITION_INFORMATION_GPT {
56     GUID    PartitionType;
57     GUID    PartitionId;
58     ULONG64 Attributes;
59     WCHAR   Name[36];
60 } PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT;
61
62 typedef struct _PARTITION_INFORMATION_EX {
63     PARTITION_STYLE PartitionStyle;
64     LARGE_INTEGER   StartingOffset;
65     LARGE_INTEGER   PartitionLength;
66     ULONG           PartitionNumber;
67     BOOLEAN         RewritePartition;
68     union {
69         PARTITION_INFORMATION_MBR Mbr;
70         PARTITION_INFORMATION_GPT Gpt;
71     };
72 } PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX;
73
74 typedef struct _GET_LENGTH_INFORMATION {
75     LARGE_INTEGER Length;
76 } GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;
77
78 #endif // (VER_PRODUCTBUILD < 2600)
79
80 //
81 // For backward compatibility with Windows NT 4.0 by Bruce Engle.
82 //
83 #ifndef MmGetSystemAddressForMdlSafe
84 #define MmGetSystemAddressForMdlSafe(MDL, PRIORITY) MmGetSystemAddressForMdlPrettySafe(MDL)
85
86 PVOID
87 MmGetSystemAddressForMdlPrettySafe (
88     PMDL Mdl
89     )
90 {
91     CSHORT  MdlMappingCanFail;
92     PVOID   MappedSystemVa;
93
94     MdlMappingCanFail = Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL;
95
96     Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
97
98     MappedSystemVa = MmGetSystemAddressForMdl(Mdl);
99
100     if (MdlMappingCanFail == 0)
101     {
102         Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL;
103     }
104
105     return MappedSystemVa;
106 }
107 #endif
108
109 #include "portable.h"
110 #include "httpdisk.h"
111 #include "winvblock.h"
112 #include "debug.h"
113
114 /* From bus.c */
115 extern NTSTATUS STDCALL HttpdiskBusEstablish(void);
116 extern VOID HttpdiskBusCleanup(void);
117 extern DRIVER_ADD_DEVICE HttpdiskBusAttach;
118 extern DRIVER_DISPATCH HttpdiskBusIrp;
119
120 /* For this file. */
121 #define PARAMETER_KEY           L"\\Parameters"
122
123 #define NUMBEROFDEVICES_VALUE   L"NumberOfDevices"
124
125 #define DEFAULT_NUMBEROFDEVICES 4
126
127 #define SECTOR_SIZE             512
128
129 #define TOC_DATA_TRACK          0x04
130
131 #define BUFFER_SIZE             (4096 * 4)
132
133 HANDLE dir_handle;
134 PDRIVER_OBJECT HttpdiskDriverObj = NULL;
135
136 typedef struct _HTTP_HEADER {
137     LARGE_INTEGER ContentLength;
138 } HTTP_HEADER, *PHTTP_HEADER;
139
140 NTSTATUS
141 DriverEntry (
142     IN PDRIVER_OBJECT   DriverObject,
143     IN PUNICODE_STRING  RegistryPath
144 );
145
146 NTSTATUS
147 HttpDiskCreateDevice (
148     IN PDRIVER_OBJECT   DriverObject,
149     IN ULONG            Number,
150     IN DEVICE_TYPE      DeviceType
151 );
152
153 VOID
154 HttpDiskUnload (
155     IN PDRIVER_OBJECT   DriverObject
156 );
157
158 PDEVICE_OBJECT
159 HttpDiskDeleteDevice (
160     IN PDEVICE_OBJECT   DeviceObject
161 );
162
163 static
164   __drv_dispatchType(IRP_MJ_CREATE)
165   __drv_dispatchType(IRP_MJ_CLOSE)
166   DRIVER_DISPATCH HttpdiskIrpCreateClose_;
167
168 static
169   __drv_dispatchType(IRP_MJ_READ)
170   __drv_dispatchType(IRP_MJ_WRITE)
171   DRIVER_DISPATCH HttpdiskIrpReadWrite_;
172
173 static
174   __drv_dispatchType(IRP_MJ_DEVICE_CONTROL)
175   DRIVER_DISPATCH HttpdiskIrpDevCtl_;
176
177 VOID
178 HttpDiskThread (
179     IN PVOID            Context
180 );
181
182 NTSTATUS
183 HttpDiskConnect (
184     IN PDEVICE_OBJECT   DeviceObject,
185     IN PIRP             Irp
186 );
187
188 NTSTATUS
189 HttpDiskDisconnect (
190     IN PDEVICE_OBJECT   DeviceObject,
191     IN PIRP             Irp
192 );
193
194 NTSTATUS
195 HttpDiskGetHeader (
196     IN ULONG                Address,
197     IN USHORT               Port,
198     IN PUCHAR               HostName,
199     IN PUCHAR               FileName,
200     OUT PIO_STATUS_BLOCK    IoStatus,
201     OUT PHTTP_HEADER        HttpHeader
202 );
203
204 NTSTATUS
205 HttpDiskGetBlock (
206     IN int                  *Socket,
207     IN ULONG                Address,
208     IN USHORT               Port,
209     IN PUCHAR               HostName,
210     IN PUCHAR               FileName,
211     IN PLARGE_INTEGER       Offset,
212     IN ULONG                Length,
213     OUT PIO_STATUS_BLOCK    IoStatus,
214     OUT PVOID               SystemBuffer
215 );
216
217 __int64 __cdecl _atoi64(const char *);
218 int __cdecl _snprintf(char *, size_t, const char *, ...);
219 int __cdecl swprintf(wchar_t *, const wchar_t *, ...);
220
221 /** Memory allocation functions. */
222 PVOID HttpDiskMalloc(SIZE_T size) {
223     return ExAllocatePoolWithTag(NonPagedPool, size, 'DHvW');
224   }
225
226 PVOID HttpDiskPalloc(SIZE_T size) {
227     /*
228      * The call-points for this function merely place-hold for where
229      * Bo's original work allocated from paged pool.  Since this
230      * version is intended for booting, we don't use paged pool.
231      */
232     return ExAllocatePoolWithTag(NonPagedPool, size, 'DHvW');
233   }
234
235 #pragma code_seg("INIT")
236
237 NTSTATUS
238 DriverEntry (
239     IN PDRIVER_OBJECT   DriverObject,
240     IN PUNICODE_STRING  RegistryPath
241     )
242 {
243     UNICODE_STRING              parameter_path;
244     RTL_QUERY_REGISTRY_TABLE    query_table[2];
245     ULONG                       n_devices;
246     NTSTATUS                    status;
247     UNICODE_STRING              device_dir_name;
248     OBJECT_ATTRIBUTES           object_attributes;
249     ULONG                       n;
250     USHORT                      n_created_devices;
251
252     HttpdiskDriverObj = DriverObject;
253
254     parameter_path.Length = 0;
255
256     parameter_path.MaximumLength = RegistryPath->Length + sizeof(PARAMETER_KEY);
257
258     parameter_path.Buffer = HttpDiskPalloc(parameter_path.MaximumLength);
259
260     if (parameter_path.Buffer == NULL)
261     {
262         return STATUS_INSUFFICIENT_RESOURCES;
263     }
264
265     RtlCopyUnicodeString(&parameter_path, RegistryPath);
266
267     RtlAppendUnicodeToString(&parameter_path, PARAMETER_KEY);
268
269     RtlZeroMemory(&query_table[0], sizeof(query_table));
270
271     query_table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
272     query_table[0].Name = NUMBEROFDEVICES_VALUE;
273     query_table[0].EntryContext = &n_devices;
274
275     status = RtlQueryRegistryValues(
276         RTL_REGISTRY_ABSOLUTE,
277         parameter_path.Buffer,
278         &query_table[0],
279         NULL,
280         NULL
281         );
282
283     ExFreePool(parameter_path.Buffer);
284
285     if (!NT_SUCCESS(status))
286     {
287         DbgPrint("HttpDisk: Query registry failed, using default values.\n");
288         n_devices = DEFAULT_NUMBEROFDEVICES;
289     }
290
291     RtlInitUnicodeString(&device_dir_name, DEVICE_DIR_NAME);
292
293     InitializeObjectAttributes(
294         &object_attributes,
295         &device_dir_name,
296         OBJ_PERMANENT,
297         NULL,
298         NULL
299         );
300
301     status = ZwCreateDirectoryObject(
302         &dir_handle,
303         DIRECTORY_ALL_ACCESS,
304         &object_attributes
305         );
306
307     if (!NT_SUCCESS(status))
308     {
309         return status;
310     }
311
312     ZwMakeTemporaryObject(dir_handle);
313
314     for (n = 0, n_created_devices = 0; n < n_devices; n++)
315     {
316         status = HttpDiskCreateDevice(DriverObject, n, FILE_DEVICE_DISK);
317
318         if (NT_SUCCESS(status))
319         {
320             n_created_devices++;
321         }
322     }
323
324     for (n = 0; n < n_devices; n++)
325     {
326         status = HttpDiskCreateDevice(DriverObject, n, FILE_DEVICE_CD_ROM);
327
328         if (NT_SUCCESS(status))
329         {
330             n_created_devices++;
331         }
332     }
333
334     if (n_created_devices == 0)
335     {
336         ZwClose(dir_handle);
337         return status;
338     }
339
340     DriverObject->MajorFunction[IRP_MJ_CREATE] = HttpdiskIrpCreateClose_;
341     DriverObject->MajorFunction[IRP_MJ_CLOSE] = HttpdiskIrpCreateClose_;
342     DriverObject->MajorFunction[IRP_MJ_READ] = HttpdiskIrpReadWrite_;
343     DriverObject->MajorFunction[IRP_MJ_WRITE] = HttpdiskIrpReadWrite_;
344     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HttpdiskIrpDevCtl_;
345
346     DriverObject->DriverUnload = HttpDiskUnload;
347     DriverObject->DriverExtension->AddDevice = HttpdiskBusAttach;
348
349     status = HttpdiskBusEstablish();
350     if (!NT_SUCCESS(status))
351       HttpDiskUnload(DriverObject);
352
353     DBG("Success.\n");
354     return status;
355 }
356
357 NTSTATUS
358 HttpDiskCreateDevice (
359     IN PDRIVER_OBJECT   DriverObject,
360     IN ULONG            Number,
361     IN DEVICE_TYPE      DeviceType
362     )
363 {
364     WCHAR               device_name_buffer[MAXIMUM_FILENAME_LENGTH];
365     UNICODE_STRING      device_name;
366     NTSTATUS            status;
367     PDEVICE_OBJECT      device_object;
368     HTTPDISK_SP_DEV   device_extension;
369     HANDLE              thread_handle;
370
371     ASSERT(DriverObject != NULL);
372
373     if (DeviceType == FILE_DEVICE_CD_ROM)
374     {
375         swprintf(
376             device_name_buffer,
377             DEVICE_NAME_PREFIX L"Cd" L"%u",
378             Number
379             );
380     }
381     else
382     {
383         swprintf(
384             device_name_buffer,
385             DEVICE_NAME_PREFIX L"Disk" L"%u",
386             Number
387             );
388     }
389
390     RtlInitUnicodeString(&device_name, device_name_buffer);
391
392     status = IoCreateDevice(
393         DriverObject,
394         sizeof (HTTPDISK_S_DEV),
395         &device_name,
396         DeviceType,
397         0,
398         FALSE,
399         &device_object
400         );
401
402     if (!NT_SUCCESS(status))
403     {
404         return status;
405     }
406
407     device_object->Flags |= DO_DIRECT_IO;
408
409     device_extension = (HTTPDISK_SP_DEV) device_object->DeviceExtension;
410
411     device_extension->media_in_device = FALSE;
412
413     device_extension->host_name = NULL;
414
415     device_extension->file_name = NULL;
416
417     device_extension->socket = -1;
418
419     device_object->Characteristics |= FILE_READ_ONLY_DEVICE;
420
421     InitializeListHead(&device_extension->list_head);
422
423     KeInitializeSpinLock(&device_extension->list_lock);
424
425     KeInitializeEvent(
426         &device_extension->request_event,
427         SynchronizationEvent,
428         FALSE
429         );
430
431     device_extension->terminate_thread = FALSE;
432
433     device_extension->bus = FALSE;
434
435     status = PsCreateSystemThread(
436         &thread_handle,
437         (ACCESS_MASK) 0L,
438         NULL,
439         NULL,
440         NULL,
441         HttpDiskThread,
442         device_object
443         );
444
445     if (!NT_SUCCESS(status))
446     {
447         IoDeleteDevice(device_object);
448         return status;
449     }
450
451     status = ObReferenceObjectByHandle(
452         thread_handle,
453         THREAD_ALL_ACCESS,
454         NULL,
455         KernelMode,
456         &device_extension->thread_pointer,
457         NULL
458         );
459
460     if (!NT_SUCCESS(status))
461     {
462         ZwClose(thread_handle);
463
464         device_extension->terminate_thread = TRUE;
465
466         KeSetEvent(
467             &device_extension->request_event,
468             (KPRIORITY) 0,
469             FALSE
470             );
471
472         IoDeleteDevice(device_object);
473
474         return status;
475     }
476
477     ZwClose(thread_handle);
478
479     return STATUS_SUCCESS;
480 }
481
482 #pragma code_seg("PAGE")
483
484 VOID
485 HttpDiskUnload (
486     IN PDRIVER_OBJECT DriverObject
487     )
488 {
489     PDEVICE_OBJECT device_object;
490
491     HttpdiskBusCleanup();
492
493     device_object = DriverObject->DeviceObject;
494
495     while (device_object)
496     {
497         device_object = HttpDiskDeleteDevice(device_object);
498     }
499
500     ZwClose(dir_handle);
501 }
502
503 PDEVICE_OBJECT
504 HttpDiskDeleteDevice (
505     IN PDEVICE_OBJECT DeviceObject
506     )
507 {
508     HTTPDISK_SP_DEV   device_extension;
509     PDEVICE_OBJECT      next_device_object;
510
511     ASSERT(DeviceObject != NULL);
512
513     device_extension = (HTTPDISK_SP_DEV) DeviceObject->DeviceExtension;
514
515     device_extension->terminate_thread = TRUE;
516
517     KeSetEvent(
518         &device_extension->request_event,
519         (KPRIORITY) 0,
520         FALSE
521         );
522
523     KeWaitForSingleObject(
524         device_extension->thread_pointer,
525         Executive,
526         KernelMode,
527         FALSE,
528         NULL
529         );
530
531     ObDereferenceObject(device_extension->thread_pointer);
532
533     next_device_object = DeviceObject->NextDevice;
534
535     IoDeleteDevice(DeviceObject);
536
537     return next_device_object;
538 }
539
540 static NTSTATUS HttpdiskIrpCreateClose_(
541     IN PDEVICE_OBJECT   DeviceObject,
542     IN PIRP             Irp
543   ) {
544     HTTPDISK_SP_DEV   device_extension;
545
546     device_extension = (HTTPDISK_SP_DEV) DeviceObject->DeviceExtension;
547
548     /* Check for a bus IRP. */
549     if (device_extension->bus)
550       return HttpdiskBusIrp(DeviceObject, Irp);
551
552     Irp->IoStatus.Status = STATUS_SUCCESS;
553     Irp->IoStatus.Information = FILE_OPENED;
554
555     IoCompleteRequest(Irp, IO_NO_INCREMENT);
556
557     return STATUS_SUCCESS;
558   }
559
560 #pragma code_seg()
561
562 static NTSTATUS HttpdiskIrpReadWrite_(
563     IN PDEVICE_OBJECT   DeviceObject,
564     IN PIRP             Irp
565   ) {
566     HTTPDISK_SP_DEV   device_extension;
567     PIO_STACK_LOCATION  io_stack;
568
569     device_extension = (HTTPDISK_SP_DEV) DeviceObject->DeviceExtension;
570
571     /* Check for a bus IRP. */
572     if (device_extension->bus)
573       return HttpdiskBusIrp(DeviceObject, Irp);
574
575     if (!device_extension->media_in_device)
576     {
577         Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
578         Irp->IoStatus.Information = 0;
579
580         IoCompleteRequest(Irp, IO_NO_INCREMENT);
581
582         return STATUS_NO_MEDIA_IN_DEVICE;
583     }
584
585     io_stack = IoGetCurrentIrpStackLocation(Irp);
586
587     if (io_stack->Parameters.Read.Length == 0)
588     {
589         Irp->IoStatus.Status = STATUS_SUCCESS;
590         Irp->IoStatus.Information = 0;
591
592         IoCompleteRequest(Irp, IO_NO_INCREMENT);
593
594         return STATUS_SUCCESS;
595     }
596
597     IoMarkIrpPending(Irp);
598
599     ExInterlockedInsertTailList(
600         &device_extension->list_head,
601         &Irp->Tail.Overlay.ListEntry,
602         &device_extension->list_lock
603         );
604
605     KeSetEvent(
606         &device_extension->request_event,
607         (KPRIORITY) 0,
608         FALSE
609         );
610
611     return STATUS_PENDING;
612   }
613
614 static NTSTATUS HttpdiskIrpDevCtl_(
615     IN PDEVICE_OBJECT   DeviceObject,
616     IN PIRP             Irp
617   ) {
618     HTTPDISK_SP_DEV   device_extension;
619     PIO_STACK_LOCATION  io_stack;
620     NTSTATUS            status;
621
622     device_extension = (HTTPDISK_SP_DEV) DeviceObject->DeviceExtension;
623
624     /* Check for a bus IRP. */
625     if (device_extension->bus)
626       return HttpdiskBusIrp(DeviceObject, Irp);
627
628     io_stack = IoGetCurrentIrpStackLocation(Irp);
629
630     if (!device_extension->media_in_device &&
631         io_stack->Parameters.DeviceIoControl.IoControlCode !=
632         IOCTL_HTTP_DISK_CONNECT)
633     {
634         Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
635         Irp->IoStatus.Information = 0;
636
637         IoCompleteRequest(Irp, IO_NO_INCREMENT);
638
639         return STATUS_NO_MEDIA_IN_DEVICE;
640     }
641
642     switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
643     {
644     case IOCTL_HTTP_DISK_CONNECT:
645         {
646             if (device_extension->media_in_device)
647             {
648                 DbgPrint("HttpDisk: IOCTL_HTTP_DISK_CONNECT: Media already opened.\n");
649
650                 status = STATUS_INVALID_DEVICE_REQUEST;
651                 Irp->IoStatus.Information = 0;
652                 break;
653             }
654
655             if (io_stack->Parameters.DeviceIoControl.InputBufferLength <
656                 sizeof(HTTP_DISK_INFORMATION))
657             {
658                 status = STATUS_INVALID_PARAMETER;
659                 Irp->IoStatus.Information = 0;
660                 break;
661             }
662
663             if (io_stack->Parameters.DeviceIoControl.InputBufferLength <
664                 sizeof(HTTP_DISK_INFORMATION) +
665                 ((PHTTP_DISK_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->FileNameLength -
666                 sizeof(UCHAR))
667             {
668                 status = STATUS_INVALID_PARAMETER;
669                 Irp->IoStatus.Information = 0;
670                 break;
671             }
672
673             IoMarkIrpPending(Irp);
674
675             ExInterlockedInsertTailList(
676                 &device_extension->list_head,
677                 &Irp->Tail.Overlay.ListEntry,
678                 &device_extension->list_lock
679                 );
680
681             KeSetEvent(
682                 &device_extension->request_event,
683                 (KPRIORITY) 0,
684                 FALSE
685                 );
686
687             status = STATUS_PENDING;
688
689             break;
690         }
691
692     case IOCTL_HTTP_DISK_DISCONNECT:
693         {
694             IoMarkIrpPending(Irp);
695
696             ExInterlockedInsertTailList(
697                 &device_extension->list_head,
698                 &Irp->Tail.Overlay.ListEntry,
699                 &device_extension->list_lock
700                 );
701
702             KeSetEvent(
703                 &device_extension->request_event,
704                 (KPRIORITY) 0,
705                 FALSE
706                 );
707
708             status = STATUS_PENDING;
709
710             break;
711         }
712
713     case IOCTL_DISK_CHECK_VERIFY:
714     case IOCTL_CDROM_CHECK_VERIFY:
715     case IOCTL_STORAGE_CHECK_VERIFY:
716     case IOCTL_STORAGE_CHECK_VERIFY2:
717         {
718             status = STATUS_SUCCESS;
719             Irp->IoStatus.Information = 0;
720             break;
721         }
722
723     case IOCTL_DISK_GET_DRIVE_GEOMETRY:
724     case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
725         {
726             PDISK_GEOMETRY  disk_geometry;
727             ULONGLONG       length;
728
729             if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
730                 sizeof(DISK_GEOMETRY))
731             {
732                 status = STATUS_BUFFER_TOO_SMALL;
733                 Irp->IoStatus.Information = 0;
734                 break;
735             }
736
737             disk_geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
738
739             length = device_extension->file_size.QuadPart;
740
741             disk_geometry->Cylinders.QuadPart = length / SECTOR_SIZE / 32 / 2;
742             disk_geometry->MediaType = FixedMedia;
743             disk_geometry->TracksPerCylinder = 2;
744             disk_geometry->SectorsPerTrack = 32;
745             disk_geometry->BytesPerSector = SECTOR_SIZE;
746
747             status = STATUS_SUCCESS;
748             Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
749
750             break;
751         }
752
753     case IOCTL_DISK_GET_LENGTH_INFO:
754         {
755             PGET_LENGTH_INFORMATION get_length_information;
756
757             if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
758                 sizeof(GET_LENGTH_INFORMATION))
759             {
760                 status = STATUS_BUFFER_TOO_SMALL;
761                 Irp->IoStatus.Information = 0;
762                 break;
763             }
764
765             get_length_information = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
766
767             get_length_information->Length.QuadPart = device_extension->file_size.QuadPart;
768
769             status = STATUS_SUCCESS;
770             Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
771
772         break;
773         }
774
775     case IOCTL_DISK_GET_PARTITION_INFO:
776         {
777             PPARTITION_INFORMATION  partition_information;
778             ULONGLONG               length;
779
780             if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
781                 sizeof(PARTITION_INFORMATION))
782             {
783                 status = STATUS_BUFFER_TOO_SMALL;
784                 Irp->IoStatus.Information = 0;
785                 break;
786             }
787
788             partition_information = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
789
790             length = device_extension->file_size.QuadPart;
791
792             partition_information->StartingOffset.QuadPart = 0;
793             partition_information->PartitionLength.QuadPart = length;
794             partition_information->HiddenSectors = 1;
795             partition_information->PartitionNumber = 0;
796             partition_information->PartitionType = 0;
797             partition_information->BootIndicator = FALSE;
798             partition_information->RecognizedPartition = FALSE;
799             partition_information->RewritePartition = FALSE;
800
801             status = STATUS_SUCCESS;
802             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
803
804             break;
805         }
806
807     case IOCTL_DISK_GET_PARTITION_INFO_EX:
808         {
809             PPARTITION_INFORMATION_EX   partition_information_ex;
810             ULONGLONG                   length;
811
812             if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
813                 sizeof(PARTITION_INFORMATION_EX))
814             {
815                 status = STATUS_BUFFER_TOO_SMALL;
816                 Irp->IoStatus.Information = 0;
817                 break;
818             }
819
820             partition_information_ex = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
821
822             length = device_extension->file_size.QuadPart;
823
824             partition_information_ex->PartitionStyle = PARTITION_STYLE_MBR;
825             partition_information_ex->StartingOffset.QuadPart = 0;
826             partition_information_ex->PartitionLength.QuadPart = length;
827             partition_information_ex->PartitionNumber = 0;
828             partition_information_ex->RewritePartition = FALSE;
829             partition_information_ex->Mbr.PartitionType = 0;
830             partition_information_ex->Mbr.BootIndicator = FALSE;
831             partition_information_ex->Mbr.RecognizedPartition = FALSE;
832             partition_information_ex->Mbr.HiddenSectors = 1;
833
834             status = STATUS_SUCCESS;
835             Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
836
837             break;
838         }
839
840     case IOCTL_DISK_IS_WRITABLE:
841         {
842             status = STATUS_MEDIA_WRITE_PROTECTED;
843             Irp->IoStatus.Information = 0;
844             break;
845         }
846
847     case IOCTL_DISK_MEDIA_REMOVAL:
848     case IOCTL_STORAGE_MEDIA_REMOVAL:
849         {
850             status = STATUS_SUCCESS;
851             Irp->IoStatus.Information = 0;
852             break;
853         }
854
855     case IOCTL_CDROM_READ_TOC:
856         {
857             PCDROM_TOC cdrom_toc;
858
859             if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
860                 sizeof(CDROM_TOC))
861             {
862                 status = STATUS_BUFFER_TOO_SMALL;
863                 Irp->IoStatus.Information = 0;
864                 break;
865             }
866
867             cdrom_toc = (PCDROM_TOC) Irp->AssociatedIrp.SystemBuffer;
868
869             RtlZeroMemory(cdrom_toc, sizeof(CDROM_TOC));
870
871             cdrom_toc->FirstTrack = 1;
872             cdrom_toc->LastTrack = 1;
873             cdrom_toc->TrackData[0].Control = TOC_DATA_TRACK;
874
875             status = STATUS_SUCCESS;
876             Irp->IoStatus.Information = sizeof(CDROM_TOC);
877
878             break;
879         }
880
881     case IOCTL_DISK_SET_PARTITION_INFO:
882         {
883             status = STATUS_MEDIA_WRITE_PROTECTED;
884             Irp->IoStatus.Information = 0;
885             break;
886         }
887
888     case IOCTL_DISK_VERIFY:
889         {
890             PVERIFY_INFORMATION verify_information;
891
892             if (io_stack->Parameters.DeviceIoControl.InputBufferLength <
893                 sizeof(VERIFY_INFORMATION))
894             {
895                 status = STATUS_INVALID_PARAMETER;
896                 Irp->IoStatus.Information = 0;
897                 break;
898             }
899
900             verify_information = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
901
902             status = STATUS_SUCCESS;
903             Irp->IoStatus.Information = verify_information->Length;
904
905             break;
906         }
907
908     default:
909         {
910             KdPrint((
911                 "HttpDisk: Unknown IoControlCode: %#x\n",
912                 io_stack->Parameters.DeviceIoControl.IoControlCode
913                 ));
914
915             status = STATUS_INVALID_DEVICE_REQUEST;
916             Irp->IoStatus.Information = 0;
917         }
918     }
919
920     if (status != STATUS_PENDING)
921     {
922         Irp->IoStatus.Status = status;
923
924         IoCompleteRequest(Irp, IO_NO_INCREMENT);
925     }
926
927     return status;
928   }
929
930 #pragma code_seg("PAGE")
931
932 VOID
933 HttpDiskThread (
934     IN PVOID Context
935     )
936 {
937     PDEVICE_OBJECT      device_object;
938     HTTPDISK_SP_DEV   device_extension;
939     PLIST_ENTRY         request;
940     PIRP                irp;
941     PIO_STACK_LOCATION  io_stack;
942
943     ASSERT(Context != NULL);
944
945     device_object = (PDEVICE_OBJECT) Context;
946
947     device_extension = (HTTPDISK_SP_DEV) device_object->DeviceExtension;
948
949     KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
950
951     for (;;)
952     {
953         KeWaitForSingleObject(
954             &device_extension->request_event,
955             Executive,
956             KernelMode,
957             FALSE,
958             NULL
959             );
960
961         if (device_extension->terminate_thread)
962         {
963             PsTerminateSystemThread(STATUS_SUCCESS);
964         }
965
966         while (request = ExInterlockedRemoveHeadList(
967             &device_extension->list_head,
968             &device_extension->list_lock
969             ))
970         {
971             irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
972
973             io_stack = IoGetCurrentIrpStackLocation(irp);
974
975             switch (io_stack->MajorFunction)
976             {
977             case IRP_MJ_READ:
978                 HttpDiskGetBlock(
979                     &device_extension->socket,
980                     device_extension->address,
981                     device_extension->port,
982                     device_extension->host_name,
983                     device_extension->file_name,
984                     &io_stack->Parameters.Read.ByteOffset,
985                     io_stack->Parameters.Read.Length,
986                     &irp->IoStatus,
987                     MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority)
988                     );
989                 if (!NT_SUCCESS(irp->IoStatus.Status))
990                 {
991                     HttpDiskGetBlock(
992                         &device_extension->socket,
993                         device_extension->address,
994                         device_extension->port,
995                         device_extension->host_name,
996                         device_extension->file_name,
997                         &io_stack->Parameters.Read.ByteOffset,
998                         io_stack->Parameters.Read.Length,
999                         &irp->IoStatus,
1000                         MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority)
1001                         );
1002                 }
1003                 break;
1004
1005             case IRP_MJ_WRITE:
1006                 irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
1007                 irp->IoStatus.Information = 0;
1008                 break;
1009
1010             case IRP_MJ_DEVICE_CONTROL:
1011                 switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
1012                 {
1013                 case IOCTL_HTTP_DISK_CONNECT:
1014                     irp->IoStatus.Status = HttpDiskConnect(device_object, irp);
1015                     break;
1016
1017                 case IOCTL_HTTP_DISK_DISCONNECT:
1018                     irp->IoStatus.Status = HttpDiskDisconnect(device_object, irp);
1019                     break;
1020
1021                 default:
1022                     irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
1023                 }
1024                 break;
1025
1026             default:
1027                 irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
1028             }
1029
1030             IoCompleteRequest(
1031                 irp,
1032                 (CCHAR) (NT_SUCCESS(irp->IoStatus.Status) ?
1033                 IO_DISK_INCREMENT : IO_NO_INCREMENT)
1034                 );
1035         }
1036     }
1037 }
1038
1039 NTSTATUS
1040 HttpDiskConnect (
1041     IN PDEVICE_OBJECT   DeviceObject,
1042     IN PIRP             Irp
1043     )
1044 {
1045     HTTPDISK_SP_DEV       device_extension;
1046     PHTTP_DISK_INFORMATION  http_disk_information;
1047     HTTP_HEADER             http_header;
1048
1049     ASSERT(DeviceObject != NULL);
1050     ASSERT(Irp != NULL);
1051
1052     device_extension = (HTTPDISK_SP_DEV) DeviceObject->DeviceExtension;
1053
1054     http_disk_information = (PHTTP_DISK_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
1055
1056     device_extension->address = http_disk_information->Address;
1057
1058     device_extension->port = http_disk_information->Port;
1059
1060     device_extension->host_name = HttpDiskMalloc(
1061         http_disk_information->HostNameLength + 1
1062       );
1063
1064     if (device_extension->host_name == NULL)
1065     {
1066         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1067         return Irp->IoStatus.Status;
1068     }
1069
1070     RtlCopyMemory(
1071         device_extension->host_name,
1072         http_disk_information->HostName,
1073         http_disk_information->HostNameLength
1074         );
1075
1076     device_extension->host_name[http_disk_information->HostNameLength] = '\0';
1077
1078     device_extension->file_name = HttpDiskMalloc(
1079         http_disk_information->FileNameLength + 1
1080       );
1081
1082     if (device_extension->file_name == NULL)
1083     {
1084         if (device_extension->host_name != NULL)
1085         {
1086             ExFreePool(device_extension->host_name);
1087             device_extension->host_name = NULL;
1088         }
1089
1090         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
1091         return Irp->IoStatus.Status;
1092     }
1093
1094     RtlCopyMemory(
1095         device_extension->file_name,
1096         http_disk_information->FileName,
1097         http_disk_information->FileNameLength
1098         );
1099
1100     device_extension->file_name[http_disk_information->FileNameLength] = '\0';
1101
1102     HttpDiskGetHeader(
1103         device_extension->address,
1104         device_extension->port,
1105         device_extension->host_name,
1106         device_extension->file_name,
1107         &Irp->IoStatus,
1108         &http_header
1109         );
1110
1111     if (!NT_SUCCESS(Irp->IoStatus.Status))
1112     {
1113         HttpDiskGetHeader(
1114             device_extension->address,
1115             device_extension->port,
1116             device_extension->host_name,
1117             device_extension->file_name,
1118             &Irp->IoStatus,
1119             &http_header
1120             );
1121     }
1122
1123     if (!NT_SUCCESS(Irp->IoStatus.Status))
1124     {
1125         if (device_extension->host_name != NULL)
1126         {
1127             ExFreePool(device_extension->host_name);
1128             device_extension->host_name = NULL;
1129         }
1130
1131         if (device_extension->file_name != NULL)
1132         {
1133             ExFreePool(device_extension->file_name);
1134             device_extension->file_name = NULL;
1135         }
1136
1137         return Irp->IoStatus.Status;
1138     }
1139
1140     device_extension->file_size.QuadPart = http_header.ContentLength.QuadPart;
1141
1142     device_extension->media_in_device = TRUE;
1143
1144     return Irp->IoStatus.Status;
1145 }
1146
1147 NTSTATUS
1148 HttpDiskDisconnect (
1149     IN PDEVICE_OBJECT   DeviceObject,
1150     IN PIRP             Irp
1151     )
1152 {
1153     HTTPDISK_SP_DEV device_extension;
1154
1155     ASSERT(DeviceObject != NULL);
1156     ASSERT(Irp != NULL);
1157
1158     device_extension = (HTTPDISK_SP_DEV) DeviceObject->DeviceExtension;
1159
1160     device_extension->media_in_device = FALSE;
1161
1162     if (device_extension->host_name != NULL)
1163     {
1164         ExFreePool(device_extension->host_name);
1165         device_extension->host_name = NULL;
1166     }
1167
1168     if (device_extension->file_name != NULL)
1169     {
1170         ExFreePool(device_extension->file_name);
1171         device_extension->file_name = NULL;
1172     }
1173
1174     if (device_extension->socket > 0)
1175     {
1176         close(device_extension->socket);
1177         device_extension->socket = -1;
1178     }
1179
1180     Irp->IoStatus.Status = STATUS_SUCCESS;
1181     Irp->IoStatus.Information = 0;
1182
1183     return STATUS_SUCCESS;
1184 }
1185
1186 NTSTATUS
1187 HttpDiskGetHeader (
1188     IN ULONG                Address,
1189     IN USHORT               Port,
1190     IN PUCHAR               HostName,
1191     IN PUCHAR               FileName,
1192     OUT PIO_STATUS_BLOCK    IoStatus,
1193     OUT PHTTP_HEADER        HttpHeader
1194     )
1195 {
1196     int                 kSocket;
1197     struct sockaddr_in  toAddr;
1198     int                 status, nSent, nRecv;
1199     char                *buffer, *pStr;
1200
1201     ASSERT(HostName != NULL);
1202     ASSERT(FileName != NULL);
1203     ASSERT(IoStatus != NULL);
1204     ASSERT(HttpHeader != NULL);
1205
1206     buffer = HttpDiskPalloc(BUFFER_SIZE);
1207
1208     if (buffer == NULL)
1209     {
1210         IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
1211         return IoStatus->Status;
1212     }
1213
1214     kSocket = socket(AF_INET, SOCK_STREAM, 0);
1215
1216     if (kSocket < 0)
1217     {
1218         DbgPrint("HttpDisk: socket() error: %#x\n", kSocket);
1219         ExFreePool(buffer);
1220         IoStatus->Status = kSocket;
1221         return IoStatus->Status;
1222     }
1223
1224     toAddr.sin_family = AF_INET;
1225     toAddr.sin_port = Port;
1226     toAddr.sin_addr.s_addr = Address;
1227
1228     status = connect(kSocket, (struct sockaddr*) &toAddr, sizeof(toAddr));
1229
1230     if (status < 0)
1231     {
1232         DbgPrint("HttpDisk: connect() error: %#x\n", status);
1233         ExFreePool(buffer);
1234         close(kSocket);
1235         IoStatus->Status = status;
1236         return IoStatus->Status;
1237     }
1238
1239     // Example request:
1240     //  HEAD 'FileName' HTTP/1.1
1241     //  Host: 'HostName'
1242     //  Accept: */*
1243     //  User-Agent: HttpDisk/1.2
1244     //  Connection: close
1245     //
1246     // Interesting lines in answer:
1247     //  HTTP/1.1 200 OK
1248     //  Accept-Ranges: bytes
1249     //  Content-Length: 'total file size'
1250
1251     _snprintf(
1252         buffer,
1253         BUFFER_SIZE,
1254         "HEAD %s HTTP/1.1\r\nHost: %s\r\nAccept: */*\r\nUser-Agent: HttpDisk/1.2\r\nConnection: close\r\n\r\n",
1255         FileName,
1256         HostName
1257         );
1258
1259     nSent = send(kSocket, buffer, strlen(buffer), 0);
1260
1261     if (nSent < 0)
1262     {
1263         DbgPrint("HttpDisk: send() error: %#x\n", nSent);
1264         ExFreePool(buffer);
1265         close(kSocket);
1266         IoStatus->Status = nSent;
1267         return IoStatus->Status;
1268     }
1269
1270     nRecv = recv(kSocket, buffer, BUFFER_SIZE, 0);
1271
1272     if (nRecv < 0)
1273     {
1274         DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);
1275         ExFreePool(buffer);
1276         close(kSocket);
1277         IoStatus->Status = nRecv;
1278         return IoStatus->Status;
1279     }
1280
1281     close(kSocket);
1282
1283     buffer[BUFFER_SIZE - 1] = '\0';
1284
1285     if (_strnicmp(buffer, "HTTP/1.1 200 OK", 15))
1286     {
1287         DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
1288         ExFreePool(buffer);
1289         IoStatus->Status = STATUS_NO_SUCH_FILE;
1290         return IoStatus->Status;
1291     }
1292
1293     pStr = strstr(buffer, "Content-Length:");
1294
1295     if (pStr == NULL || pStr + 16 >= buffer + BUFFER_SIZE)
1296     {
1297         DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
1298         ExFreePool(buffer);
1299         IoStatus->Status = STATUS_NO_SUCH_FILE;
1300         return IoStatus->Status;
1301     }
1302
1303     HttpHeader->ContentLength.QuadPart = _atoi64(pStr + 16);
1304
1305     if (HttpHeader->ContentLength.QuadPart == 0)
1306     {
1307         DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
1308         ExFreePool(buffer);
1309         IoStatus->Status = STATUS_NO_SUCH_FILE;
1310         return IoStatus->Status;
1311     }
1312
1313     ExFreePool(buffer);
1314
1315     IoStatus->Status = STATUS_SUCCESS;
1316     IoStatus->Information = 0;
1317
1318     return STATUS_SUCCESS;
1319 }
1320
1321 NTSTATUS
1322 HttpDiskGetBlock (
1323     IN int                  *Socket,
1324     IN ULONG                Address,
1325     IN USHORT               Port,
1326     IN PUCHAR               HostName,
1327     IN PUCHAR               FileName,
1328     IN PLARGE_INTEGER       Offset,
1329     IN ULONG                Length,
1330     OUT PIO_STATUS_BLOCK    IoStatus,
1331     OUT PVOID               SystemBuffer
1332     )
1333 {
1334     struct sockaddr_in  toAddr;
1335     int                 status, nSent, nRecv;
1336     unsigned int        dataLen;
1337     char                *buffer, *pData;
1338
1339     ASSERT(Socket != NULL);
1340     ASSERT(HostName != NULL);
1341     ASSERT(FileName != NULL);
1342     ASSERT(Offset != NULL);
1343     ASSERT(IoStatus != NULL);
1344     ASSERT(SystemBuffer != NULL);
1345
1346     IoStatus->Information = 0;
1347
1348     buffer = HttpDiskPalloc(BUFFER_SIZE + 1);
1349
1350     if (buffer == NULL)
1351     {
1352         IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
1353         return IoStatus->Status;
1354     }
1355
1356     // Example request:
1357     //  GET 'FileName' HTTP/1.1
1358     //  Host: 'HostName'
1359     //  Range: bytes='Offset'-'Offset + Length - 1'
1360     //  Accept: */*
1361     //  User-Agent: HttpDisk/1.2
1362     //
1363     // Interesting lines in answer:
1364     //  HTTP/1.1 206 Partial content
1365     //  Content-Length: 'requested size'
1366     //  Content-Range: bytes 'start'-'end'/'total file size'
1367     //  Data follows after '\r\n\r\n'
1368
1369     _snprintf(
1370         buffer,
1371         BUFFER_SIZE,
1372         "GET %s HTTP/1.1\r\nHost: %s\r\nRange: bytes=%I64u-%I64u\r\nAccept: */*\r\nUser-Agent: HttpDisk/1.2\r\n\r\n",
1373         FileName,
1374         HostName,
1375         Offset->QuadPart,
1376         Offset->QuadPart + Length - 1
1377         );
1378
1379     if (*Socket < 0)
1380     {
1381         *Socket = socket(AF_INET, SOCK_STREAM, 0);
1382
1383         if (*Socket < 0)
1384         {
1385             ExFreePool(buffer);
1386             *Socket = -1;
1387             IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
1388             return IoStatus->Status;
1389         }
1390
1391         toAddr.sin_family = AF_INET;
1392         toAddr.sin_port = Port;
1393         toAddr.sin_addr.s_addr = Address;
1394
1395         status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));
1396
1397         if (status < 0)
1398         {
1399             DbgPrint("HttpDisk: connect() error: %#x\n", status);
1400             ExFreePool(buffer);
1401             close(*Socket);
1402             *Socket = -1;
1403             IoStatus->Status = status;
1404             return IoStatus->Status;
1405         }
1406     }
1407
1408     nSent = send(*Socket, buffer, strlen(buffer), 0);
1409
1410     if (nSent < 0)
1411     {
1412         KdPrint(("HttpDisk: send() error: %#x\n", nSent));
1413
1414         close(*Socket);
1415
1416         *Socket = socket(AF_INET, SOCK_STREAM, 0);
1417
1418         if (*Socket < 0)
1419         {
1420             ExFreePool(buffer);
1421             *Socket = -1;
1422             IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
1423             return IoStatus->Status;
1424         }
1425
1426         toAddr.sin_family = AF_INET;
1427         toAddr.sin_port = Port;
1428         toAddr.sin_addr.s_addr = Address;
1429
1430         status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));
1431
1432         if (status < 0)
1433         {
1434             DbgPrint("HttpDisk: connect() error: %#x\n", status);
1435             ExFreePool(buffer);
1436             close(*Socket);
1437             *Socket = -1;
1438             IoStatus->Status = status;
1439             return IoStatus->Status;
1440         }
1441
1442         nSent = send(*Socket, buffer, strlen(buffer), 0);
1443
1444         if (nSent < 0)
1445         {
1446             DbgPrint("HttpDisk: send() error: %#x\n", nSent);
1447             ExFreePool(buffer);
1448             close(*Socket);
1449             *Socket = -1;
1450             IoStatus->Status = nSent;
1451             return IoStatus->Status;
1452         }
1453     }
1454
1455     nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);
1456
1457     if (nRecv < 0)
1458     {
1459         KdPrint(("HttpDisk: recv() error: %#x\n", nRecv));
1460
1461         close(*Socket);
1462
1463         *Socket = socket(AF_INET, SOCK_STREAM, 0);
1464
1465         if (*Socket < 0)
1466         {
1467             ExFreePool(buffer);
1468             *Socket = -1;
1469             IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
1470             return IoStatus->Status;
1471         }
1472
1473         toAddr.sin_family = AF_INET;
1474         toAddr.sin_port = Port;
1475         toAddr.sin_addr.s_addr = Address;
1476
1477         status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));
1478
1479         if (status < 0)
1480         {
1481             DbgPrint("HttpDisk: connect() error: %#x\n", status);
1482             ExFreePool(buffer);
1483             close(*Socket);
1484             *Socket = -1;
1485             IoStatus->Status = status;
1486             return IoStatus->Status;
1487         }
1488
1489         nSent = send(*Socket, buffer, strlen(buffer), 0);
1490
1491         if (nSent < 0)
1492         {
1493             DbgPrint("HttpDisk: send() error: %#x\n", nSent);
1494             ExFreePool(buffer);
1495             close(*Socket);
1496             *Socket = -1;
1497             IoStatus->Status = nSent;
1498             return IoStatus->Status;
1499         }
1500
1501         nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);
1502
1503         if (nRecv < 0)
1504         {
1505             DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);
1506             ExFreePool(buffer);
1507             close(*Socket);
1508             *Socket = -1;
1509             IoStatus->Status = nRecv;
1510             return IoStatus->Status;
1511         }
1512     }
1513
1514     buffer[BUFFER_SIZE] = '\0';
1515
1516     if (_strnicmp(buffer, "HTTP/1.1 206 Partial Content", 28))
1517     {
1518         DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
1519         ExFreePool(buffer);
1520         close(*Socket);
1521         *Socket = -1;
1522         IoStatus->Status = STATUS_UNSUCCESSFUL;
1523         return IoStatus->Status;
1524     }
1525
1526     pData = strstr(buffer, "\r\n\r\n") + 4;
1527
1528     if (pData == NULL || pData < buffer || pData >= buffer + BUFFER_SIZE)
1529     {
1530         DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
1531         ExFreePool(buffer);
1532         close(*Socket);
1533         *Socket = -1;
1534         IoStatus->Status = STATUS_UNSUCCESSFUL;
1535         return IoStatus->Status;
1536     }
1537
1538     dataLen = nRecv - (pData - buffer);
1539
1540     if (dataLen > Length || pData + dataLen > buffer + BUFFER_SIZE)
1541     {
1542         DbgPrint("HttpDisk: Invalid data length %u in HTTP response:\n%s", dataLen, buffer);
1543         ExFreePool(buffer);
1544         close(*Socket);
1545         *Socket = -1;
1546         IoStatus->Status = STATUS_UNSUCCESSFUL;
1547         return IoStatus->Status;
1548     }
1549
1550     if (dataLen > 0)
1551     {
1552         RtlCopyMemory(
1553             SystemBuffer,
1554             pData,
1555             dataLen
1556             );
1557     }
1558
1559     while (dataLen < Length)
1560     {
1561         nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);
1562         if (nRecv < 0)
1563         {
1564             DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);
1565             close(*Socket);
1566             *Socket = -1;
1567             break;
1568         }
1569         if (nRecv < 1 || dataLen + nRecv > Length || nRecv > BUFFER_SIZE)
1570         {
1571             DbgPrint("HttpDisk: Invalid data length %u+%u\n", dataLen, nRecv);
1572             close(*Socket);
1573             *Socket = -1;
1574             break;
1575         }
1576         RtlCopyMemory(
1577             (PVOID)((PUCHAR) SystemBuffer + dataLen),
1578             buffer,
1579             nRecv
1580         );
1581         dataLen += nRecv;
1582     }
1583
1584     if (dataLen != Length)
1585     {
1586         DbgPrint("HttpDisk: received data length: %u, expected data length: %u\n", dataLen, Length);
1587     }
1588
1589     ExFreePool(buffer);
1590     IoStatus->Status = STATUS_SUCCESS;
1591     IoStatus->Information = dataLen;
1592     return IoStatus->Status;
1593 }