[httpdisk] Dos2Unix source files
authorShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Tue, 11 May 2010 03:38:24 +0000 (23:38 -0400)
committerShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Tue, 11 May 2010 03:39:28 +0000 (23:39 -0400)
src/httpdisk/httpdisk.c
src/httpdisk/httpdisk.rc
src/httpdisk/ksocket.c
src/httpdisk/ksocket.h
src/httpdisk/ktdi.c
src/httpdisk/ktdi.h
src/httpdisk_util/httpdisk.c
src/httpdisk_util/httpdisk.rc
src/include/httpdisk.h

index e9d4e7b..9d9c2d8 100644 (file)
-/*\r
-    HTTP Virtual Disk.\r
-    Copyright (C) 2006 Bo Brantén.\r
-    This program is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-    This program is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-    You should have received a copy of the GNU General Public License\r
-    along with this program; if not, write to the Free Software\r
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-#include <ntddk.h>\r
-#include <ntdddisk.h>\r
-#include <ntddcdrm.h>\r
-#include <ntverp.h>\r
-#include "ksocket.h"\r
-\r
-//\r
-// We include some stuff from newer DDK:s here so that one\r
-// version of the driver for all versions of Windows can\r
-// be compiled with the Windows NT 4.0 DDK.\r
-//\r
-#if (VER_PRODUCTBUILD < 2195)\r
-\r
-#define FILE_DEVICE_MASS_STORAGE            0x0000002d\r
-#define IOCTL_STORAGE_CHECK_VERIFY2         CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
-\r
-#endif // (VER_PRODUCTBUILD < 2195)\r
-\r
-#if (VER_PRODUCTBUILD < 2600)\r
-\r
-#define IOCTL_DISK_GET_PARTITION_INFO_EX    CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
-#define IOCTL_DISK_GET_LENGTH_INFO          CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)\r
-\r
-typedef enum _PARTITION_STYLE {\r
-    PARTITION_STYLE_MBR,\r
-    PARTITION_STYLE_GPT\r
-} PARTITION_STYLE;\r
-\r
-typedef unsigned __int64 ULONG64, *PULONG64;\r
-\r
-typedef struct _PARTITION_INFORMATION_MBR {\r
-    UCHAR   PartitionType;\r
-    BOOLEAN BootIndicator;\r
-    BOOLEAN RecognizedPartition;\r
-    ULONG   HiddenSectors;\r
-} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR;\r
-\r
-typedef struct _PARTITION_INFORMATION_GPT {\r
-    GUID    PartitionType;\r
-    GUID    PartitionId;\r
-    ULONG64 Attributes;\r
-    WCHAR   Name[36];\r
-} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT;\r
-\r
-typedef struct _PARTITION_INFORMATION_EX {\r
-    PARTITION_STYLE PartitionStyle;\r
-    LARGE_INTEGER   StartingOffset;\r
-    LARGE_INTEGER   PartitionLength;\r
-    ULONG           PartitionNumber;\r
-    BOOLEAN         RewritePartition;\r
-    union {\r
-        PARTITION_INFORMATION_MBR Mbr;\r
-        PARTITION_INFORMATION_GPT Gpt;\r
-    };\r
-} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX;\r
-\r
-typedef struct _GET_LENGTH_INFORMATION {\r
-    LARGE_INTEGER Length;\r
-} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;\r
-\r
-#endif // (VER_PRODUCTBUILD < 2600)\r
-\r
-//\r
-// For backward compatibility with Windows NT 4.0 by Bruce Engle.\r
-//\r
-#ifndef MmGetSystemAddressForMdlSafe\r
-#define MmGetSystemAddressForMdlSafe(MDL, PRIORITY) MmGetSystemAddressForMdlPrettySafe(MDL)\r
-\r
-PVOID\r
-MmGetSystemAddressForMdlPrettySafe (\r
-    PMDL Mdl\r
-    )\r
-{\r
-    CSHORT  MdlMappingCanFail;\r
-    PVOID   MappedSystemVa;\r
-\r
-    MdlMappingCanFail = Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL;\r
-\r
-    Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;\r
-\r
-    MappedSystemVa = MmGetSystemAddressForMdl(Mdl);\r
-\r
-    if (MdlMappingCanFail == 0)\r
-    {\r
-        Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL;\r
-    }\r
-\r
-    return MappedSystemVa;\r
-}\r
-#endif\r
-\r
-#include "httpdisk.h"\r
-\r
-#define PARAMETER_KEY           L"\\Parameters"\r
-\r
-#define NUMBEROFDEVICES_VALUE   L"NumberOfDevices"\r
-\r
-#define DEFAULT_NUMBEROFDEVICES 4\r
-\r
-#define SECTOR_SIZE             512\r
-\r
-#define TOC_DATA_TRACK          0x04\r
-\r
-#define BUFFER_SIZE             (4096 * 4)\r
-\r
-HANDLE dir_handle;\r
-\r
-typedef struct _HTTP_HEADER {\r
-    LARGE_INTEGER ContentLength;\r
-} HTTP_HEADER, *PHTTP_HEADER;\r
-\r
-typedef struct _DEVICE_EXTENSION {\r
-    BOOLEAN         media_in_device;\r
-    ULONG           address;\r
-    USHORT          port;\r
-    PUCHAR          host_name;\r
-    PUCHAR          file_name;\r
-    LARGE_INTEGER   file_size;\r
-    int             socket;\r
-    LIST_ENTRY      list_head;\r
-    KSPIN_LOCK      list_lock;\r
-    KEVENT          request_event;\r
-    PVOID           thread_pointer;\r
-    BOOLEAN         terminate_thread;\r
-} DEVICE_EXTENSION, *PDEVICE_EXTENSION;\r
-\r
-NTSTATUS\r
-DriverEntry (\r
-    IN PDRIVER_OBJECT   DriverObject,\r
-    IN PUNICODE_STRING  RegistryPath\r
-);\r
-\r
-NTSTATUS\r
-HttpDiskCreateDevice (\r
-    IN PDRIVER_OBJECT   DriverObject,\r
-    IN ULONG            Number,\r
-    IN DEVICE_TYPE      DeviceType\r
-);\r
-\r
-VOID\r
-HttpDiskUnload (\r
-    IN PDRIVER_OBJECT   DriverObject\r
-);\r
-\r
-PDEVICE_OBJECT\r
-HttpDiskDeleteDevice (\r
-    IN PDEVICE_OBJECT   DeviceObject\r
-);\r
-\r
-NTSTATUS\r
-HttpDiskCreateClose (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-);\r
-\r
-NTSTATUS\r
-HttpDiskReadWrite (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-);\r
-\r
-NTSTATUS\r
-HttpDiskDeviceControl (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-);\r
-\r
-VOID\r
-HttpDiskThread (\r
-    IN PVOID            Context\r
-);\r
-\r
-NTSTATUS\r
-HttpDiskConnect (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-);\r
-\r
-NTSTATUS\r
-HttpDiskDisconnect (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-);\r
-\r
-NTSTATUS\r
-HttpDiskGetHeader (\r
-    IN ULONG                Address,\r
-    IN USHORT               Port,\r
-    IN PUCHAR               HostName,\r
-    IN PUCHAR               FileName,\r
-    OUT PIO_STATUS_BLOCK    IoStatus,\r
-    OUT PHTTP_HEADER        HttpHeader\r
-);\r
-\r
-NTSTATUS\r
-HttpDiskGetBlock (\r
-    IN int                  *Socket,\r
-    IN ULONG                Address,\r
-    IN USHORT               Port,\r
-    IN PUCHAR               HostName,\r
-    IN PUCHAR               FileName,\r
-    IN PLARGE_INTEGER       Offset,\r
-    IN ULONG                Length,\r
-    OUT PIO_STATUS_BLOCK    IoStatus,\r
-    OUT PVOID               SystemBuffer\r
-);\r
-\r
-__int64 __cdecl _atoi64(const char *);\r
-int __cdecl _snprintf(char *, size_t, const char *, ...);\r
-int __cdecl swprintf(wchar_t *, const wchar_t *, ...);\r
-\r
-#pragma code_seg("INIT")\r
-\r
-NTSTATUS\r
-DriverEntry (\r
-    IN PDRIVER_OBJECT   DriverObject,\r
-    IN PUNICODE_STRING  RegistryPath\r
-    )\r
-{\r
-    UNICODE_STRING              parameter_path;\r
-    RTL_QUERY_REGISTRY_TABLE    query_table[2];\r
-    ULONG                       n_devices;\r
-    NTSTATUS                    status;\r
-    UNICODE_STRING              device_dir_name;\r
-    OBJECT_ATTRIBUTES           object_attributes;\r
-    ULONG                       n;\r
-    USHORT                      n_created_devices;\r
-\r
-    parameter_path.Length = 0;\r
-\r
-    parameter_path.MaximumLength = RegistryPath->Length + sizeof(PARAMETER_KEY);\r
-\r
-    parameter_path.Buffer = (PWSTR) ExAllocatePool(PagedPool, parameter_path.MaximumLength);\r
-\r
-    if (parameter_path.Buffer == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    RtlCopyUnicodeString(&parameter_path, RegistryPath);\r
-\r
-    RtlAppendUnicodeToString(&parameter_path, PARAMETER_KEY);\r
-\r
-    RtlZeroMemory(&query_table[0], sizeof(query_table));\r
-\r
-    query_table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;\r
-    query_table[0].Name = NUMBEROFDEVICES_VALUE;\r
-    query_table[0].EntryContext = &n_devices;\r
-\r
-    status = RtlQueryRegistryValues(\r
-        RTL_REGISTRY_ABSOLUTE,\r
-        parameter_path.Buffer,\r
-        &query_table[0],\r
-        NULL,\r
-        NULL\r
-        );\r
-\r
-    ExFreePool(parameter_path.Buffer);\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        DbgPrint("HttpDisk: Query registry failed, using default values.\n");\r
-        n_devices = DEFAULT_NUMBEROFDEVICES;\r
-    }\r
-\r
-    RtlInitUnicodeString(&device_dir_name, DEVICE_DIR_NAME);\r
-\r
-    InitializeObjectAttributes(\r
-        &object_attributes,\r
-        &device_dir_name,\r
-        OBJ_PERMANENT,\r
-        NULL,\r
-        NULL\r
-        );\r
-\r
-    status = ZwCreateDirectoryObject(\r
-        &dir_handle,\r
-        DIRECTORY_ALL_ACCESS,\r
-        &object_attributes\r
-        );\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        return status;\r
-    }\r
-\r
-    ZwMakeTemporaryObject(dir_handle);\r
-\r
-    for (n = 0, n_created_devices = 0; n < n_devices; n++)\r
-    {\r
-        status = HttpDiskCreateDevice(DriverObject, n, FILE_DEVICE_DISK);\r
-\r
-        if (NT_SUCCESS(status))\r
-        {\r
-            n_created_devices++;\r
-        }\r
-    }\r
-\r
-    for (n = 0; n < n_devices; n++)\r
-    {\r
-        status = HttpDiskCreateDevice(DriverObject, n, FILE_DEVICE_CD_ROM);\r
-\r
-        if (NT_SUCCESS(status))\r
-        {\r
-            n_created_devices++;\r
-        }\r
-    }\r
-\r
-    if (n_created_devices == 0)\r
-    {\r
-        ZwClose(dir_handle);\r
-        return status;\r
-    }\r
-\r
-    DriverObject->MajorFunction[IRP_MJ_CREATE]         = HttpDiskCreateClose;\r
-    DriverObject->MajorFunction[IRP_MJ_CLOSE]          = HttpDiskCreateClose;\r
-    DriverObject->MajorFunction[IRP_MJ_READ]           = HttpDiskReadWrite;\r
-    DriverObject->MajorFunction[IRP_MJ_WRITE]          = HttpDiskReadWrite;\r
-    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HttpDiskDeviceControl;\r
-\r
-    DriverObject->DriverUnload = HttpDiskUnload;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS\r
-HttpDiskCreateDevice (\r
-    IN PDRIVER_OBJECT   DriverObject,\r
-    IN ULONG            Number,\r
-    IN DEVICE_TYPE      DeviceType\r
-    )\r
-{\r
-    WCHAR               device_name_buffer[MAXIMUM_FILENAME_LENGTH];\r
-    UNICODE_STRING      device_name;\r
-    NTSTATUS            status;\r
-    PDEVICE_OBJECT      device_object;\r
-    PDEVICE_EXTENSION   device_extension;\r
-    HANDLE              thread_handle;\r
-\r
-    ASSERT(DriverObject != NULL);\r
-\r
-    if (DeviceType == FILE_DEVICE_CD_ROM)\r
-    {\r
-        swprintf(\r
-            device_name_buffer,\r
-            DEVICE_NAME_PREFIX L"Cd" L"%u",\r
-            Number\r
-            );\r
-    }\r
-    else\r
-    {\r
-        swprintf(\r
-            device_name_buffer,\r
-            DEVICE_NAME_PREFIX L"Disk" L"%u",\r
-            Number\r
-            );\r
-    }\r
-\r
-    RtlInitUnicodeString(&device_name, device_name_buffer);\r
-\r
-    status = IoCreateDevice(\r
-        DriverObject,\r
-        sizeof(DEVICE_EXTENSION),\r
-        &device_name,\r
-        DeviceType,\r
-        0,\r
-        FALSE,\r
-        &device_object\r
-        );\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        return status;\r
-    }\r
-\r
-    device_object->Flags |= DO_DIRECT_IO;\r
-\r
-    device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;\r
-\r
-    device_extension->media_in_device = FALSE;\r
-\r
-    device_extension->host_name = NULL;\r
-\r
-    device_extension->file_name = NULL;\r
-\r
-    device_extension->socket = -1;\r
-\r
-    device_object->Characteristics |= FILE_READ_ONLY_DEVICE;\r
-\r
-    InitializeListHead(&device_extension->list_head);\r
-\r
-    KeInitializeSpinLock(&device_extension->list_lock);\r
-\r
-    KeInitializeEvent(\r
-        &device_extension->request_event,\r
-        SynchronizationEvent,\r
-        FALSE\r
-        );\r
-\r
-    device_extension->terminate_thread = FALSE;\r
-\r
-    status = PsCreateSystemThread(\r
-        &thread_handle,\r
-        (ACCESS_MASK) 0L,\r
-        NULL,\r
-        NULL,\r
-        NULL,\r
-        HttpDiskThread,\r
-        device_object\r
-        );\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        IoDeleteDevice(device_object);\r
-        return status;\r
-    }\r
-\r
-    status = ObReferenceObjectByHandle(\r
-        thread_handle,\r
-        THREAD_ALL_ACCESS,\r
-        NULL,\r
-        KernelMode,\r
-        &device_extension->thread_pointer,\r
-        NULL\r
-        );\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        ZwClose(thread_handle);\r
-\r
-        device_extension->terminate_thread = TRUE;\r
-\r
-        KeSetEvent(\r
-            &device_extension->request_event,\r
-            (KPRIORITY) 0,\r
-            FALSE\r
-            );\r
-\r
-        IoDeleteDevice(device_object);\r
-\r
-        return status;\r
-    }\r
-\r
-    ZwClose(thread_handle);\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-#pragma code_seg("PAGE")\r
-\r
-VOID\r
-HttpDiskUnload (\r
-    IN PDRIVER_OBJECT DriverObject\r
-    )\r
-{\r
-    PDEVICE_OBJECT device_object;\r
-\r
-    device_object = DriverObject->DeviceObject;\r
-\r
-    while (device_object)\r
-    {\r
-        device_object = HttpDiskDeleteDevice(device_object);\r
-    }\r
-\r
-    ZwClose(dir_handle);\r
-}\r
-\r
-PDEVICE_OBJECT\r
-HttpDiskDeleteDevice (\r
-    IN PDEVICE_OBJECT DeviceObject\r
-    )\r
-{\r
-    PDEVICE_EXTENSION   device_extension;\r
-    PDEVICE_OBJECT      next_device_object;\r
-\r
-    ASSERT(DeviceObject != NULL);\r
-\r
-    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;\r
-\r
-    device_extension->terminate_thread = TRUE;\r
-\r
-    KeSetEvent(\r
-        &device_extension->request_event,\r
-        (KPRIORITY) 0,\r
-        FALSE\r
-        );\r
-\r
-    KeWaitForSingleObject(\r
-        device_extension->thread_pointer,\r
-        Executive,\r
-        KernelMode,\r
-        FALSE,\r
-        NULL\r
-        );\r
-\r
-    ObDereferenceObject(device_extension->thread_pointer);\r
-\r
-    next_device_object = DeviceObject->NextDevice;\r
-\r
-    IoDeleteDevice(DeviceObject);\r
-\r
-    return next_device_object;\r
-}\r
-\r
-NTSTATUS\r
-HttpDiskCreateClose (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-    )\r
-{\r
-    Irp->IoStatus.Status = STATUS_SUCCESS;\r
-    Irp->IoStatus.Information = FILE_OPENED;\r
-\r
-    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-#pragma code_seg()\r
-\r
-NTSTATUS\r
-HttpDiskReadWrite (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-    )\r
-{\r
-    PDEVICE_EXTENSION   device_extension;\r
-    PIO_STACK_LOCATION  io_stack;\r
-\r
-    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;\r
-\r
-    if (!device_extension->media_in_device)\r
-    {\r
-        Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;\r
-        Irp->IoStatus.Information = 0;\r
-\r
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-\r
-        return STATUS_NO_MEDIA_IN_DEVICE;\r
-    }\r
-\r
-    io_stack = IoGetCurrentIrpStackLocation(Irp);\r
-\r
-    if (io_stack->Parameters.Read.Length == 0)\r
-    {\r
-        Irp->IoStatus.Status = STATUS_SUCCESS;\r
-        Irp->IoStatus.Information = 0;\r
-\r
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-\r
-        return STATUS_SUCCESS;\r
-    }\r
-\r
-    IoMarkIrpPending(Irp);\r
-\r
-    ExInterlockedInsertTailList(\r
-        &device_extension->list_head,\r
-        &Irp->Tail.Overlay.ListEntry,\r
-        &device_extension->list_lock\r
-        );\r
-\r
-    KeSetEvent(\r
-        &device_extension->request_event,\r
-        (KPRIORITY) 0,\r
-        FALSE\r
-        );\r
-\r
-    return STATUS_PENDING;\r
-}\r
-\r
-NTSTATUS\r
-HttpDiskDeviceControl (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-    )\r
-{\r
-    PDEVICE_EXTENSION   device_extension;\r
-    PIO_STACK_LOCATION  io_stack;\r
-    NTSTATUS            status;\r
-\r
-    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;\r
-\r
-    io_stack = IoGetCurrentIrpStackLocation(Irp);\r
-\r
-    if (!device_extension->media_in_device &&\r
-        io_stack->Parameters.DeviceIoControl.IoControlCode !=\r
-        IOCTL_HTTP_DISK_CONNECT)\r
-    {\r
-        Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;\r
-        Irp->IoStatus.Information = 0;\r
-\r
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-\r
-        return STATUS_NO_MEDIA_IN_DEVICE;\r
-    }\r
-\r
-    switch (io_stack->Parameters.DeviceIoControl.IoControlCode)\r
-    {\r
-    case IOCTL_HTTP_DISK_CONNECT:\r
-        {\r
-            if (device_extension->media_in_device)\r
-            {\r
-                DbgPrint("HttpDisk: IOCTL_HTTP_DISK_CONNECT: Media already opened.\n");\r
-\r
-                status = STATUS_INVALID_DEVICE_REQUEST;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            if (io_stack->Parameters.DeviceIoControl.InputBufferLength <\r
-                sizeof(HTTP_DISK_INFORMATION))\r
-            {\r
-                status = STATUS_INVALID_PARAMETER;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            if (io_stack->Parameters.DeviceIoControl.InputBufferLength <\r
-                sizeof(HTTP_DISK_INFORMATION) +\r
-                ((PHTTP_DISK_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->FileNameLength -\r
-                sizeof(UCHAR))\r
-            {\r
-                status = STATUS_INVALID_PARAMETER;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            IoMarkIrpPending(Irp);\r
-\r
-            ExInterlockedInsertTailList(\r
-                &device_extension->list_head,\r
-                &Irp->Tail.Overlay.ListEntry,\r
-                &device_extension->list_lock\r
-                );\r
-\r
-            KeSetEvent(\r
-                &device_extension->request_event,\r
-                (KPRIORITY) 0,\r
-                FALSE\r
-                );\r
-\r
-            status = STATUS_PENDING;\r
-\r
-            break;\r
-        }\r
-\r
-    case IOCTL_HTTP_DISK_DISCONNECT:\r
-        {\r
-            IoMarkIrpPending(Irp);\r
-\r
-            ExInterlockedInsertTailList(\r
-                &device_extension->list_head,\r
-                &Irp->Tail.Overlay.ListEntry,\r
-                &device_extension->list_lock\r
-                );\r
-\r
-            KeSetEvent(\r
-                &device_extension->request_event,\r
-                (KPRIORITY) 0,\r
-                FALSE\r
-                );\r
-\r
-            status = STATUS_PENDING;\r
-\r
-            break;\r
-        }\r
-\r
-    case IOCTL_DISK_CHECK_VERIFY:\r
-    case IOCTL_CDROM_CHECK_VERIFY:\r
-    case IOCTL_STORAGE_CHECK_VERIFY:\r
-    case IOCTL_STORAGE_CHECK_VERIFY2:\r
-        {\r
-            status = STATUS_SUCCESS;\r
-            Irp->IoStatus.Information = 0;\r
-            break;\r
-        }\r
-\r
-    case IOCTL_DISK_GET_DRIVE_GEOMETRY:\r
-    case IOCTL_CDROM_GET_DRIVE_GEOMETRY:\r
-        {\r
-            PDISK_GEOMETRY  disk_geometry;\r
-            ULONGLONG       length;\r
-\r
-            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <\r
-                sizeof(DISK_GEOMETRY))\r
-            {\r
-                status = STATUS_BUFFER_TOO_SMALL;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            disk_geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;\r
-\r
-            length = device_extension->file_size.QuadPart;\r
-\r
-            disk_geometry->Cylinders.QuadPart = length / SECTOR_SIZE / 32 / 2;\r
-            disk_geometry->MediaType = FixedMedia;\r
-            disk_geometry->TracksPerCylinder = 2;\r
-            disk_geometry->SectorsPerTrack = 32;\r
-            disk_geometry->BytesPerSector = SECTOR_SIZE;\r
-\r
-            status = STATUS_SUCCESS;\r
-            Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);\r
-\r
-            break;\r
-        }\r
-\r
-    case IOCTL_DISK_GET_LENGTH_INFO:\r
-        {\r
-            PGET_LENGTH_INFORMATION get_length_information;\r
-\r
-            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <\r
-                sizeof(GET_LENGTH_INFORMATION))\r
-            {\r
-                status = STATUS_BUFFER_TOO_SMALL;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            get_length_information = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;\r
-\r
-            get_length_information->Length.QuadPart = device_extension->file_size.QuadPart;\r
-\r
-            status = STATUS_SUCCESS;\r
-            Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);\r
-\r
-        break;\r
-        }\r
-\r
-    case IOCTL_DISK_GET_PARTITION_INFO:\r
-        {\r
-            PPARTITION_INFORMATION  partition_information;\r
-            ULONGLONG               length;\r
-\r
-            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <\r
-                sizeof(PARTITION_INFORMATION))\r
-            {\r
-                status = STATUS_BUFFER_TOO_SMALL;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            partition_information = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;\r
-\r
-            length = device_extension->file_size.QuadPart;\r
-\r
-            partition_information->StartingOffset.QuadPart = 0;\r
-            partition_information->PartitionLength.QuadPart = length;\r
-            partition_information->HiddenSectors = 1;\r
-            partition_information->PartitionNumber = 0;\r
-            partition_information->PartitionType = 0;\r
-            partition_information->BootIndicator = FALSE;\r
-            partition_information->RecognizedPartition = FALSE;\r
-            partition_information->RewritePartition = FALSE;\r
-\r
-            status = STATUS_SUCCESS;\r
-            Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);\r
-\r
-            break;\r
-        }\r
-\r
-    case IOCTL_DISK_GET_PARTITION_INFO_EX:\r
-        {\r
-            PPARTITION_INFORMATION_EX   partition_information_ex;\r
-            ULONGLONG                   length;\r
-\r
-            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <\r
-                sizeof(PARTITION_INFORMATION_EX))\r
-            {\r
-                status = STATUS_BUFFER_TOO_SMALL;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            partition_information_ex = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;\r
-\r
-            length = device_extension->file_size.QuadPart;\r
-\r
-            partition_information_ex->PartitionStyle = PARTITION_STYLE_MBR;\r
-            partition_information_ex->StartingOffset.QuadPart = 0;\r
-            partition_information_ex->PartitionLength.QuadPart = length;\r
-            partition_information_ex->PartitionNumber = 0;\r
-            partition_information_ex->RewritePartition = FALSE;\r
-            partition_information_ex->Mbr.PartitionType = 0;\r
-            partition_information_ex->Mbr.BootIndicator = FALSE;\r
-            partition_information_ex->Mbr.RecognizedPartition = FALSE;\r
-            partition_information_ex->Mbr.HiddenSectors = 1;\r
-\r
-            status = STATUS_SUCCESS;\r
-            Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);\r
-\r
-            break;\r
-        }\r
-\r
-    case IOCTL_DISK_IS_WRITABLE:\r
-        {\r
-            status = STATUS_MEDIA_WRITE_PROTECTED;\r
-            Irp->IoStatus.Information = 0;\r
-            break;\r
-        }\r
-\r
-    case IOCTL_DISK_MEDIA_REMOVAL:\r
-    case IOCTL_STORAGE_MEDIA_REMOVAL:\r
-        {\r
-            status = STATUS_SUCCESS;\r
-            Irp->IoStatus.Information = 0;\r
-            break;\r
-        }\r
-\r
-    case IOCTL_CDROM_READ_TOC:\r
-        {\r
-            PCDROM_TOC cdrom_toc;\r
-\r
-            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <\r
-                sizeof(CDROM_TOC))\r
-            {\r
-                status = STATUS_BUFFER_TOO_SMALL;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            cdrom_toc = (PCDROM_TOC) Irp->AssociatedIrp.SystemBuffer;\r
-\r
-            RtlZeroMemory(cdrom_toc, sizeof(CDROM_TOC));\r
-\r
-            cdrom_toc->FirstTrack = 1;\r
-            cdrom_toc->LastTrack = 1;\r
-            cdrom_toc->TrackData[0].Control = TOC_DATA_TRACK;\r
-\r
-            status = STATUS_SUCCESS;\r
-            Irp->IoStatus.Information = sizeof(CDROM_TOC);\r
-\r
-            break;\r
-        }\r
-\r
-    case IOCTL_DISK_SET_PARTITION_INFO:\r
-        {\r
-            status = STATUS_MEDIA_WRITE_PROTECTED;\r
-            Irp->IoStatus.Information = 0;\r
-            break;\r
-        }\r
-\r
-    case IOCTL_DISK_VERIFY:\r
-        {\r
-            PVERIFY_INFORMATION verify_information;\r
-\r
-            if (io_stack->Parameters.DeviceIoControl.InputBufferLength <\r
-                sizeof(VERIFY_INFORMATION))\r
-            {\r
-                status = STATUS_INVALID_PARAMETER;\r
-                Irp->IoStatus.Information = 0;\r
-                break;\r
-            }\r
-\r
-            verify_information = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;\r
-\r
-            status = STATUS_SUCCESS;\r
-            Irp->IoStatus.Information = verify_information->Length;\r
-\r
-            break;\r
-        }\r
-\r
-    default:\r
-        {\r
-            KdPrint((\r
-                "HttpDisk: Unknown IoControlCode: %#x\n",\r
-                io_stack->Parameters.DeviceIoControl.IoControlCode\r
-                ));\r
-\r
-            status = STATUS_INVALID_DEVICE_REQUEST;\r
-            Irp->IoStatus.Information = 0;\r
-        }\r
-    }\r
-\r
-    if (status != STATUS_PENDING)\r
-    {\r
-        Irp->IoStatus.Status = status;\r
-\r
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
-    }\r
-\r
-    return status;\r
-}\r
-\r
-#pragma code_seg("PAGE")\r
-\r
-VOID\r
-HttpDiskThread (\r
-    IN PVOID Context\r
-    )\r
-{\r
-    PDEVICE_OBJECT      device_object;\r
-    PDEVICE_EXTENSION   device_extension;\r
-    PLIST_ENTRY         request;\r
-    PIRP                irp;\r
-    PIO_STACK_LOCATION  io_stack;\r
-\r
-    ASSERT(Context != NULL);\r
-\r
-    device_object = (PDEVICE_OBJECT) Context;\r
-\r
-    device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;\r
-\r
-    KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);\r
-\r
-    for (;;)\r
-    {\r
-        KeWaitForSingleObject(\r
-            &device_extension->request_event,\r
-            Executive,\r
-            KernelMode,\r
-            FALSE,\r
-            NULL\r
-            );\r
-\r
-        if (device_extension->terminate_thread)\r
-        {\r
-            PsTerminateSystemThread(STATUS_SUCCESS);\r
-        }\r
-\r
-        while (request = ExInterlockedRemoveHeadList(\r
-            &device_extension->list_head,\r
-            &device_extension->list_lock\r
-            ))\r
-        {\r
-            irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);\r
-\r
-            io_stack = IoGetCurrentIrpStackLocation(irp);\r
-\r
-            switch (io_stack->MajorFunction)\r
-            {\r
-            case IRP_MJ_READ:\r
-                HttpDiskGetBlock(\r
-                    &device_extension->socket,\r
-                    device_extension->address,\r
-                    device_extension->port,\r
-                    device_extension->host_name,\r
-                    device_extension->file_name,\r
-                    &io_stack->Parameters.Read.ByteOffset,\r
-                    io_stack->Parameters.Read.Length,\r
-                    &irp->IoStatus,\r
-                    MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority)\r
-                    );\r
-                if (!NT_SUCCESS(irp->IoStatus.Status))\r
-                {\r
-                    HttpDiskGetBlock(\r
-                        &device_extension->socket,\r
-                        device_extension->address,\r
-                        device_extension->port,\r
-                        device_extension->host_name,\r
-                        device_extension->file_name,\r
-                        &io_stack->Parameters.Read.ByteOffset,\r
-                        io_stack->Parameters.Read.Length,\r
-                        &irp->IoStatus,\r
-                        MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority)\r
-                        );\r
-                }\r
-                break;\r
-\r
-            case IRP_MJ_WRITE:\r
-                irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;\r
-                irp->IoStatus.Information = 0;\r
-                break;\r
-\r
-            case IRP_MJ_DEVICE_CONTROL:\r
-                switch (io_stack->Parameters.DeviceIoControl.IoControlCode)\r
-                {\r
-                case IOCTL_HTTP_DISK_CONNECT:\r
-                    irp->IoStatus.Status = HttpDiskConnect(device_object, irp);\r
-                    break;\r
-\r
-                case IOCTL_HTTP_DISK_DISCONNECT:\r
-                    irp->IoStatus.Status = HttpDiskDisconnect(device_object, irp);\r
-                    break;\r
-\r
-                default:\r
-                    irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;\r
-                }\r
-                break;\r
-\r
-            default:\r
-                irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;\r
-            }\r
-\r
-            IoCompleteRequest(\r
-                irp,\r
-                (CCHAR) (NT_SUCCESS(irp->IoStatus.Status) ?\r
-                IO_DISK_INCREMENT : IO_NO_INCREMENT)\r
-                );\r
-        }\r
-    }\r
-}\r
-\r
-NTSTATUS\r
-HttpDiskConnect (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-    )\r
-{\r
-    PDEVICE_EXTENSION       device_extension;\r
-    PHTTP_DISK_INFORMATION  http_disk_information;\r
-    HTTP_HEADER             http_header;\r
-\r
-    ASSERT(DeviceObject != NULL);\r
-    ASSERT(Irp != NULL);\r
-\r
-    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;\r
-\r
-    http_disk_information = (PHTTP_DISK_INFORMATION) Irp->AssociatedIrp.SystemBuffer;\r
-\r
-    device_extension->address = http_disk_information->Address;\r
-\r
-    device_extension->port = http_disk_information->Port;\r
-\r
-    device_extension->host_name = ExAllocatePool(NonPagedPool, http_disk_information->HostNameLength + 1);\r
-\r
-    if (device_extension->host_name == NULL)\r
-    {\r
-        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;\r
-        return Irp->IoStatus.Status;\r
-    }\r
-\r
-    RtlCopyMemory(\r
-        device_extension->host_name,\r
-        http_disk_information->HostName,\r
-        http_disk_information->HostNameLength\r
-        );\r
-\r
-    device_extension->host_name[http_disk_information->HostNameLength] = '\0';\r
-\r
-    device_extension->file_name = ExAllocatePool(NonPagedPool, http_disk_information->FileNameLength + 1);\r
-\r
-    if (device_extension->file_name == NULL)\r
-    {\r
-        if (device_extension->host_name != NULL)\r
-        {\r
-            ExFreePool(device_extension->host_name);\r
-            device_extension->host_name = NULL;\r
-        }\r
-\r
-        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;\r
-        return Irp->IoStatus.Status;\r
-    }\r
-\r
-    RtlCopyMemory(\r
-        device_extension->file_name,\r
-        http_disk_information->FileName,\r
-        http_disk_information->FileNameLength\r
-        );\r
-\r
-    device_extension->file_name[http_disk_information->FileNameLength] = '\0';\r
-\r
-    HttpDiskGetHeader(\r
-        device_extension->address,\r
-        device_extension->port,\r
-        device_extension->host_name,\r
-        device_extension->file_name,\r
-        &Irp->IoStatus,\r
-        &http_header\r
-        );\r
-\r
-    if (!NT_SUCCESS(Irp->IoStatus.Status))\r
-    {\r
-        HttpDiskGetHeader(\r
-            device_extension->address,\r
-            device_extension->port,\r
-            device_extension->host_name,\r
-            device_extension->file_name,\r
-            &Irp->IoStatus,\r
-            &http_header\r
-            );\r
-    }\r
-\r
-    if (!NT_SUCCESS(Irp->IoStatus.Status))\r
-    {\r
-        if (device_extension->host_name != NULL)\r
-        {\r
-            ExFreePool(device_extension->host_name);\r
-            device_extension->host_name = NULL;\r
-        }\r
-\r
-        if (device_extension->file_name != NULL)\r
-        {\r
-            ExFreePool(device_extension->file_name);\r
-            device_extension->file_name = NULL;\r
-        }\r
-\r
-        return Irp->IoStatus.Status;\r
-    }\r
-\r
-    device_extension->file_size.QuadPart = http_header.ContentLength.QuadPart;\r
-\r
-    device_extension->media_in_device = TRUE;\r
-\r
-    return Irp->IoStatus.Status;\r
-}\r
-\r
-NTSTATUS\r
-HttpDiskDisconnect (\r
-    IN PDEVICE_OBJECT   DeviceObject,\r
-    IN PIRP             Irp\r
-    )\r
-{\r
-    PDEVICE_EXTENSION device_extension;\r
-\r
-    ASSERT(DeviceObject != NULL);\r
-    ASSERT(Irp != NULL);\r
-\r
-    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;\r
-\r
-    device_extension->media_in_device = FALSE;\r
-\r
-    if (device_extension->host_name != NULL)\r
-    {\r
-        ExFreePool(device_extension->host_name);\r
-        device_extension->host_name = NULL;\r
-    }\r
-\r
-    if (device_extension->file_name != NULL)\r
-    {\r
-        ExFreePool(device_extension->file_name);\r
-        device_extension->file_name = NULL;\r
-    }\r
-\r
-    if (device_extension->socket > 0)\r
-    {\r
-        close(device_extension->socket);\r
-        device_extension->socket = -1;\r
-    }\r
-\r
-    Irp->IoStatus.Status = STATUS_SUCCESS;\r
-    Irp->IoStatus.Information = 0;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS\r
-HttpDiskGetHeader (\r
-    IN ULONG                Address,\r
-    IN USHORT               Port,\r
-    IN PUCHAR               HostName,\r
-    IN PUCHAR               FileName,\r
-    OUT PIO_STATUS_BLOCK    IoStatus,\r
-    OUT PHTTP_HEADER        HttpHeader\r
-    )\r
-{\r
-    int                 kSocket;\r
-    struct sockaddr_in  toAddr;\r
-    int                 status, nSent, nRecv;\r
-    char                *buffer, *pStr;\r
-\r
-    ASSERT(HostName != NULL);\r
-    ASSERT(FileName != NULL);\r
-    ASSERT(IoStatus != NULL);\r
-    ASSERT(HttpHeader != NULL);\r
-\r
-    buffer = ExAllocatePool(PagedPool, BUFFER_SIZE);\r
-\r
-    if (buffer == NULL)\r
-    {\r
-        IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    kSocket = socket(AF_INET, SOCK_STREAM, 0);\r
-\r
-    if (kSocket < 0)\r
-    {\r
-        DbgPrint("HttpDisk: socket() error: %#x\n", kSocket);\r
-        ExFreePool(buffer);\r
-        IoStatus->Status = kSocket;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    toAddr.sin_family = AF_INET;\r
-    toAddr.sin_port = Port;\r
-    toAddr.sin_addr.s_addr = Address;\r
-\r
-    status = connect(kSocket, (struct sockaddr*) &toAddr, sizeof(toAddr));\r
-\r
-    if (status < 0)\r
-    {\r
-        DbgPrint("HttpDisk: connect() error: %#x\n", status);\r
-        ExFreePool(buffer);\r
-        close(kSocket);\r
-        IoStatus->Status = status;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    // Example request:\r
-    //  HEAD 'FileName' HTTP/1.1\r
-    //  Host: 'HostName'\r
-    //  Accept: */*\r
-    //  User-Agent: HttpDisk/1.2\r
-    //  Connection: close\r
-    //\r
-    // Interesting lines in answer:\r
-    //  HTTP/1.1 200 OK\r
-    //  Accept-Ranges: bytes\r
-    //  Content-Length: 'total file size'\r
-\r
-    _snprintf(\r
-        buffer,\r
-        BUFFER_SIZE,\r
-        "HEAD %s HTTP/1.1\r\nHost: %s\r\nAccept: */*\r\nUser-Agent: HttpDisk/1.2\r\nConnection: close\r\n\r\n",\r
-        FileName,\r
-        HostName\r
-        );\r
-\r
-    nSent = send(kSocket, buffer, strlen(buffer), 0);\r
-\r
-    if (nSent < 0)\r
-    {\r
-        DbgPrint("HttpDisk: send() error: %#x\n", nSent);\r
-        ExFreePool(buffer);\r
-        close(kSocket);\r
-        IoStatus->Status = nSent;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    nRecv = recv(kSocket, buffer, BUFFER_SIZE, 0);\r
-\r
-    if (nRecv < 0)\r
-    {\r
-        DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);\r
-        ExFreePool(buffer);\r
-        close(kSocket);\r
-        IoStatus->Status = nRecv;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    close(kSocket);\r
-\r
-    buffer[BUFFER_SIZE - 1] = '\0';\r
-\r
-    if (_strnicmp(buffer, "HTTP/1.1 200 OK", 15))\r
-    {\r
-        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);\r
-        ExFreePool(buffer);\r
-        IoStatus->Status = STATUS_NO_SUCH_FILE;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    pStr = strstr(buffer, "Content-Length:");\r
-\r
-    if (pStr == NULL || pStr + 16 >= buffer + BUFFER_SIZE)\r
-    {\r
-        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);\r
-        ExFreePool(buffer);\r
-        IoStatus->Status = STATUS_NO_SUCH_FILE;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    HttpHeader->ContentLength.QuadPart = _atoi64(pStr + 16);\r
-\r
-    if (HttpHeader->ContentLength.QuadPart == 0)\r
-    {\r
-        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);\r
-        ExFreePool(buffer);\r
-        IoStatus->Status = STATUS_NO_SUCH_FILE;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    ExFreePool(buffer);\r
-\r
-    IoStatus->Status = STATUS_SUCCESS;\r
-    IoStatus->Information = 0;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS\r
-HttpDiskGetBlock (\r
-    IN int                  *Socket,\r
-    IN ULONG                Address,\r
-    IN USHORT               Port,\r
-    IN PUCHAR               HostName,\r
-    IN PUCHAR               FileName,\r
-    IN PLARGE_INTEGER       Offset,\r
-    IN ULONG                Length,\r
-    OUT PIO_STATUS_BLOCK    IoStatus,\r
-    OUT PVOID               SystemBuffer\r
-    )\r
-{\r
-    struct sockaddr_in  toAddr;\r
-    int                 status, nSent, nRecv;\r
-    unsigned int        dataLen;\r
-    char                *buffer, *pData;\r
-\r
-    ASSERT(Socket != NULL);\r
-    ASSERT(HostName != NULL);\r
-    ASSERT(FileName != NULL);\r
-    ASSERT(Offset != NULL);\r
-    ASSERT(IoStatus != NULL);\r
-    ASSERT(SystemBuffer != NULL);\r
-\r
-    IoStatus->Information = 0;\r
-\r
-    buffer = ExAllocatePool(PagedPool, BUFFER_SIZE + 1);\r
-\r
-    if (buffer == NULL)\r
-    {\r
-        IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    // Example request:\r
-    //  GET 'FileName' HTTP/1.1\r
-    //  Host: 'HostName'\r
-    //  Range: bytes='Offset'-'Offset + Length - 1'\r
-    //  Accept: */*\r
-    //  User-Agent: HttpDisk/1.2\r
-    //\r
-    // Interesting lines in answer:\r
-    //  HTTP/1.1 206 Partial content\r
-    //  Content-Length: 'requested size'\r
-    //  Content-Range: bytes 'start'-'end'/'total file size'\r
-    //  Data follows after '\r\n\r\n'\r
-\r
-    _snprintf(\r
-        buffer,\r
-        BUFFER_SIZE,\r
-        "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",\r
-        FileName,\r
-        HostName,\r
-        Offset->QuadPart,\r
-        Offset->QuadPart + Length - 1\r
-        );\r
-\r
-    if (*Socket < 0)\r
-    {\r
-        *Socket = socket(AF_INET, SOCK_STREAM, 0);\r
-\r
-        if (*Socket < 0)\r
-        {\r
-            ExFreePool(buffer);\r
-            *Socket = -1;\r
-            IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;\r
-            return IoStatus->Status;\r
-        }\r
-\r
-        toAddr.sin_family = AF_INET;\r
-        toAddr.sin_port = Port;\r
-        toAddr.sin_addr.s_addr = Address;\r
-\r
-        status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));\r
-\r
-        if (status < 0)\r
-        {\r
-            DbgPrint("HttpDisk: connect() error: %#x\n", status);\r
-            ExFreePool(buffer);\r
-            close(*Socket);\r
-            *Socket = -1;\r
-            IoStatus->Status = status;\r
-            return IoStatus->Status;\r
-        }\r
-    }\r
-\r
-    nSent = send(*Socket, buffer, strlen(buffer), 0);\r
-\r
-    if (nSent < 0)\r
-    {\r
-        KdPrint(("HttpDisk: send() error: %#x\n", nSent));\r
-\r
-        close(*Socket);\r
-\r
-        *Socket = socket(AF_INET, SOCK_STREAM, 0);\r
-\r
-        if (*Socket < 0)\r
-        {\r
-            ExFreePool(buffer);\r
-            *Socket = -1;\r
-            IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;\r
-            return IoStatus->Status;\r
-        }\r
-\r
-        toAddr.sin_family = AF_INET;\r
-        toAddr.sin_port = Port;\r
-        toAddr.sin_addr.s_addr = Address;\r
-\r
-        status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));\r
-\r
-        if (status < 0)\r
-        {\r
-            DbgPrint("HttpDisk: connect() error: %#x\n", status);\r
-            ExFreePool(buffer);\r
-            close(*Socket);\r
-            *Socket = -1;\r
-            IoStatus->Status = status;\r
-            return IoStatus->Status;\r
-        }\r
-\r
-        nSent = send(*Socket, buffer, strlen(buffer), 0);\r
-\r
-        if (nSent < 0)\r
-        {\r
-            DbgPrint("HttpDisk: send() error: %#x\n", nSent);\r
-            ExFreePool(buffer);\r
-            close(*Socket);\r
-            *Socket = -1;\r
-            IoStatus->Status = nSent;\r
-            return IoStatus->Status;\r
-        }\r
-    }\r
-\r
-    nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);\r
-\r
-    if (nRecv < 0)\r
-    {\r
-        KdPrint(("HttpDisk: recv() error: %#x\n", nRecv));\r
-\r
-        close(*Socket);\r
-\r
-        *Socket = socket(AF_INET, SOCK_STREAM, 0);\r
-\r
-        if (*Socket < 0)\r
-        {\r
-            ExFreePool(buffer);\r
-            *Socket = -1;\r
-            IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;\r
-            return IoStatus->Status;\r
-        }\r
-\r
-        toAddr.sin_family = AF_INET;\r
-        toAddr.sin_port = Port;\r
-        toAddr.sin_addr.s_addr = Address;\r
-\r
-        status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));\r
-\r
-        if (status < 0)\r
-        {\r
-            DbgPrint("HttpDisk: connect() error: %#x\n", status);\r
-            ExFreePool(buffer);\r
-            close(*Socket);\r
-            *Socket = -1;\r
-            IoStatus->Status = status;\r
-            return IoStatus->Status;\r
-        }\r
-\r
-        nSent = send(*Socket, buffer, strlen(buffer), 0);\r
-\r
-        if (nSent < 0)\r
-        {\r
-            DbgPrint("HttpDisk: send() error: %#x\n", nSent);\r
-            ExFreePool(buffer);\r
-            close(*Socket);\r
-            *Socket = -1;\r
-            IoStatus->Status = nSent;\r
-            return IoStatus->Status;\r
-        }\r
-\r
-        nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);\r
-\r
-        if (nRecv < 0)\r
-        {\r
-            DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);\r
-            ExFreePool(buffer);\r
-            close(*Socket);\r
-            *Socket = -1;\r
-            IoStatus->Status = nRecv;\r
-            return IoStatus->Status;\r
-        }\r
-    }\r
-\r
-    buffer[BUFFER_SIZE] = '\0';\r
-\r
-    if (_strnicmp(buffer, "HTTP/1.1 206 Partial Content", 28))\r
-    {\r
-        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);\r
-        ExFreePool(buffer);\r
-        close(*Socket);\r
-        *Socket = -1;\r
-        IoStatus->Status = STATUS_UNSUCCESSFUL;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    pData = strstr(buffer, "\r\n\r\n") + 4;\r
-\r
-    if (pData == NULL || pData < buffer || pData >= buffer + BUFFER_SIZE)\r
-    {\r
-        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);\r
-        ExFreePool(buffer);\r
-        close(*Socket);\r
-        *Socket = -1;\r
-        IoStatus->Status = STATUS_UNSUCCESSFUL;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    dataLen = nRecv - (pData - buffer);\r
-\r
-    if (dataLen > Length || pData + dataLen > buffer + BUFFER_SIZE)\r
-    {\r
-        DbgPrint("HttpDisk: Invalid data length %u in HTTP response:\n%s", dataLen, buffer);\r
-        ExFreePool(buffer);\r
-        close(*Socket);\r
-        *Socket = -1;\r
-        IoStatus->Status = STATUS_UNSUCCESSFUL;\r
-        return IoStatus->Status;\r
-    }\r
-\r
-    if (dataLen > 0)\r
-    {\r
-        RtlCopyMemory(\r
-            SystemBuffer,\r
-            pData,\r
-            dataLen\r
-            );\r
-    }\r
-\r
-    while (dataLen < Length)\r
-    {\r
-        nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);\r
-        if (nRecv < 0)\r
-        {\r
-            DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);\r
-            close(*Socket);\r
-            *Socket = -1;\r
-            break;\r
-        }\r
-        if (nRecv < 1 || dataLen + nRecv > Length || nRecv > BUFFER_SIZE)\r
-        {\r
-            DbgPrint("HttpDisk: Invalid data length %u+%u\n", dataLen, nRecv);\r
-            close(*Socket);\r
-            *Socket = -1;\r
-            break;\r
-        }\r
-        RtlCopyMemory(\r
-            (PVOID)((PUCHAR) SystemBuffer + dataLen),\r
-            buffer,\r
-            nRecv\r
-        );\r
-        dataLen += nRecv;\r
-    }\r
-\r
-    if (dataLen != Length)\r
-    {\r
-        DbgPrint("HttpDisk: received data length: %u, expected data length: %u\n", dataLen, Length);\r
-    }\r
-\r
-    ExFreePool(buffer);\r
-    IoStatus->Status = STATUS_SUCCESS;\r
-    IoStatus->Information = dataLen;\r
-    return IoStatus->Status;\r
-}\r
+/*
+    HTTP Virtual Disk.
+    Copyright (C) 2006 Bo Brantén.
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <ntddk.h>
+#include <ntdddisk.h>
+#include <ntddcdrm.h>
+#include <ntverp.h>
+#include "ksocket.h"
+
+//
+// We include some stuff from newer DDK:s here so that one
+// version of the driver for all versions of Windows can
+// be compiled with the Windows NT 4.0 DDK.
+//
+#if (VER_PRODUCTBUILD < 2195)
+
+#define FILE_DEVICE_MASS_STORAGE            0x0000002d
+#define IOCTL_STORAGE_CHECK_VERIFY2         CTL_CODE(IOCTL_STORAGE_BASE, 0x0200, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif // (VER_PRODUCTBUILD < 2195)
+
+#if (VER_PRODUCTBUILD < 2600)
+
+#define IOCTL_DISK_GET_PARTITION_INFO_EX    CTL_CODE(IOCTL_DISK_BASE, 0x0012, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_DISK_GET_LENGTH_INFO          CTL_CODE(IOCTL_DISK_BASE, 0x0017, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+typedef enum _PARTITION_STYLE {
+    PARTITION_STYLE_MBR,
+    PARTITION_STYLE_GPT
+} PARTITION_STYLE;
+
+typedef unsigned __int64 ULONG64, *PULONG64;
+
+typedef struct _PARTITION_INFORMATION_MBR {
+    UCHAR   PartitionType;
+    BOOLEAN BootIndicator;
+    BOOLEAN RecognizedPartition;
+    ULONG   HiddenSectors;
+} PARTITION_INFORMATION_MBR, *PPARTITION_INFORMATION_MBR;
+
+typedef struct _PARTITION_INFORMATION_GPT {
+    GUID    PartitionType;
+    GUID    PartitionId;
+    ULONG64 Attributes;
+    WCHAR   Name[36];
+} PARTITION_INFORMATION_GPT, *PPARTITION_INFORMATION_GPT;
+
+typedef struct _PARTITION_INFORMATION_EX {
+    PARTITION_STYLE PartitionStyle;
+    LARGE_INTEGER   StartingOffset;
+    LARGE_INTEGER   PartitionLength;
+    ULONG           PartitionNumber;
+    BOOLEAN         RewritePartition;
+    union {
+        PARTITION_INFORMATION_MBR Mbr;
+        PARTITION_INFORMATION_GPT Gpt;
+    };
+} PARTITION_INFORMATION_EX, *PPARTITION_INFORMATION_EX;
+
+typedef struct _GET_LENGTH_INFORMATION {
+    LARGE_INTEGER Length;
+} GET_LENGTH_INFORMATION, *PGET_LENGTH_INFORMATION;
+
+#endif // (VER_PRODUCTBUILD < 2600)
+
+//
+// For backward compatibility with Windows NT 4.0 by Bruce Engle.
+//
+#ifndef MmGetSystemAddressForMdlSafe
+#define MmGetSystemAddressForMdlSafe(MDL, PRIORITY) MmGetSystemAddressForMdlPrettySafe(MDL)
+
+PVOID
+MmGetSystemAddressForMdlPrettySafe (
+    PMDL Mdl
+    )
+{
+    CSHORT  MdlMappingCanFail;
+    PVOID   MappedSystemVa;
+
+    MdlMappingCanFail = Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL;
+
+    Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
+
+    MappedSystemVa = MmGetSystemAddressForMdl(Mdl);
+
+    if (MdlMappingCanFail == 0)
+    {
+        Mdl->MdlFlags &= ~MDL_MAPPING_CAN_FAIL;
+    }
+
+    return MappedSystemVa;
+}
+#endif
+
+#include "httpdisk.h"
+
+#define PARAMETER_KEY           L"\\Parameters"
+
+#define NUMBEROFDEVICES_VALUE   L"NumberOfDevices"
+
+#define DEFAULT_NUMBEROFDEVICES 4
+
+#define SECTOR_SIZE             512
+
+#define TOC_DATA_TRACK          0x04
+
+#define BUFFER_SIZE             (4096 * 4)
+
+HANDLE dir_handle;
+
+typedef struct _HTTP_HEADER {
+    LARGE_INTEGER ContentLength;
+} HTTP_HEADER, *PHTTP_HEADER;
+
+typedef struct _DEVICE_EXTENSION {
+    BOOLEAN         media_in_device;
+    ULONG           address;
+    USHORT          port;
+    PUCHAR          host_name;
+    PUCHAR          file_name;
+    LARGE_INTEGER   file_size;
+    int             socket;
+    LIST_ENTRY      list_head;
+    KSPIN_LOCK      list_lock;
+    KEVENT          request_event;
+    PVOID           thread_pointer;
+    BOOLEAN         terminate_thread;
+} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
+
+NTSTATUS
+DriverEntry (
+    IN PDRIVER_OBJECT   DriverObject,
+    IN PUNICODE_STRING  RegistryPath
+);
+
+NTSTATUS
+HttpDiskCreateDevice (
+    IN PDRIVER_OBJECT   DriverObject,
+    IN ULONG            Number,
+    IN DEVICE_TYPE      DeviceType
+);
+
+VOID
+HttpDiskUnload (
+    IN PDRIVER_OBJECT   DriverObject
+);
+
+PDEVICE_OBJECT
+HttpDiskDeleteDevice (
+    IN PDEVICE_OBJECT   DeviceObject
+);
+
+NTSTATUS
+HttpDiskCreateClose (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+);
+
+NTSTATUS
+HttpDiskReadWrite (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+);
+
+NTSTATUS
+HttpDiskDeviceControl (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+);
+
+VOID
+HttpDiskThread (
+    IN PVOID            Context
+);
+
+NTSTATUS
+HttpDiskConnect (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+);
+
+NTSTATUS
+HttpDiskDisconnect (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+);
+
+NTSTATUS
+HttpDiskGetHeader (
+    IN ULONG                Address,
+    IN USHORT               Port,
+    IN PUCHAR               HostName,
+    IN PUCHAR               FileName,
+    OUT PIO_STATUS_BLOCK    IoStatus,
+    OUT PHTTP_HEADER        HttpHeader
+);
+
+NTSTATUS
+HttpDiskGetBlock (
+    IN int                  *Socket,
+    IN ULONG                Address,
+    IN USHORT               Port,
+    IN PUCHAR               HostName,
+    IN PUCHAR               FileName,
+    IN PLARGE_INTEGER       Offset,
+    IN ULONG                Length,
+    OUT PIO_STATUS_BLOCK    IoStatus,
+    OUT PVOID               SystemBuffer
+);
+
+__int64 __cdecl _atoi64(const char *);
+int __cdecl _snprintf(char *, size_t, const char *, ...);
+int __cdecl swprintf(wchar_t *, const wchar_t *, ...);
+
+#pragma code_seg("INIT")
+
+NTSTATUS
+DriverEntry (
+    IN PDRIVER_OBJECT   DriverObject,
+    IN PUNICODE_STRING  RegistryPath
+    )
+{
+    UNICODE_STRING              parameter_path;
+    RTL_QUERY_REGISTRY_TABLE    query_table[2];
+    ULONG                       n_devices;
+    NTSTATUS                    status;
+    UNICODE_STRING              device_dir_name;
+    OBJECT_ATTRIBUTES           object_attributes;
+    ULONG                       n;
+    USHORT                      n_created_devices;
+
+    parameter_path.Length = 0;
+
+    parameter_path.MaximumLength = RegistryPath->Length + sizeof(PARAMETER_KEY);
+
+    parameter_path.Buffer = (PWSTR) ExAllocatePool(PagedPool, parameter_path.MaximumLength);
+
+    if (parameter_path.Buffer == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlCopyUnicodeString(&parameter_path, RegistryPath);
+
+    RtlAppendUnicodeToString(&parameter_path, PARAMETER_KEY);
+
+    RtlZeroMemory(&query_table[0], sizeof(query_table));
+
+    query_table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+    query_table[0].Name = NUMBEROFDEVICES_VALUE;
+    query_table[0].EntryContext = &n_devices;
+
+    status = RtlQueryRegistryValues(
+        RTL_REGISTRY_ABSOLUTE,
+        parameter_path.Buffer,
+        &query_table[0],
+        NULL,
+        NULL
+        );
+
+    ExFreePool(parameter_path.Buffer);
+
+    if (!NT_SUCCESS(status))
+    {
+        DbgPrint("HttpDisk: Query registry failed, using default values.\n");
+        n_devices = DEFAULT_NUMBEROFDEVICES;
+    }
+
+    RtlInitUnicodeString(&device_dir_name, DEVICE_DIR_NAME);
+
+    InitializeObjectAttributes(
+        &object_attributes,
+        &device_dir_name,
+        OBJ_PERMANENT,
+        NULL,
+        NULL
+        );
+
+    status = ZwCreateDirectoryObject(
+        &dir_handle,
+        DIRECTORY_ALL_ACCESS,
+        &object_attributes
+        );
+
+    if (!NT_SUCCESS(status))
+    {
+        return status;
+    }
+
+    ZwMakeTemporaryObject(dir_handle);
+
+    for (n = 0, n_created_devices = 0; n < n_devices; n++)
+    {
+        status = HttpDiskCreateDevice(DriverObject, n, FILE_DEVICE_DISK);
+
+        if (NT_SUCCESS(status))
+        {
+            n_created_devices++;
+        }
+    }
+
+    for (n = 0; n < n_devices; n++)
+    {
+        status = HttpDiskCreateDevice(DriverObject, n, FILE_DEVICE_CD_ROM);
+
+        if (NT_SUCCESS(status))
+        {
+            n_created_devices++;
+        }
+    }
+
+    if (n_created_devices == 0)
+    {
+        ZwClose(dir_handle);
+        return status;
+    }
+
+    DriverObject->MajorFunction[IRP_MJ_CREATE]         = HttpDiskCreateClose;
+    DriverObject->MajorFunction[IRP_MJ_CLOSE]          = HttpDiskCreateClose;
+    DriverObject->MajorFunction[IRP_MJ_READ]           = HttpDiskReadWrite;
+    DriverObject->MajorFunction[IRP_MJ_WRITE]          = HttpDiskReadWrite;
+    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HttpDiskDeviceControl;
+
+    DriverObject->DriverUnload = HttpDiskUnload;
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+HttpDiskCreateDevice (
+    IN PDRIVER_OBJECT   DriverObject,
+    IN ULONG            Number,
+    IN DEVICE_TYPE      DeviceType
+    )
+{
+    WCHAR               device_name_buffer[MAXIMUM_FILENAME_LENGTH];
+    UNICODE_STRING      device_name;
+    NTSTATUS            status;
+    PDEVICE_OBJECT      device_object;
+    PDEVICE_EXTENSION   device_extension;
+    HANDLE              thread_handle;
+
+    ASSERT(DriverObject != NULL);
+
+    if (DeviceType == FILE_DEVICE_CD_ROM)
+    {
+        swprintf(
+            device_name_buffer,
+            DEVICE_NAME_PREFIX L"Cd" L"%u",
+            Number
+            );
+    }
+    else
+    {
+        swprintf(
+            device_name_buffer,
+            DEVICE_NAME_PREFIX L"Disk" L"%u",
+            Number
+            );
+    }
+
+    RtlInitUnicodeString(&device_name, device_name_buffer);
+
+    status = IoCreateDevice(
+        DriverObject,
+        sizeof(DEVICE_EXTENSION),
+        &device_name,
+        DeviceType,
+        0,
+        FALSE,
+        &device_object
+        );
+
+    if (!NT_SUCCESS(status))
+    {
+        return status;
+    }
+
+    device_object->Flags |= DO_DIRECT_IO;
+
+    device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;
+
+    device_extension->media_in_device = FALSE;
+
+    device_extension->host_name = NULL;
+
+    device_extension->file_name = NULL;
+
+    device_extension->socket = -1;
+
+    device_object->Characteristics |= FILE_READ_ONLY_DEVICE;
+
+    InitializeListHead(&device_extension->list_head);
+
+    KeInitializeSpinLock(&device_extension->list_lock);
+
+    KeInitializeEvent(
+        &device_extension->request_event,
+        SynchronizationEvent,
+        FALSE
+        );
+
+    device_extension->terminate_thread = FALSE;
+
+    status = PsCreateSystemThread(
+        &thread_handle,
+        (ACCESS_MASK) 0L,
+        NULL,
+        NULL,
+        NULL,
+        HttpDiskThread,
+        device_object
+        );
+
+    if (!NT_SUCCESS(status))
+    {
+        IoDeleteDevice(device_object);
+        return status;
+    }
+
+    status = ObReferenceObjectByHandle(
+        thread_handle,
+        THREAD_ALL_ACCESS,
+        NULL,
+        KernelMode,
+        &device_extension->thread_pointer,
+        NULL
+        );
+
+    if (!NT_SUCCESS(status))
+    {
+        ZwClose(thread_handle);
+
+        device_extension->terminate_thread = TRUE;
+
+        KeSetEvent(
+            &device_extension->request_event,
+            (KPRIORITY) 0,
+            FALSE
+            );
+
+        IoDeleteDevice(device_object);
+
+        return status;
+    }
+
+    ZwClose(thread_handle);
+
+    return STATUS_SUCCESS;
+}
+
+#pragma code_seg("PAGE")
+
+VOID
+HttpDiskUnload (
+    IN PDRIVER_OBJECT DriverObject
+    )
+{
+    PDEVICE_OBJECT device_object;
+
+    device_object = DriverObject->DeviceObject;
+
+    while (device_object)
+    {
+        device_object = HttpDiskDeleteDevice(device_object);
+    }
+
+    ZwClose(dir_handle);
+}
+
+PDEVICE_OBJECT
+HttpDiskDeleteDevice (
+    IN PDEVICE_OBJECT DeviceObject
+    )
+{
+    PDEVICE_EXTENSION   device_extension;
+    PDEVICE_OBJECT      next_device_object;
+
+    ASSERT(DeviceObject != NULL);
+
+    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+    device_extension->terminate_thread = TRUE;
+
+    KeSetEvent(
+        &device_extension->request_event,
+        (KPRIORITY) 0,
+        FALSE
+        );
+
+    KeWaitForSingleObject(
+        device_extension->thread_pointer,
+        Executive,
+        KernelMode,
+        FALSE,
+        NULL
+        );
+
+    ObDereferenceObject(device_extension->thread_pointer);
+
+    next_device_object = DeviceObject->NextDevice;
+
+    IoDeleteDevice(DeviceObject);
+
+    return next_device_object;
+}
+
+NTSTATUS
+HttpDiskCreateClose (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+    )
+{
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    Irp->IoStatus.Information = FILE_OPENED;
+
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return STATUS_SUCCESS;
+}
+
+#pragma code_seg()
+
+NTSTATUS
+HttpDiskReadWrite (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+    )
+{
+    PDEVICE_EXTENSION   device_extension;
+    PIO_STACK_LOCATION  io_stack;
+
+    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+    if (!device_extension->media_in_device)
+    {
+        Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
+        Irp->IoStatus.Information = 0;
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        return STATUS_NO_MEDIA_IN_DEVICE;
+    }
+
+    io_stack = IoGetCurrentIrpStackLocation(Irp);
+
+    if (io_stack->Parameters.Read.Length == 0)
+    {
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+        Irp->IoStatus.Information = 0;
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        return STATUS_SUCCESS;
+    }
+
+    IoMarkIrpPending(Irp);
+
+    ExInterlockedInsertTailList(
+        &device_extension->list_head,
+        &Irp->Tail.Overlay.ListEntry,
+        &device_extension->list_lock
+        );
+
+    KeSetEvent(
+        &device_extension->request_event,
+        (KPRIORITY) 0,
+        FALSE
+        );
+
+    return STATUS_PENDING;
+}
+
+NTSTATUS
+HttpDiskDeviceControl (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+    )
+{
+    PDEVICE_EXTENSION   device_extension;
+    PIO_STACK_LOCATION  io_stack;
+    NTSTATUS            status;
+
+    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+    io_stack = IoGetCurrentIrpStackLocation(Irp);
+
+    if (!device_extension->media_in_device &&
+        io_stack->Parameters.DeviceIoControl.IoControlCode !=
+        IOCTL_HTTP_DISK_CONNECT)
+    {
+        Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
+        Irp->IoStatus.Information = 0;
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+        return STATUS_NO_MEDIA_IN_DEVICE;
+    }
+
+    switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
+    {
+    case IOCTL_HTTP_DISK_CONNECT:
+        {
+            if (device_extension->media_in_device)
+            {
+                DbgPrint("HttpDisk: IOCTL_HTTP_DISK_CONNECT: Media already opened.\n");
+
+                status = STATUS_INVALID_DEVICE_REQUEST;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            if (io_stack->Parameters.DeviceIoControl.InputBufferLength <
+                sizeof(HTTP_DISK_INFORMATION))
+            {
+                status = STATUS_INVALID_PARAMETER;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            if (io_stack->Parameters.DeviceIoControl.InputBufferLength <
+                sizeof(HTTP_DISK_INFORMATION) +
+                ((PHTTP_DISK_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->FileNameLength -
+                sizeof(UCHAR))
+            {
+                status = STATUS_INVALID_PARAMETER;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            IoMarkIrpPending(Irp);
+
+            ExInterlockedInsertTailList(
+                &device_extension->list_head,
+                &Irp->Tail.Overlay.ListEntry,
+                &device_extension->list_lock
+                );
+
+            KeSetEvent(
+                &device_extension->request_event,
+                (KPRIORITY) 0,
+                FALSE
+                );
+
+            status = STATUS_PENDING;
+
+            break;
+        }
+
+    case IOCTL_HTTP_DISK_DISCONNECT:
+        {
+            IoMarkIrpPending(Irp);
+
+            ExInterlockedInsertTailList(
+                &device_extension->list_head,
+                &Irp->Tail.Overlay.ListEntry,
+                &device_extension->list_lock
+                );
+
+            KeSetEvent(
+                &device_extension->request_event,
+                (KPRIORITY) 0,
+                FALSE
+                );
+
+            status = STATUS_PENDING;
+
+            break;
+        }
+
+    case IOCTL_DISK_CHECK_VERIFY:
+    case IOCTL_CDROM_CHECK_VERIFY:
+    case IOCTL_STORAGE_CHECK_VERIFY:
+    case IOCTL_STORAGE_CHECK_VERIFY2:
+        {
+            status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = 0;
+            break;
+        }
+
+    case IOCTL_DISK_GET_DRIVE_GEOMETRY:
+    case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
+        {
+            PDISK_GEOMETRY  disk_geometry;
+            ULONGLONG       length;
+
+            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
+                sizeof(DISK_GEOMETRY))
+            {
+                status = STATUS_BUFFER_TOO_SMALL;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            disk_geometry = (PDISK_GEOMETRY) Irp->AssociatedIrp.SystemBuffer;
+
+            length = device_extension->file_size.QuadPart;
+
+            disk_geometry->Cylinders.QuadPart = length / SECTOR_SIZE / 32 / 2;
+            disk_geometry->MediaType = FixedMedia;
+            disk_geometry->TracksPerCylinder = 2;
+            disk_geometry->SectorsPerTrack = 32;
+            disk_geometry->BytesPerSector = SECTOR_SIZE;
+
+            status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
+
+            break;
+        }
+
+    case IOCTL_DISK_GET_LENGTH_INFO:
+        {
+            PGET_LENGTH_INFORMATION get_length_information;
+
+            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
+                sizeof(GET_LENGTH_INFORMATION))
+            {
+                status = STATUS_BUFFER_TOO_SMALL;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            get_length_information = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
+
+            get_length_information->Length.QuadPart = device_extension->file_size.QuadPart;
+
+            status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = sizeof(GET_LENGTH_INFORMATION);
+
+        break;
+        }
+
+    case IOCTL_DISK_GET_PARTITION_INFO:
+        {
+            PPARTITION_INFORMATION  partition_information;
+            ULONGLONG               length;
+
+            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
+                sizeof(PARTITION_INFORMATION))
+            {
+                status = STATUS_BUFFER_TOO_SMALL;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            partition_information = (PPARTITION_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
+
+            length = device_extension->file_size.QuadPart;
+
+            partition_information->StartingOffset.QuadPart = 0;
+            partition_information->PartitionLength.QuadPart = length;
+            partition_information->HiddenSectors = 1;
+            partition_information->PartitionNumber = 0;
+            partition_information->PartitionType = 0;
+            partition_information->BootIndicator = FALSE;
+            partition_information->RecognizedPartition = FALSE;
+            partition_information->RewritePartition = FALSE;
+
+            status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION);
+
+            break;
+        }
+
+    case IOCTL_DISK_GET_PARTITION_INFO_EX:
+        {
+            PPARTITION_INFORMATION_EX   partition_information_ex;
+            ULONGLONG                   length;
+
+            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
+                sizeof(PARTITION_INFORMATION_EX))
+            {
+                status = STATUS_BUFFER_TOO_SMALL;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            partition_information_ex = (PPARTITION_INFORMATION_EX) Irp->AssociatedIrp.SystemBuffer;
+
+            length = device_extension->file_size.QuadPart;
+
+            partition_information_ex->PartitionStyle = PARTITION_STYLE_MBR;
+            partition_information_ex->StartingOffset.QuadPart = 0;
+            partition_information_ex->PartitionLength.QuadPart = length;
+            partition_information_ex->PartitionNumber = 0;
+            partition_information_ex->RewritePartition = FALSE;
+            partition_information_ex->Mbr.PartitionType = 0;
+            partition_information_ex->Mbr.BootIndicator = FALSE;
+            partition_information_ex->Mbr.RecognizedPartition = FALSE;
+            partition_information_ex->Mbr.HiddenSectors = 1;
+
+            status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = sizeof(PARTITION_INFORMATION_EX);
+
+            break;
+        }
+
+    case IOCTL_DISK_IS_WRITABLE:
+        {
+            status = STATUS_MEDIA_WRITE_PROTECTED;
+            Irp->IoStatus.Information = 0;
+            break;
+        }
+
+    case IOCTL_DISK_MEDIA_REMOVAL:
+    case IOCTL_STORAGE_MEDIA_REMOVAL:
+        {
+            status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = 0;
+            break;
+        }
+
+    case IOCTL_CDROM_READ_TOC:
+        {
+            PCDROM_TOC cdrom_toc;
+
+            if (io_stack->Parameters.DeviceIoControl.OutputBufferLength <
+                sizeof(CDROM_TOC))
+            {
+                status = STATUS_BUFFER_TOO_SMALL;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            cdrom_toc = (PCDROM_TOC) Irp->AssociatedIrp.SystemBuffer;
+
+            RtlZeroMemory(cdrom_toc, sizeof(CDROM_TOC));
+
+            cdrom_toc->FirstTrack = 1;
+            cdrom_toc->LastTrack = 1;
+            cdrom_toc->TrackData[0].Control = TOC_DATA_TRACK;
+
+            status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = sizeof(CDROM_TOC);
+
+            break;
+        }
+
+    case IOCTL_DISK_SET_PARTITION_INFO:
+        {
+            status = STATUS_MEDIA_WRITE_PROTECTED;
+            Irp->IoStatus.Information = 0;
+            break;
+        }
+
+    case IOCTL_DISK_VERIFY:
+        {
+            PVERIFY_INFORMATION verify_information;
+
+            if (io_stack->Parameters.DeviceIoControl.InputBufferLength <
+                sizeof(VERIFY_INFORMATION))
+            {
+                status = STATUS_INVALID_PARAMETER;
+                Irp->IoStatus.Information = 0;
+                break;
+            }
+
+            verify_information = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
+
+            status = STATUS_SUCCESS;
+            Irp->IoStatus.Information = verify_information->Length;
+
+            break;
+        }
+
+    default:
+        {
+            KdPrint((
+                "HttpDisk: Unknown IoControlCode: %#x\n",
+                io_stack->Parameters.DeviceIoControl.IoControlCode
+                ));
+
+            status = STATUS_INVALID_DEVICE_REQUEST;
+            Irp->IoStatus.Information = 0;
+        }
+    }
+
+    if (status != STATUS_PENDING)
+    {
+        Irp->IoStatus.Status = status;
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+
+    return status;
+}
+
+#pragma code_seg("PAGE")
+
+VOID
+HttpDiskThread (
+    IN PVOID Context
+    )
+{
+    PDEVICE_OBJECT      device_object;
+    PDEVICE_EXTENSION   device_extension;
+    PLIST_ENTRY         request;
+    PIRP                irp;
+    PIO_STACK_LOCATION  io_stack;
+
+    ASSERT(Context != NULL);
+
+    device_object = (PDEVICE_OBJECT) Context;
+
+    device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;
+
+    KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
+
+    for (;;)
+    {
+        KeWaitForSingleObject(
+            &device_extension->request_event,
+            Executive,
+            KernelMode,
+            FALSE,
+            NULL
+            );
+
+        if (device_extension->terminate_thread)
+        {
+            PsTerminateSystemThread(STATUS_SUCCESS);
+        }
+
+        while (request = ExInterlockedRemoveHeadList(
+            &device_extension->list_head,
+            &device_extension->list_lock
+            ))
+        {
+            irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
+
+            io_stack = IoGetCurrentIrpStackLocation(irp);
+
+            switch (io_stack->MajorFunction)
+            {
+            case IRP_MJ_READ:
+                HttpDiskGetBlock(
+                    &device_extension->socket,
+                    device_extension->address,
+                    device_extension->port,
+                    device_extension->host_name,
+                    device_extension->file_name,
+                    &io_stack->Parameters.Read.ByteOffset,
+                    io_stack->Parameters.Read.Length,
+                    &irp->IoStatus,
+                    MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority)
+                    );
+                if (!NT_SUCCESS(irp->IoStatus.Status))
+                {
+                    HttpDiskGetBlock(
+                        &device_extension->socket,
+                        device_extension->address,
+                        device_extension->port,
+                        device_extension->host_name,
+                        device_extension->file_name,
+                        &io_stack->Parameters.Read.ByteOffset,
+                        io_stack->Parameters.Read.Length,
+                        &irp->IoStatus,
+                        MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority)
+                        );
+                }
+                break;
+
+            case IRP_MJ_WRITE:
+                irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED;
+                irp->IoStatus.Information = 0;
+                break;
+
+            case IRP_MJ_DEVICE_CONTROL:
+                switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
+                {
+                case IOCTL_HTTP_DISK_CONNECT:
+                    irp->IoStatus.Status = HttpDiskConnect(device_object, irp);
+                    break;
+
+                case IOCTL_HTTP_DISK_DISCONNECT:
+                    irp->IoStatus.Status = HttpDiskDisconnect(device_object, irp);
+                    break;
+
+                default:
+                    irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
+                }
+                break;
+
+            default:
+                irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
+            }
+
+            IoCompleteRequest(
+                irp,
+                (CCHAR) (NT_SUCCESS(irp->IoStatus.Status) ?
+                IO_DISK_INCREMENT : IO_NO_INCREMENT)
+                );
+        }
+    }
+}
+
+NTSTATUS
+HttpDiskConnect (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+    )
+{
+    PDEVICE_EXTENSION       device_extension;
+    PHTTP_DISK_INFORMATION  http_disk_information;
+    HTTP_HEADER             http_header;
+
+    ASSERT(DeviceObject != NULL);
+    ASSERT(Irp != NULL);
+
+    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+    http_disk_information = (PHTTP_DISK_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
+
+    device_extension->address = http_disk_information->Address;
+
+    device_extension->port = http_disk_information->Port;
+
+    device_extension->host_name = ExAllocatePool(NonPagedPool, http_disk_information->HostNameLength + 1);
+
+    if (device_extension->host_name == NULL)
+    {
+        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+        return Irp->IoStatus.Status;
+    }
+
+    RtlCopyMemory(
+        device_extension->host_name,
+        http_disk_information->HostName,
+        http_disk_information->HostNameLength
+        );
+
+    device_extension->host_name[http_disk_information->HostNameLength] = '\0';
+
+    device_extension->file_name = ExAllocatePool(NonPagedPool, http_disk_information->FileNameLength + 1);
+
+    if (device_extension->file_name == NULL)
+    {
+        if (device_extension->host_name != NULL)
+        {
+            ExFreePool(device_extension->host_name);
+            device_extension->host_name = NULL;
+        }
+
+        Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
+        return Irp->IoStatus.Status;
+    }
+
+    RtlCopyMemory(
+        device_extension->file_name,
+        http_disk_information->FileName,
+        http_disk_information->FileNameLength
+        );
+
+    device_extension->file_name[http_disk_information->FileNameLength] = '\0';
+
+    HttpDiskGetHeader(
+        device_extension->address,
+        device_extension->port,
+        device_extension->host_name,
+        device_extension->file_name,
+        &Irp->IoStatus,
+        &http_header
+        );
+
+    if (!NT_SUCCESS(Irp->IoStatus.Status))
+    {
+        HttpDiskGetHeader(
+            device_extension->address,
+            device_extension->port,
+            device_extension->host_name,
+            device_extension->file_name,
+            &Irp->IoStatus,
+            &http_header
+            );
+    }
+
+    if (!NT_SUCCESS(Irp->IoStatus.Status))
+    {
+        if (device_extension->host_name != NULL)
+        {
+            ExFreePool(device_extension->host_name);
+            device_extension->host_name = NULL;
+        }
+
+        if (device_extension->file_name != NULL)
+        {
+            ExFreePool(device_extension->file_name);
+            device_extension->file_name = NULL;
+        }
+
+        return Irp->IoStatus.Status;
+    }
+
+    device_extension->file_size.QuadPart = http_header.ContentLength.QuadPart;
+
+    device_extension->media_in_device = TRUE;
+
+    return Irp->IoStatus.Status;
+}
+
+NTSTATUS
+HttpDiskDisconnect (
+    IN PDEVICE_OBJECT   DeviceObject,
+    IN PIRP             Irp
+    )
+{
+    PDEVICE_EXTENSION device_extension;
+
+    ASSERT(DeviceObject != NULL);
+    ASSERT(Irp != NULL);
+
+    device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+
+    device_extension->media_in_device = FALSE;
+
+    if (device_extension->host_name != NULL)
+    {
+        ExFreePool(device_extension->host_name);
+        device_extension->host_name = NULL;
+    }
+
+    if (device_extension->file_name != NULL)
+    {
+        ExFreePool(device_extension->file_name);
+        device_extension->file_name = NULL;
+    }
+
+    if (device_extension->socket > 0)
+    {
+        close(device_extension->socket);
+        device_extension->socket = -1;
+    }
+
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    Irp->IoStatus.Information = 0;
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+HttpDiskGetHeader (
+    IN ULONG                Address,
+    IN USHORT               Port,
+    IN PUCHAR               HostName,
+    IN PUCHAR               FileName,
+    OUT PIO_STATUS_BLOCK    IoStatus,
+    OUT PHTTP_HEADER        HttpHeader
+    )
+{
+    int                 kSocket;
+    struct sockaddr_in  toAddr;
+    int                 status, nSent, nRecv;
+    char                *buffer, *pStr;
+
+    ASSERT(HostName != NULL);
+    ASSERT(FileName != NULL);
+    ASSERT(IoStatus != NULL);
+    ASSERT(HttpHeader != NULL);
+
+    buffer = ExAllocatePool(PagedPool, BUFFER_SIZE);
+
+    if (buffer == NULL)
+    {
+        IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
+        return IoStatus->Status;
+    }
+
+    kSocket = socket(AF_INET, SOCK_STREAM, 0);
+
+    if (kSocket < 0)
+    {
+        DbgPrint("HttpDisk: socket() error: %#x\n", kSocket);
+        ExFreePool(buffer);
+        IoStatus->Status = kSocket;
+        return IoStatus->Status;
+    }
+
+    toAddr.sin_family = AF_INET;
+    toAddr.sin_port = Port;
+    toAddr.sin_addr.s_addr = Address;
+
+    status = connect(kSocket, (struct sockaddr*) &toAddr, sizeof(toAddr));
+
+    if (status < 0)
+    {
+        DbgPrint("HttpDisk: connect() error: %#x\n", status);
+        ExFreePool(buffer);
+        close(kSocket);
+        IoStatus->Status = status;
+        return IoStatus->Status;
+    }
+
+    // Example request:
+    //  HEAD 'FileName' HTTP/1.1
+    //  Host: 'HostName'
+    //  Accept: */*
+    //  User-Agent: HttpDisk/1.2
+    //  Connection: close
+    //
+    // Interesting lines in answer:
+    //  HTTP/1.1 200 OK
+    //  Accept-Ranges: bytes
+    //  Content-Length: 'total file size'
+
+    _snprintf(
+        buffer,
+        BUFFER_SIZE,
+        "HEAD %s HTTP/1.1\r\nHost: %s\r\nAccept: */*\r\nUser-Agent: HttpDisk/1.2\r\nConnection: close\r\n\r\n",
+        FileName,
+        HostName
+        );
+
+    nSent = send(kSocket, buffer, strlen(buffer), 0);
+
+    if (nSent < 0)
+    {
+        DbgPrint("HttpDisk: send() error: %#x\n", nSent);
+        ExFreePool(buffer);
+        close(kSocket);
+        IoStatus->Status = nSent;
+        return IoStatus->Status;
+    }
+
+    nRecv = recv(kSocket, buffer, BUFFER_SIZE, 0);
+
+    if (nRecv < 0)
+    {
+        DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);
+        ExFreePool(buffer);
+        close(kSocket);
+        IoStatus->Status = nRecv;
+        return IoStatus->Status;
+    }
+
+    close(kSocket);
+
+    buffer[BUFFER_SIZE - 1] = '\0';
+
+    if (_strnicmp(buffer, "HTTP/1.1 200 OK", 15))
+    {
+        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
+        ExFreePool(buffer);
+        IoStatus->Status = STATUS_NO_SUCH_FILE;
+        return IoStatus->Status;
+    }
+
+    pStr = strstr(buffer, "Content-Length:");
+
+    if (pStr == NULL || pStr + 16 >= buffer + BUFFER_SIZE)
+    {
+        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
+        ExFreePool(buffer);
+        IoStatus->Status = STATUS_NO_SUCH_FILE;
+        return IoStatus->Status;
+    }
+
+    HttpHeader->ContentLength.QuadPart = _atoi64(pStr + 16);
+
+    if (HttpHeader->ContentLength.QuadPart == 0)
+    {
+        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
+        ExFreePool(buffer);
+        IoStatus->Status = STATUS_NO_SUCH_FILE;
+        return IoStatus->Status;
+    }
+
+    ExFreePool(buffer);
+
+    IoStatus->Status = STATUS_SUCCESS;
+    IoStatus->Information = 0;
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+HttpDiskGetBlock (
+    IN int                  *Socket,
+    IN ULONG                Address,
+    IN USHORT               Port,
+    IN PUCHAR               HostName,
+    IN PUCHAR               FileName,
+    IN PLARGE_INTEGER       Offset,
+    IN ULONG                Length,
+    OUT PIO_STATUS_BLOCK    IoStatus,
+    OUT PVOID               SystemBuffer
+    )
+{
+    struct sockaddr_in  toAddr;
+    int                 status, nSent, nRecv;
+    unsigned int        dataLen;
+    char                *buffer, *pData;
+
+    ASSERT(Socket != NULL);
+    ASSERT(HostName != NULL);
+    ASSERT(FileName != NULL);
+    ASSERT(Offset != NULL);
+    ASSERT(IoStatus != NULL);
+    ASSERT(SystemBuffer != NULL);
+
+    IoStatus->Information = 0;
+
+    buffer = ExAllocatePool(PagedPool, BUFFER_SIZE + 1);
+
+    if (buffer == NULL)
+    {
+        IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
+        return IoStatus->Status;
+    }
+
+    // Example request:
+    //  GET 'FileName' HTTP/1.1
+    //  Host: 'HostName'
+    //  Range: bytes='Offset'-'Offset + Length - 1'
+    //  Accept: */*
+    //  User-Agent: HttpDisk/1.2
+    //
+    // Interesting lines in answer:
+    //  HTTP/1.1 206 Partial content
+    //  Content-Length: 'requested size'
+    //  Content-Range: bytes 'start'-'end'/'total file size'
+    //  Data follows after '\r\n\r\n'
+
+    _snprintf(
+        buffer,
+        BUFFER_SIZE,
+        "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",
+        FileName,
+        HostName,
+        Offset->QuadPart,
+        Offset->QuadPart + Length - 1
+        );
+
+    if (*Socket < 0)
+    {
+        *Socket = socket(AF_INET, SOCK_STREAM, 0);
+
+        if (*Socket < 0)
+        {
+            ExFreePool(buffer);
+            *Socket = -1;
+            IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
+            return IoStatus->Status;
+        }
+
+        toAddr.sin_family = AF_INET;
+        toAddr.sin_port = Port;
+        toAddr.sin_addr.s_addr = Address;
+
+        status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));
+
+        if (status < 0)
+        {
+            DbgPrint("HttpDisk: connect() error: %#x\n", status);
+            ExFreePool(buffer);
+            close(*Socket);
+            *Socket = -1;
+            IoStatus->Status = status;
+            return IoStatus->Status;
+        }
+    }
+
+    nSent = send(*Socket, buffer, strlen(buffer), 0);
+
+    if (nSent < 0)
+    {
+        KdPrint(("HttpDisk: send() error: %#x\n", nSent));
+
+        close(*Socket);
+
+        *Socket = socket(AF_INET, SOCK_STREAM, 0);
+
+        if (*Socket < 0)
+        {
+            ExFreePool(buffer);
+            *Socket = -1;
+            IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
+            return IoStatus->Status;
+        }
+
+        toAddr.sin_family = AF_INET;
+        toAddr.sin_port = Port;
+        toAddr.sin_addr.s_addr = Address;
+
+        status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));
+
+        if (status < 0)
+        {
+            DbgPrint("HttpDisk: connect() error: %#x\n", status);
+            ExFreePool(buffer);
+            close(*Socket);
+            *Socket = -1;
+            IoStatus->Status = status;
+            return IoStatus->Status;
+        }
+
+        nSent = send(*Socket, buffer, strlen(buffer), 0);
+
+        if (nSent < 0)
+        {
+            DbgPrint("HttpDisk: send() error: %#x\n", nSent);
+            ExFreePool(buffer);
+            close(*Socket);
+            *Socket = -1;
+            IoStatus->Status = nSent;
+            return IoStatus->Status;
+        }
+    }
+
+    nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);
+
+    if (nRecv < 0)
+    {
+        KdPrint(("HttpDisk: recv() error: %#x\n", nRecv));
+
+        close(*Socket);
+
+        *Socket = socket(AF_INET, SOCK_STREAM, 0);
+
+        if (*Socket < 0)
+        {
+            ExFreePool(buffer);
+            *Socket = -1;
+            IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
+            return IoStatus->Status;
+        }
+
+        toAddr.sin_family = AF_INET;
+        toAddr.sin_port = Port;
+        toAddr.sin_addr.s_addr = Address;
+
+        status = connect(*Socket, (struct sockaddr*) &toAddr, sizeof(toAddr));
+
+        if (status < 0)
+        {
+            DbgPrint("HttpDisk: connect() error: %#x\n", status);
+            ExFreePool(buffer);
+            close(*Socket);
+            *Socket = -1;
+            IoStatus->Status = status;
+            return IoStatus->Status;
+        }
+
+        nSent = send(*Socket, buffer, strlen(buffer), 0);
+
+        if (nSent < 0)
+        {
+            DbgPrint("HttpDisk: send() error: %#x\n", nSent);
+            ExFreePool(buffer);
+            close(*Socket);
+            *Socket = -1;
+            IoStatus->Status = nSent;
+            return IoStatus->Status;
+        }
+
+        nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);
+
+        if (nRecv < 0)
+        {
+            DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);
+            ExFreePool(buffer);
+            close(*Socket);
+            *Socket = -1;
+            IoStatus->Status = nRecv;
+            return IoStatus->Status;
+        }
+    }
+
+    buffer[BUFFER_SIZE] = '\0';
+
+    if (_strnicmp(buffer, "HTTP/1.1 206 Partial Content", 28))
+    {
+        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
+        ExFreePool(buffer);
+        close(*Socket);
+        *Socket = -1;
+        IoStatus->Status = STATUS_UNSUCCESSFUL;
+        return IoStatus->Status;
+    }
+
+    pData = strstr(buffer, "\r\n\r\n") + 4;
+
+    if (pData == NULL || pData < buffer || pData >= buffer + BUFFER_SIZE)
+    {
+        DbgPrint("HttpDisk: Invalid HTTP response:\n%s", buffer);
+        ExFreePool(buffer);
+        close(*Socket);
+        *Socket = -1;
+        IoStatus->Status = STATUS_UNSUCCESSFUL;
+        return IoStatus->Status;
+    }
+
+    dataLen = nRecv - (pData - buffer);
+
+    if (dataLen > Length || pData + dataLen > buffer + BUFFER_SIZE)
+    {
+        DbgPrint("HttpDisk: Invalid data length %u in HTTP response:\n%s", dataLen, buffer);
+        ExFreePool(buffer);
+        close(*Socket);
+        *Socket = -1;
+        IoStatus->Status = STATUS_UNSUCCESSFUL;
+        return IoStatus->Status;
+    }
+
+    if (dataLen > 0)
+    {
+        RtlCopyMemory(
+            SystemBuffer,
+            pData,
+            dataLen
+            );
+    }
+
+    while (dataLen < Length)
+    {
+        nRecv = recv(*Socket, buffer, BUFFER_SIZE, 0);
+        if (nRecv < 0)
+        {
+            DbgPrint("HttpDisk: recv() error: %#x\n", nRecv);
+            close(*Socket);
+            *Socket = -1;
+            break;
+        }
+        if (nRecv < 1 || dataLen + nRecv > Length || nRecv > BUFFER_SIZE)
+        {
+            DbgPrint("HttpDisk: Invalid data length %u+%u\n", dataLen, nRecv);
+            close(*Socket);
+            *Socket = -1;
+            break;
+        }
+        RtlCopyMemory(
+            (PVOID)((PUCHAR) SystemBuffer + dataLen),
+            buffer,
+            nRecv
+        );
+        dataLen += nRecv;
+    }
+
+    if (dataLen != Length)
+    {
+        DbgPrint("HttpDisk: received data length: %u, expected data length: %u\n", dataLen, Length);
+    }
+
+    ExFreePool(buffer);
+    IoStatus->Status = STATUS_SUCCESS;
+    IoStatus->Information = dataLen;
+    return IoStatus->Status;
+}
index 0495bb1..4151fef 100644 (file)
-//Microsoft Developer Studio generated resource script.\r
-//\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifndef _MAC\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION 3,0,0,0\r
- PRODUCTVERSION 3,0,0,0\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x40004L\r
- FILETYPE 0x3L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
-    BLOCK "StringFileInfo"\r
-    BEGIN\r
-        BLOCK "040904b0"\r
-        BEGIN\r
-            VALUE "CompanyName", "Bo Brantén\0"\r
-            VALUE "FileDescription", "HTTP Virtual Disk\0"\r
-            VALUE "FileVersion", "3.0.0.0\0"\r
-            VALUE "InternalName", "httpdisk\0"\r
-            VALUE "LegalCopyright", "Copyright © 2006 Bo Brantén\0"\r
-            VALUE "OriginalFilename", "httpdisk.sys\0"\r
-            VALUE "ProductName", "httpdisk\0"\r
-            VALUE "ProductVersion", "3.0.0.0\0"\r
-        END\r
-    END\r
-    BLOCK "VarFileInfo"\r
-    BEGIN\r
-        VALUE "Translation", 0x409, 1200\r
-    END\r
-END\r
-\r
-#endif    // !_MAC\r
-\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE DISCARDABLE \r
-BEGIN\r
-    "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE DISCARDABLE \r
-BEGIN\r
-    "#include ""afxres.h""\r\n"\r
-    "\0"\r
-END\r
-\r
-3 TEXTINCLUDE DISCARDABLE \r
-BEGIN\r
-    "\r\n"\r
-    "\0"\r
-END\r
-\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-#endif    // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif    // not APSTUDIO_INVOKED\r
-\r
+//Microsoft Developer Studio generated resource script.
+//
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 3,0,0,0
+ PRODUCTVERSION 3,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x3L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Bo Brantén\0"
+            VALUE "FileDescription", "HTTP Virtual Disk\0"
+            VALUE "FileVersion", "3.0.0.0\0"
+            VALUE "InternalName", "httpdisk\0"
+            VALUE "LegalCopyright", "Copyright © 2006 Bo Brantén\0"
+            VALUE "OriginalFilename", "httpdisk.sys\0"
+            VALUE "ProductName", "httpdisk\0"
+            VALUE "ProductVersion", "3.0.0.0\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
index df971e2..d52d3a8 100644 (file)
-/*\r
-    HTTP Virtual Disk.\r
-    Copyright (C) 2006 Bo Brantén.\r
-    This program is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-    This program is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-    You should have received a copy of the GNU General Public License\r
-    along with this program; if not, write to the Free Software\r
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-#include <ntddk.h>\r
-#include <tdikrnl.h>\r
-#include "ktdi.h"\r
-#include "ksocket.h"\r
-\r
-typedef struct _STREAM_SOCKET {\r
-    HANDLE              connectionHandle;\r
-    PFILE_OBJECT        connectionFileObject;\r
-    KEVENT              disconnectEvent;\r
-} STREAM_SOCKET, *PSTREAM_SOCKET;\r
-\r
-typedef struct _SOCKET {\r
-    int                 type;\r
-    BOOLEAN             isBound;\r
-    BOOLEAN             isConnected;\r
-    BOOLEAN             isListening;\r
-    BOOLEAN             isShuttingdown;\r
-    BOOLEAN             isShared;\r
-    HANDLE              addressHandle;\r
-    PFILE_OBJECT        addressFileObject;\r
-    PSTREAM_SOCKET      streamSocket;\r
-    struct sockaddr     peer;\r
-} SOCKET, *PSOCKET;\r
-\r
-NTSTATUS event_disconnect(PVOID TdiEventContext, CONNECTION_CONTEXT ConnectionContext, LONG DisconnectDataLength,\r
-                          PVOID DisconnectData, LONG DisconnectInformationLength, PVOID DisconnectInformation,\r
-                          ULONG DisconnectFlags)\r
-{\r
-    PSOCKET s = (PSOCKET) TdiEventContext;\r
-    PSTREAM_SOCKET streamSocket = (PSTREAM_SOCKET) ConnectionContext;\r
-    KeSetEvent(&streamSocket->disconnectEvent, 0, FALSE);\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-int __cdecl accept(int socket, struct sockaddr *addr, int *addrlen)\r
-{\r
-    return -1;\r
-}\r
-\r
-int __cdecl bind(int socket, const struct sockaddr *addr, int addrlen)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-    const struct sockaddr_in* localAddr = (const struct sockaddr_in*) addr;\r
-    UNICODE_STRING devName;\r
-    NTSTATUS status;\r
-\r
-    if (s->isBound || addr == NULL || addrlen < sizeof(struct sockaddr_in))\r
-    {\r
-        return -1;\r
-    }\r
-\r
-    if (s->type == SOCK_DGRAM)\r
-    {\r
-        RtlInitUnicodeString(&devName, L"\\Device\\Udp");\r
-    }\r
-    else if (s->type == SOCK_STREAM)\r
-    {\r
-        RtlInitUnicodeString(&devName, L"\\Device\\Tcp");\r
-    }\r
-    else\r
-    {\r
-        return -1;\r
-    }\r
-\r
-    status = tdi_open_transport_address(\r
-        &devName,\r
-        localAddr->sin_addr.s_addr,\r
-        localAddr->sin_port,\r
-        s->isShared,\r
-        &s->addressHandle,\r
-        &s->addressFileObject\r
-        );\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        s->addressFileObject = NULL;\r
-        s->addressHandle = (HANDLE) -1;\r
-        return status;\r
-    }\r
-\r
-    if (s->type == SOCK_STREAM)\r
-    {\r
-        tdi_set_event_handler(s->addressFileObject, TDI_EVENT_DISCONNECT, event_disconnect, s);\r
-    }\r
-\r
-    s->isBound = TRUE;\r
-\r
-    return 0;\r
-}\r
-\r
-int __cdecl close(int socket)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-\r
-    if (s->isBound)\r
-    {\r
-        if (s->type == SOCK_STREAM && s->streamSocket)\r
-        {\r
-            if (s->isConnected)\r
-            {\r
-                if (!s->isShuttingdown)\r
-                {\r
-                    tdi_disconnect(s->streamSocket->connectionFileObject, TDI_DISCONNECT_RELEASE);\r
-                }\r
-                //KeWaitForSingleObject(&s->streamSocket->disconnectEvent, Executive, KernelMode, FALSE, NULL);\r
-            }\r
-            if (s->streamSocket->connectionFileObject)\r
-            {\r
-                tdi_disassociate_address(s->streamSocket->connectionFileObject);\r
-                ObDereferenceObject(s->streamSocket->connectionFileObject);\r
-            }\r
-            if (s->streamSocket->connectionHandle != (HANDLE) -1)\r
-            {\r
-                ZwClose(s->streamSocket->connectionHandle);\r
-            }\r
-            ExFreePool(s->streamSocket);\r
-        }\r
-\r
-        if (s->type == SOCK_DGRAM || s->type == SOCK_STREAM)\r
-        {\r
-            ObDereferenceObject(s->addressFileObject);\r
-            if (s->addressHandle != (HANDLE) -1)\r
-            {\r
-                ZwClose(s->addressHandle);\r
-            }\r
-        }\r
-    }\r
-\r
-    ExFreePool(s);\r
-\r
-    return 0;\r
-}\r
-\r
-int __cdecl connect(int socket, const struct sockaddr *addr, int addrlen)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-    const struct sockaddr_in* remoteAddr = (const struct sockaddr_in*) addr;\r
-    UNICODE_STRING devName;\r
-    NTSTATUS status;\r
-\r
-    if (addr == NULL || addrlen < sizeof(struct sockaddr_in))\r
-    {\r
-        return -1;\r
-    }\r
-\r
-    if (!s->isBound)\r
-    {\r
-        struct sockaddr_in localAddr;\r
-\r
-        localAddr.sin_family = AF_INET;\r
-        localAddr.sin_port = 0;\r
-        localAddr.sin_addr.s_addr = INADDR_ANY;\r
-\r
-        status = bind(socket, (struct sockaddr*) &localAddr, sizeof(localAddr));\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            return status;\r
-        }\r
-    }\r
-\r
-    if (s->type == SOCK_STREAM)\r
-    {\r
-        if (s->isConnected || s->isListening)\r
-        {\r
-            return -1;\r
-        }\r
-\r
-        if (!s->streamSocket)\r
-        {\r
-            s->streamSocket = (PSTREAM_SOCKET) ExAllocatePool(NonPagedPool, sizeof(STREAM_SOCKET));\r
-\r
-            if (!s->streamSocket)\r
-            {\r
-                return STATUS_INSUFFICIENT_RESOURCES;\r
-            }\r
-\r
-            RtlZeroMemory(s->streamSocket, sizeof(STREAM_SOCKET));\r
-            s->streamSocket->connectionHandle = (HANDLE) -1;\r
-            KeInitializeEvent(&s->streamSocket->disconnectEvent, NotificationEvent, FALSE);\r
-        }\r
-\r
-        RtlInitUnicodeString(&devName, L"\\Device\\Tcp");\r
-\r
-        status = tdi_open_connection_endpoint(\r
-            &devName,\r
-            s->streamSocket,\r
-            s->isShared,\r
-            &s->streamSocket->connectionHandle,\r
-            &s->streamSocket->connectionFileObject\r
-            );\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            s->streamSocket->connectionFileObject = NULL;\r
-            s->streamSocket->connectionHandle = (HANDLE) -1;\r
-            return status;\r
-        }\r
-\r
-        status = tdi_associate_address(s->streamSocket->connectionFileObject, s->addressHandle);\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            ObDereferenceObject(s->streamSocket->connectionFileObject);\r
-            s->streamSocket->connectionFileObject = NULL;\r
-            ZwClose(s->streamSocket->connectionHandle);\r
-            s->streamSocket->connectionHandle = (HANDLE) -1;\r
-            return status;\r
-        }\r
-\r
-        status = tdi_connect(\r
-            s->streamSocket->connectionFileObject,\r
-            remoteAddr->sin_addr.s_addr,\r
-            remoteAddr->sin_port\r
-            );\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            tdi_disassociate_address(s->streamSocket->connectionFileObject);\r
-            ObDereferenceObject(s->streamSocket->connectionFileObject);\r
-            s->streamSocket->connectionFileObject = NULL;\r
-            ZwClose(s->streamSocket->connectionHandle);\r
-            s->streamSocket->connectionHandle = (HANDLE) -1;\r
-            return status;\r
-        }\r
-        else\r
-        {\r
-            s->peer = *addr;\r
-            s->isConnected = TRUE;\r
-            return 0;\r
-        }\r
-    }\r
-    else if (s->type == SOCK_DGRAM)\r
-    {\r
-        s->peer = *addr;\r
-        if (remoteAddr->sin_addr.s_addr == 0 && remoteAddr->sin_port == 0)\r
-        {\r
-            s->isConnected = FALSE;\r
-        }\r
-        else\r
-        {\r
-            s->isConnected = TRUE;\r
-        }\r
-        return 0;\r
-    }\r
-    else\r
-    {\r
-        return -1;\r
-    }\r
-}\r
-\r
-int __cdecl getpeername(int socket, struct sockaddr *addr, int *addrlen)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-\r
-    if (!s->isConnected || addr == NULL || addrlen == NULL || *addrlen < sizeof(struct sockaddr_in))\r
-    {\r
-        return -1;\r
-    }\r
-\r
-    *addr = s->peer;\r
-    *addrlen = sizeof(s->peer);\r
-\r
-    return 0;\r
-}\r
-\r
-int __cdecl getsockname(int socket, struct sockaddr *addr, int *addrlen)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-    struct sockaddr_in* localAddr = (struct sockaddr_in*) addr;\r
-\r
-    if (!s->isBound || addr == NULL || addrlen == NULL || *addrlen < sizeof(struct sockaddr_in))\r
-    {\r
-        return -1;\r
-    }\r
-\r
-    if (s->type == SOCK_DGRAM)\r
-    {\r
-        *addrlen = sizeof(struct sockaddr_in);\r
-\r
-        return tdi_query_address(\r
-            s->addressFileObject,\r
-            &localAddr->sin_addr.s_addr,\r
-            &localAddr->sin_port\r
-            );\r
-    }\r
-    else if (s->type == SOCK_STREAM)\r
-    {\r
-        *addrlen = sizeof(struct sockaddr_in);\r
-\r
-        return tdi_query_address(\r
-            s->streamSocket && s->streamSocket->connectionFileObject ? s->streamSocket->connectionFileObject : s->addressFileObject,\r
-            &localAddr->sin_addr.s_addr,\r
-            &localAddr->sin_port\r
-            );\r
-    }\r
-    else\r
-    {\r
-        return -1;\r
-    }\r
-}\r
-\r
-int __cdecl getsockopt(int socket, int level, int optname, char *optval, int *optlen)\r
-{\r
-    return -1;\r
-}\r
-\r
-int __cdecl listen(int socket, int backlog)\r
-{\r
-    return -1;\r
-}\r
-\r
-int __cdecl recv(int socket, char *buf, int len, int flags)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-\r
-    if (s->type == SOCK_DGRAM)\r
-    {\r
-        return recvfrom(socket, buf, len, flags, 0, 0);\r
-    }\r
-    else if (s->type == SOCK_STREAM)\r
-    {\r
-        if (!s->isConnected)\r
-        {\r
-            return -1;\r
-        }\r
-\r
-        return tdi_recv_stream(\r
-            s->streamSocket->connectionFileObject,\r
-            buf,\r
-            len,\r
-            flags == MSG_OOB ? TDI_RECEIVE_EXPEDITED : TDI_RECEIVE_NORMAL\r
-            );\r
-    }\r
-    else\r
-    {\r
-        return -1;\r
-    }\r
-}\r
-\r
-int __cdecl recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-    struct sockaddr_in* returnAddr = (struct sockaddr_in*) addr;\r
-\r
-    if (s->type == SOCK_STREAM)\r
-    {\r
-        return recv(socket, buf, len, flags);\r
-    }\r
-    else if (s->type == SOCK_DGRAM)\r
-    {\r
-        u_long* sin_addr = 0;\r
-        u_short* sin_port = 0;\r
-\r
-        if (!s->isBound)\r
-        {\r
-            return -1;\r
-        }\r
-\r
-        if (addr != NULL && addrlen != NULL && *addrlen >= sizeof(struct sockaddr_in))\r
-        {\r
-            sin_addr = &returnAddr->sin_addr.s_addr;\r
-            sin_port = &returnAddr->sin_port;\r
-            *addrlen = sizeof(struct sockaddr_in);\r
-        }\r
-\r
-        return tdi_recv_dgram(\r
-            s->addressFileObject,\r
-            sin_addr,\r
-            sin_port,\r
-            buf,\r
-            len,\r
-            TDI_RECEIVE_NORMAL\r
-            );\r
-    }\r
-    else\r
-    {\r
-        return -1;\r
-    }\r
-}\r
-\r
-int __cdecl select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout)\r
-{\r
-    return -1;\r
-}\r
-\r
-int __cdecl send(int socket, const char *buf, int len, int flags)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-\r
-    if (!s->isConnected)\r
-    {\r
-        return -1;\r
-    }\r
-\r
-    if (s->type == SOCK_DGRAM)\r
-    {\r
-        return sendto(socket, buf, len, flags, &s->peer, sizeof(s->peer));\r
-    }\r
-    else if (s->type == SOCK_STREAM)\r
-    {\r
-        return tdi_send_stream(\r
-            s->streamSocket->connectionFileObject,\r
-            buf,\r
-            len,\r
-            flags == MSG_OOB ? TDI_SEND_EXPEDITED : 0\r
-            );\r
-    }\r
-    else\r
-    {\r
-        return -1;\r
-    }\r
-}\r
-\r
-int __cdecl sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-    const struct sockaddr_in* remoteAddr = (const struct sockaddr_in*) addr;\r
-\r
-    if (s->type == SOCK_STREAM)\r
-    {\r
-        return send(socket, buf, len, flags);\r
-    }\r
-    else if (s->type == SOCK_DGRAM)\r
-    {\r
-        if (addr == NULL || addrlen < sizeof(struct sockaddr_in))\r
-        {\r
-            return -1;\r
-        }\r
-\r
-        if (!s->isBound)\r
-        {\r
-            struct sockaddr_in localAddr;\r
-            NTSTATUS status;\r
-\r
-            localAddr.sin_family = AF_INET;\r
-            localAddr.sin_port = 0;\r
-            localAddr.sin_addr.s_addr = INADDR_ANY;\r
-\r
-            status = bind(socket, (struct sockaddr*) &localAddr, sizeof(localAddr));\r
-\r
-            if (!NT_SUCCESS(status))\r
-            {\r
-                return status;\r
-            }\r
-        }\r
-\r
-        return tdi_send_dgram(\r
-            s->addressFileObject,\r
-            remoteAddr->sin_addr.s_addr,\r
-            remoteAddr->sin_port,\r
-            buf,\r
-            len\r
-            );\r
-    }\r
-    else\r
-    {\r
-        return -1;\r
-    }\r
-}\r
-\r
-int __cdecl setsockopt(int socket, int level, int optname, const char *optval, int optlen)\r
-{\r
-    return -1;\r
-}\r
-\r
-int __cdecl shutdown(int socket, int how)\r
-{\r
-    PSOCKET s = (PSOCKET) -socket;\r
-\r
-    if (!s->isConnected)\r
-    {\r
-        return -1;\r
-    }\r
-\r
-    if (s->type == SOCK_STREAM)\r
-    {\r
-        s->isShuttingdown = TRUE;\r
-        return tdi_disconnect(s->streamSocket->connectionFileObject, TDI_DISCONNECT_RELEASE);\r
-    }\r
-    else\r
-    {\r
-        return -1;\r
-    }\r
-}\r
-\r
-int __cdecl socket(int af, int type, int protocol)\r
-{\r
-    PSOCKET s;\r
-\r
-    if (af != AF_INET ||\r
-       (type != SOCK_DGRAM && type != SOCK_STREAM) ||\r
-       (type == SOCK_DGRAM && protocol != IPPROTO_UDP && protocol != 0) ||\r
-       (type == SOCK_STREAM && protocol != IPPROTO_TCP && protocol != 0)\r
-       )\r
-    {\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    s = (PSOCKET) ExAllocatePool(NonPagedPool, sizeof(SOCKET));\r
-\r
-    if (!s)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    RtlZeroMemory(s, sizeof(SOCKET));\r
-\r
-    s->type = type;\r
-    s->addressHandle = (HANDLE) -1;\r
-\r
-    return -(int)s;\r
-}\r
+/*
+    HTTP Virtual Disk.
+    Copyright (C) 2006 Bo Brantén.
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <ntddk.h>
+#include <tdikrnl.h>
+#include "ktdi.h"
+#include "ksocket.h"
+
+typedef struct _STREAM_SOCKET {
+    HANDLE              connectionHandle;
+    PFILE_OBJECT        connectionFileObject;
+    KEVENT              disconnectEvent;
+} STREAM_SOCKET, *PSTREAM_SOCKET;
+
+typedef struct _SOCKET {
+    int                 type;
+    BOOLEAN             isBound;
+    BOOLEAN             isConnected;
+    BOOLEAN             isListening;
+    BOOLEAN             isShuttingdown;
+    BOOLEAN             isShared;
+    HANDLE              addressHandle;
+    PFILE_OBJECT        addressFileObject;
+    PSTREAM_SOCKET      streamSocket;
+    struct sockaddr     peer;
+} SOCKET, *PSOCKET;
+
+NTSTATUS event_disconnect(PVOID TdiEventContext, CONNECTION_CONTEXT ConnectionContext, LONG DisconnectDataLength,
+                          PVOID DisconnectData, LONG DisconnectInformationLength, PVOID DisconnectInformation,
+                          ULONG DisconnectFlags)
+{
+    PSOCKET s = (PSOCKET) TdiEventContext;
+    PSTREAM_SOCKET streamSocket = (PSTREAM_SOCKET) ConnectionContext;
+    KeSetEvent(&streamSocket->disconnectEvent, 0, FALSE);
+    return STATUS_SUCCESS;
+}
+
+int __cdecl accept(int socket, struct sockaddr *addr, int *addrlen)
+{
+    return -1;
+}
+
+int __cdecl bind(int socket, const struct sockaddr *addr, int addrlen)
+{
+    PSOCKET s = (PSOCKET) -socket;
+    const struct sockaddr_in* localAddr = (const struct sockaddr_in*) addr;
+    UNICODE_STRING devName;
+    NTSTATUS status;
+
+    if (s->isBound || addr == NULL || addrlen < sizeof(struct sockaddr_in))
+    {
+        return -1;
+    }
+
+    if (s->type == SOCK_DGRAM)
+    {
+        RtlInitUnicodeString(&devName, L"\\Device\\Udp");
+    }
+    else if (s->type == SOCK_STREAM)
+    {
+        RtlInitUnicodeString(&devName, L"\\Device\\Tcp");
+    }
+    else
+    {
+        return -1;
+    }
+
+    status = tdi_open_transport_address(
+        &devName,
+        localAddr->sin_addr.s_addr,
+        localAddr->sin_port,
+        s->isShared,
+        &s->addressHandle,
+        &s->addressFileObject
+        );
+
+    if (!NT_SUCCESS(status))
+    {
+        s->addressFileObject = NULL;
+        s->addressHandle = (HANDLE) -1;
+        return status;
+    }
+
+    if (s->type == SOCK_STREAM)
+    {
+        tdi_set_event_handler(s->addressFileObject, TDI_EVENT_DISCONNECT, event_disconnect, s);
+    }
+
+    s->isBound = TRUE;
+
+    return 0;
+}
+
+int __cdecl close(int socket)
+{
+    PSOCKET s = (PSOCKET) -socket;
+
+    if (s->isBound)
+    {
+        if (s->type == SOCK_STREAM && s->streamSocket)
+        {
+            if (s->isConnected)
+            {
+                if (!s->isShuttingdown)
+                {
+                    tdi_disconnect(s->streamSocket->connectionFileObject, TDI_DISCONNECT_RELEASE);
+                }
+                //KeWaitForSingleObject(&s->streamSocket->disconnectEvent, Executive, KernelMode, FALSE, NULL);
+            }
+            if (s->streamSocket->connectionFileObject)
+            {
+                tdi_disassociate_address(s->streamSocket->connectionFileObject);
+                ObDereferenceObject(s->streamSocket->connectionFileObject);
+            }
+            if (s->streamSocket->connectionHandle != (HANDLE) -1)
+            {
+                ZwClose(s->streamSocket->connectionHandle);
+            }
+            ExFreePool(s->streamSocket);
+        }
+
+        if (s->type == SOCK_DGRAM || s->type == SOCK_STREAM)
+        {
+            ObDereferenceObject(s->addressFileObject);
+            if (s->addressHandle != (HANDLE) -1)
+            {
+                ZwClose(s->addressHandle);
+            }
+        }
+    }
+
+    ExFreePool(s);
+
+    return 0;
+}
+
+int __cdecl connect(int socket, const struct sockaddr *addr, int addrlen)
+{
+    PSOCKET s = (PSOCKET) -socket;
+    const struct sockaddr_in* remoteAddr = (const struct sockaddr_in*) addr;
+    UNICODE_STRING devName;
+    NTSTATUS status;
+
+    if (addr == NULL || addrlen < sizeof(struct sockaddr_in))
+    {
+        return -1;
+    }
+
+    if (!s->isBound)
+    {
+        struct sockaddr_in localAddr;
+
+        localAddr.sin_family = AF_INET;
+        localAddr.sin_port = 0;
+        localAddr.sin_addr.s_addr = INADDR_ANY;
+
+        status = bind(socket, (struct sockaddr*) &localAddr, sizeof(localAddr));
+
+        if (!NT_SUCCESS(status))
+        {
+            return status;
+        }
+    }
+
+    if (s->type == SOCK_STREAM)
+    {
+        if (s->isConnected || s->isListening)
+        {
+            return -1;
+        }
+
+        if (!s->streamSocket)
+        {
+            s->streamSocket = (PSTREAM_SOCKET) ExAllocatePool(NonPagedPool, sizeof(STREAM_SOCKET));
+
+            if (!s->streamSocket)
+            {
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            RtlZeroMemory(s->streamSocket, sizeof(STREAM_SOCKET));
+            s->streamSocket->connectionHandle = (HANDLE) -1;
+            KeInitializeEvent(&s->streamSocket->disconnectEvent, NotificationEvent, FALSE);
+        }
+
+        RtlInitUnicodeString(&devName, L"\\Device\\Tcp");
+
+        status = tdi_open_connection_endpoint(
+            &devName,
+            s->streamSocket,
+            s->isShared,
+            &s->streamSocket->connectionHandle,
+            &s->streamSocket->connectionFileObject
+            );
+
+        if (!NT_SUCCESS(status))
+        {
+            s->streamSocket->connectionFileObject = NULL;
+            s->streamSocket->connectionHandle = (HANDLE) -1;
+            return status;
+        }
+
+        status = tdi_associate_address(s->streamSocket->connectionFileObject, s->addressHandle);
+
+        if (!NT_SUCCESS(status))
+        {
+            ObDereferenceObject(s->streamSocket->connectionFileObject);
+            s->streamSocket->connectionFileObject = NULL;
+            ZwClose(s->streamSocket->connectionHandle);
+            s->streamSocket->connectionHandle = (HANDLE) -1;
+            return status;
+        }
+
+        status = tdi_connect(
+            s->streamSocket->connectionFileObject,
+            remoteAddr->sin_addr.s_addr,
+            remoteAddr->sin_port
+            );
+
+        if (!NT_SUCCESS(status))
+        {
+            tdi_disassociate_address(s->streamSocket->connectionFileObject);
+            ObDereferenceObject(s->streamSocket->connectionFileObject);
+            s->streamSocket->connectionFileObject = NULL;
+            ZwClose(s->streamSocket->connectionHandle);
+            s->streamSocket->connectionHandle = (HANDLE) -1;
+            return status;
+        }
+        else
+        {
+            s->peer = *addr;
+            s->isConnected = TRUE;
+            return 0;
+        }
+    }
+    else if (s->type == SOCK_DGRAM)
+    {
+        s->peer = *addr;
+        if (remoteAddr->sin_addr.s_addr == 0 && remoteAddr->sin_port == 0)
+        {
+            s->isConnected = FALSE;
+        }
+        else
+        {
+            s->isConnected = TRUE;
+        }
+        return 0;
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int __cdecl getpeername(int socket, struct sockaddr *addr, int *addrlen)
+{
+    PSOCKET s = (PSOCKET) -socket;
+
+    if (!s->isConnected || addr == NULL || addrlen == NULL || *addrlen < sizeof(struct sockaddr_in))
+    {
+        return -1;
+    }
+
+    *addr = s->peer;
+    *addrlen = sizeof(s->peer);
+
+    return 0;
+}
+
+int __cdecl getsockname(int socket, struct sockaddr *addr, int *addrlen)
+{
+    PSOCKET s = (PSOCKET) -socket;
+    struct sockaddr_in* localAddr = (struct sockaddr_in*) addr;
+
+    if (!s->isBound || addr == NULL || addrlen == NULL || *addrlen < sizeof(struct sockaddr_in))
+    {
+        return -1;
+    }
+
+    if (s->type == SOCK_DGRAM)
+    {
+        *addrlen = sizeof(struct sockaddr_in);
+
+        return tdi_query_address(
+            s->addressFileObject,
+            &localAddr->sin_addr.s_addr,
+            &localAddr->sin_port
+            );
+    }
+    else if (s->type == SOCK_STREAM)
+    {
+        *addrlen = sizeof(struct sockaddr_in);
+
+        return tdi_query_address(
+            s->streamSocket && s->streamSocket->connectionFileObject ? s->streamSocket->connectionFileObject : s->addressFileObject,
+            &localAddr->sin_addr.s_addr,
+            &localAddr->sin_port
+            );
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int __cdecl getsockopt(int socket, int level, int optname, char *optval, int *optlen)
+{
+    return -1;
+}
+
+int __cdecl listen(int socket, int backlog)
+{
+    return -1;
+}
+
+int __cdecl recv(int socket, char *buf, int len, int flags)
+{
+    PSOCKET s = (PSOCKET) -socket;
+
+    if (s->type == SOCK_DGRAM)
+    {
+        return recvfrom(socket, buf, len, flags, 0, 0);
+    }
+    else if (s->type == SOCK_STREAM)
+    {
+        if (!s->isConnected)
+        {
+            return -1;
+        }
+
+        return tdi_recv_stream(
+            s->streamSocket->connectionFileObject,
+            buf,
+            len,
+            flags == MSG_OOB ? TDI_RECEIVE_EXPEDITED : TDI_RECEIVE_NORMAL
+            );
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int __cdecl recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen)
+{
+    PSOCKET s = (PSOCKET) -socket;
+    struct sockaddr_in* returnAddr = (struct sockaddr_in*) addr;
+
+    if (s->type == SOCK_STREAM)
+    {
+        return recv(socket, buf, len, flags);
+    }
+    else if (s->type == SOCK_DGRAM)
+    {
+        u_long* sin_addr = 0;
+        u_short* sin_port = 0;
+
+        if (!s->isBound)
+        {
+            return -1;
+        }
+
+        if (addr != NULL && addrlen != NULL && *addrlen >= sizeof(struct sockaddr_in))
+        {
+            sin_addr = &returnAddr->sin_addr.s_addr;
+            sin_port = &returnAddr->sin_port;
+            *addrlen = sizeof(struct sockaddr_in);
+        }
+
+        return tdi_recv_dgram(
+            s->addressFileObject,
+            sin_addr,
+            sin_port,
+            buf,
+            len,
+            TDI_RECEIVE_NORMAL
+            );
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int __cdecl select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout)
+{
+    return -1;
+}
+
+int __cdecl send(int socket, const char *buf, int len, int flags)
+{
+    PSOCKET s = (PSOCKET) -socket;
+
+    if (!s->isConnected)
+    {
+        return -1;
+    }
+
+    if (s->type == SOCK_DGRAM)
+    {
+        return sendto(socket, buf, len, flags, &s->peer, sizeof(s->peer));
+    }
+    else if (s->type == SOCK_STREAM)
+    {
+        return tdi_send_stream(
+            s->streamSocket->connectionFileObject,
+            buf,
+            len,
+            flags == MSG_OOB ? TDI_SEND_EXPEDITED : 0
+            );
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int __cdecl sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen)
+{
+    PSOCKET s = (PSOCKET) -socket;
+    const struct sockaddr_in* remoteAddr = (const struct sockaddr_in*) addr;
+
+    if (s->type == SOCK_STREAM)
+    {
+        return send(socket, buf, len, flags);
+    }
+    else if (s->type == SOCK_DGRAM)
+    {
+        if (addr == NULL || addrlen < sizeof(struct sockaddr_in))
+        {
+            return -1;
+        }
+
+        if (!s->isBound)
+        {
+            struct sockaddr_in localAddr;
+            NTSTATUS status;
+
+            localAddr.sin_family = AF_INET;
+            localAddr.sin_port = 0;
+            localAddr.sin_addr.s_addr = INADDR_ANY;
+
+            status = bind(socket, (struct sockaddr*) &localAddr, sizeof(localAddr));
+
+            if (!NT_SUCCESS(status))
+            {
+                return status;
+            }
+        }
+
+        return tdi_send_dgram(
+            s->addressFileObject,
+            remoteAddr->sin_addr.s_addr,
+            remoteAddr->sin_port,
+            buf,
+            len
+            );
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int __cdecl setsockopt(int socket, int level, int optname, const char *optval, int optlen)
+{
+    return -1;
+}
+
+int __cdecl shutdown(int socket, int how)
+{
+    PSOCKET s = (PSOCKET) -socket;
+
+    if (!s->isConnected)
+    {
+        return -1;
+    }
+
+    if (s->type == SOCK_STREAM)
+    {
+        s->isShuttingdown = TRUE;
+        return tdi_disconnect(s->streamSocket->connectionFileObject, TDI_DISCONNECT_RELEASE);
+    }
+    else
+    {
+        return -1;
+    }
+}
+
+int __cdecl socket(int af, int type, int protocol)
+{
+    PSOCKET s;
+
+    if (af != AF_INET ||
+       (type != SOCK_DGRAM && type != SOCK_STREAM) ||
+       (type == SOCK_DGRAM && protocol != IPPROTO_UDP && protocol != 0) ||
+       (type == SOCK_STREAM && protocol != IPPROTO_TCP && protocol != 0)
+       )
+    {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    s = (PSOCKET) ExAllocatePool(NonPagedPool, sizeof(SOCKET));
+
+    if (!s)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(s, sizeof(SOCKET));
+
+    s->type = type;
+    s->addressHandle = (HANDLE) -1;
+
+    return -(int)s;
+}
index 206c8f0..7c4b00d 100644 (file)
-/*\r
-    HTTP Virtual Disk.\r
-    Copyright (C) 2006 Bo Brantén.\r
-    This program is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-    This program is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-    You should have received a copy of the GNU General Public License\r
-    along with this program; if not, write to the Free Software\r
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-#if !defined(KSOCKET_H)\r
-#define KSOCKET_H\r
-\r
-#if defined(__cplusplus)\r
-extern "C" {\r
-#endif\r
-\r
-typedef unsigned char   u_char;\r
-typedef unsigned short  u_short;\r
-typedef unsigned int    u_int;\r
-typedef unsigned long   u_long;\r
-\r
-#define AF_INET             2\r
-\r
-#define SOCK_STREAM         1\r
-#define SOCK_DGRAM          2\r
-#define SOCK_RAW            3\r
-\r
-#define IPPROTO_ICMP        1\r
-#define IPPROTO_TCP         6\r
-#define IPPROTO_UDP         17\r
-\r
-#define INADDR_ANY          0x00000000\r
-#define INADDR_LOOPBACK     0x7f000001\r
-#define INADDR_BROADCAST    0xffffffff\r
-#define INADDR_NONE         0xffffffff\r
-\r
-#define MSG_OOB             0x1\r
-\r
-#define SOMAXCONN           5\r
-\r
-#define SD_RECEIVE          0x00\r
-#define SD_SEND             0x01\r
-#define SD_BOTH             0x02\r
-\r
-#ifndef FD_SETSIZE\r
-#define FD_SETSIZE          64\r
-#endif\r
-\r
-typedef struct fd_set {\r
-    u_int   fd_count;\r
-    int     fd_array[FD_SETSIZE];\r
-} fd_set;\r
-\r
-struct hostent {\r
-    char    *h_name;\r
-    char    **h_aliases;\r
-    short   h_addrtype;\r
-    short   h_length;\r
-    char    **h_addr_list;\r
-};\r
-\r
-#define h_addr h_addr_list[0]\r
-\r
-struct in_addr {\r
-    union {\r
-        struct { u_char s_b1, s_b2, s_b3, s_b4; }   S_un_b;\r
-        struct { u_short s_w1, s_w2; }              S_un_w;\r
-        u_long                                      S_addr;\r
-    } S_un;\r
-};\r
-\r
-#define s_addr S_un.S_addr\r
-\r
-struct protoent {\r
-    char    *p_name;\r
-    char    **p_aliases;\r
-    short   p_proto;\r
-};\r
-\r
-struct servent {\r
-    char    *s_name;\r
-    char    **s_aliases;\r
-    short   s_port;\r
-    char    *s_proto;\r
-};\r
-\r
-struct sockaddr {\r
-    u_short sa_family;\r
-    char    sa_data[14];\r
-};\r
-\r
-struct sockaddr_in {\r
-    short           sin_family;\r
-    u_short         sin_port;\r
-    struct in_addr  sin_addr;\r
-    char            sin_zero[8];\r
-};\r
-\r
-struct timeval {\r
-    long tv_sec;\r
-    long tv_usec;\r
-};\r
-\r
-int __cdecl accept(int socket, struct sockaddr *addr, int *addrlen);\r
-int __cdecl bind(int socket, const struct sockaddr *addr, int addrlen);\r
-int __cdecl close(int socket);\r
-int __cdecl connect(int socket, const struct sockaddr *addr, int addrlen);\r
-struct hostent * __cdecl gethostbyaddr(const char *addr, int addrlen, int type);\r
-struct hostent * __cdecl gethostbyname(const char *name);\r
-int __cdecl gethostname(char *name, int namelen);\r
-int __cdecl getpeername(int socket, struct sockaddr *addr, int *addrlen);\r
-struct protoent * __cdecl getprotobyname(const char *name);\r
-struct protoent * __cdecl getprotobynumber(int number);\r
-struct servent * __cdecl getservbyname(const char *name, const char *proto);\r
-struct servent * __cdecl getservbyport(int port, const char *proto);\r
-int __cdecl getsockname(int socket, struct sockaddr *addr, int *addrlen);\r
-int __cdecl getsockopt(int socket, int level, int optname, char *optval, int *optlen);\r
-u_long __cdecl htonl(u_long hostlong);\r
-u_short __cdecl htons(u_short hostshort);\r
-u_long __cdecl inet_addr(const char *name);\r
-int __cdecl inet_aton(const char *name, struct in_addr *addr);\r
-char * __cdecl inet_ntoa(struct in_addr addr);\r
-int __cdecl listen(int socket, int backlog);\r
-u_long __cdecl ntohl(u_long netlong);\r
-u_short __cdecl ntohs(u_short netshort);\r
-int __cdecl recv(int socket, char *buf, int len, int flags);\r
-int __cdecl recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen);\r
-int __cdecl select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout);\r
-int __cdecl send(int socket, const char *buf, int len, int flags);\r
-int __cdecl sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen);\r
-int __cdecl setsockopt(int socket, int level, int optname, const char *optval, int optlen);\r
-int __cdecl shutdown(int socket, int how);\r
-int __cdecl socket(int af, int type, int protocol);\r
-\r
-#if defined(__cplusplus)\r
-}\r
-#endif\r
-\r
-#endif // !defined(KSOCKET_H)\r
+/*
+    HTTP Virtual Disk.
+    Copyright (C) 2006 Bo Brantén.
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#if !defined(KSOCKET_H)
+#define KSOCKET_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef unsigned char   u_char;
+typedef unsigned short  u_short;
+typedef unsigned int    u_int;
+typedef unsigned long   u_long;
+
+#define AF_INET             2
+
+#define SOCK_STREAM         1
+#define SOCK_DGRAM          2
+#define SOCK_RAW            3
+
+#define IPPROTO_ICMP        1
+#define IPPROTO_TCP         6
+#define IPPROTO_UDP         17
+
+#define INADDR_ANY          0x00000000
+#define INADDR_LOOPBACK     0x7f000001
+#define INADDR_BROADCAST    0xffffffff
+#define INADDR_NONE         0xffffffff
+
+#define MSG_OOB             0x1
+
+#define SOMAXCONN           5
+
+#define SD_RECEIVE          0x00
+#define SD_SEND             0x01
+#define SD_BOTH             0x02
+
+#ifndef FD_SETSIZE
+#define FD_SETSIZE          64
+#endif
+
+typedef struct fd_set {
+    u_int   fd_count;
+    int     fd_array[FD_SETSIZE];
+} fd_set;
+
+struct hostent {
+    char    *h_name;
+    char    **h_aliases;
+    short   h_addrtype;
+    short   h_length;
+    char    **h_addr_list;
+};
+
+#define h_addr h_addr_list[0]
+
+struct in_addr {
+    union {
+        struct { u_char s_b1, s_b2, s_b3, s_b4; }   S_un_b;
+        struct { u_short s_w1, s_w2; }              S_un_w;
+        u_long                                      S_addr;
+    } S_un;
+};
+
+#define s_addr S_un.S_addr
+
+struct protoent {
+    char    *p_name;
+    char    **p_aliases;
+    short   p_proto;
+};
+
+struct servent {
+    char    *s_name;
+    char    **s_aliases;
+    short   s_port;
+    char    *s_proto;
+};
+
+struct sockaddr {
+    u_short sa_family;
+    char    sa_data[14];
+};
+
+struct sockaddr_in {
+    short           sin_family;
+    u_short         sin_port;
+    struct in_addr  sin_addr;
+    char            sin_zero[8];
+};
+
+struct timeval {
+    long tv_sec;
+    long tv_usec;
+};
+
+int __cdecl accept(int socket, struct sockaddr *addr, int *addrlen);
+int __cdecl bind(int socket, const struct sockaddr *addr, int addrlen);
+int __cdecl close(int socket);
+int __cdecl connect(int socket, const struct sockaddr *addr, int addrlen);
+struct hostent * __cdecl gethostbyaddr(const char *addr, int addrlen, int type);
+struct hostent * __cdecl gethostbyname(const char *name);
+int __cdecl gethostname(char *name, int namelen);
+int __cdecl getpeername(int socket, struct sockaddr *addr, int *addrlen);
+struct protoent * __cdecl getprotobyname(const char *name);
+struct protoent * __cdecl getprotobynumber(int number);
+struct servent * __cdecl getservbyname(const char *name, const char *proto);
+struct servent * __cdecl getservbyport(int port, const char *proto);
+int __cdecl getsockname(int socket, struct sockaddr *addr, int *addrlen);
+int __cdecl getsockopt(int socket, int level, int optname, char *optval, int *optlen);
+u_long __cdecl htonl(u_long hostlong);
+u_short __cdecl htons(u_short hostshort);
+u_long __cdecl inet_addr(const char *name);
+int __cdecl inet_aton(const char *name, struct in_addr *addr);
+char * __cdecl inet_ntoa(struct in_addr addr);
+int __cdecl listen(int socket, int backlog);
+u_long __cdecl ntohl(u_long netlong);
+u_short __cdecl ntohs(u_short netshort);
+int __cdecl recv(int socket, char *buf, int len, int flags);
+int __cdecl recvfrom(int socket, char *buf, int len, int flags, struct sockaddr *addr, int *addrlen);
+int __cdecl select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timeval *timeout);
+int __cdecl send(int socket, const char *buf, int len, int flags);
+int __cdecl sendto(int socket, const char *buf, int len, int flags, const struct sockaddr *addr, int addrlen);
+int __cdecl setsockopt(int socket, int level, int optname, const char *optval, int optlen);
+int __cdecl shutdown(int socket, int how);
+int __cdecl socket(int af, int type, int protocol);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // !defined(KSOCKET_H)
index 4c5ee20..606bee8 100644 (file)
-/*\r
-    HTTP Virtual Disk.\r
-    Copyright (C) 2006 Bo Brantén.\r
-    This program is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-    This program is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-    You should have received a copy of the GNU General Public License\r
-    along with this program; if not, write to the Free Software\r
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-#include <ntddk.h>\r
-#include <tdikrnl.h>\r
-#include "ktdi.h"\r
-\r
-NTSTATUS tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, BOOLEAN shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject)\r
-{\r
-    OBJECT_ATTRIBUTES           attr;\r
-    PFILE_FULL_EA_INFORMATION   eaBuffer;\r
-    ULONG                       eaSize;\r
-    PTA_IP_ADDRESS              localAddr;\r
-    IO_STATUS_BLOCK             iosb;\r
-    NTSTATUS                    status;\r
-\r
-#if (VER_PRODUCTBUILD >= 2195)\r
-    InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\r
-#else\r
-    InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE, NULL, NULL);\r
-#endif\r
-\r
-    eaSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +\r
-             TDI_TRANSPORT_ADDRESS_LENGTH                      +\r
-             1                                                 +\r
-             sizeof(TA_IP_ADDRESS);\r
-\r
-    eaBuffer = (PFILE_FULL_EA_INFORMATION) ExAllocatePool(PagedPool, eaSize);\r
-\r
-    if (eaBuffer == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    eaBuffer->NextEntryOffset = 0;\r
-    eaBuffer->Flags = 0;\r
-    eaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;\r
-    eaBuffer->EaValueLength = sizeof(TA_IP_ADDRESS);\r
-\r
-    RtlCopyMemory(eaBuffer->EaName, TdiTransportAddress, eaBuffer->EaNameLength + 1);\r
-\r
-    localAddr = (PTA_IP_ADDRESS)(eaBuffer->EaName + eaBuffer->EaNameLength + 1);\r
-\r
-    localAddr->TAAddressCount = 1;\r
-    localAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;\r
-    localAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;\r
-    localAddr->Address[0].Address[0].sin_port = port;\r
-    localAddr->Address[0].Address[0].in_addr = addr;\r
-\r
-    RtlZeroMemory(localAddr->Address[0].Address[0].sin_zero, sizeof(localAddr->Address[0].Address[0].sin_zero));\r
-\r
-    status = ZwCreateFile(\r
-        addressHandle,\r
-        GENERIC_READ | GENERIC_WRITE,\r
-        &attr,\r
-        &iosb,\r
-        NULL,\r
-        FILE_ATTRIBUTE_NORMAL,\r
-        shared ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,\r
-        FILE_OPEN,\r
-        0,\r
-        eaBuffer,\r
-        eaSize\r
-        );\r
-\r
-    ExFreePool(eaBuffer);\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        return status;\r
-    }\r
-\r
-    status = ObReferenceObjectByHandle(*addressHandle, FILE_ALL_ACCESS, NULL, KernelMode, addressFileObject, NULL);\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        ZwClose(*addressHandle);\r
-        return status;\r
-    }\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS tdi_open_connection_endpoint(PUNICODE_STRING devName, PVOID connectionContext, BOOLEAN shared, PHANDLE connectionHandle, PFILE_OBJECT *connectionFileObject)\r
-{\r
-    OBJECT_ATTRIBUTES           attr;\r
-    PFILE_FULL_EA_INFORMATION   eaBuffer;\r
-    ULONG                       eaSize;\r
-    PVOID                       *context;\r
-    IO_STATUS_BLOCK             iosb;\r
-    NTSTATUS                    status;\r
-\r
-#if (VER_PRODUCTBUILD >= 2195)\r
-    InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);\r
-#else\r
-    InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE, NULL, NULL);\r
-#endif\r
-\r
-    eaSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +\r
-             TDI_CONNECTION_CONTEXT_LENGTH                     +\r
-             1                                                 +\r
-             sizeof(int);\r
-\r
-    eaBuffer = (PFILE_FULL_EA_INFORMATION) ExAllocatePool(PagedPool, eaSize);\r
-\r
-    if (eaBuffer == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    eaBuffer->NextEntryOffset = 0;\r
-    eaBuffer->Flags = 0;\r
-    eaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;\r
-    eaBuffer->EaValueLength = sizeof(int);\r
-\r
-    RtlCopyMemory(eaBuffer->EaName, TdiConnectionContext, eaBuffer->EaNameLength + 1);\r
-\r
-    context = (PVOID*) &(eaBuffer->EaName[eaBuffer->EaNameLength + 1]);\r
-\r
-    *context = connectionContext;\r
-\r
-    status = ZwCreateFile(\r
-        connectionHandle,\r
-        GENERIC_READ | GENERIC_WRITE,\r
-        &attr,\r
-        &iosb,\r
-        NULL,\r
-        FILE_ATTRIBUTE_NORMAL,\r
-        shared ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,\r
-        FILE_OPEN,\r
-        0,\r
-        eaBuffer,\r
-        eaSize\r
-        );\r
-\r
-    ExFreePool(eaBuffer);\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        return status;\r
-    }\r
-\r
-    status = ObReferenceObjectByHandle(*connectionHandle, FILE_ALL_ACCESS, NULL, KernelMode, connectionFileObject, NULL);\r
-\r
-    if (!NT_SUCCESS(status))\r
-    {\r
-        ZwClose(*connectionHandle);\r
-        return status;\r
-    }\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-NTSTATUS tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext)\r
-{\r
-    PDEVICE_OBJECT  devObj;\r
-    KEVENT          event;\r
-    PIRP            irp;\r
-    IO_STATUS_BLOCK iosb;\r
-    NTSTATUS        status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(addressFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, devObj, addressFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    TdiBuildSetEventHandler(irp, devObj, addressFileObject, NULL, NULL, eventType, eventHandler, eventContext);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    return status;\r
-}\r
-\r
-NTSTATUS tdi_unset_event_handler(PFILE_OBJECT addressFileObject, LONG eventType)\r
-{\r
-    return tdi_set_event_handler(addressFileObject, eventType, NULL, NULL);\r
-}\r
-\r
-NTSTATUS tdi_associate_address(PFILE_OBJECT connectionFileObject, HANDLE addressHandle)\r
-{\r
-    PDEVICE_OBJECT  devObj;\r
-    KEVENT          event;\r
-    PIRP            irp;\r
-    IO_STATUS_BLOCK iosb;\r
-    NTSTATUS        status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(connectionFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_ASSOCIATE_ADDRESS, devObj, connectionFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    TdiBuildAssociateAddress(irp, devObj, connectionFileObject, NULL, NULL, addressHandle);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    return status;\r
-}\r
-\r
-NTSTATUS tdi_disassociate_address(PFILE_OBJECT connectionFileObject)\r
-{\r
-    PDEVICE_OBJECT  devObj;\r
-    KEVENT          event;\r
-    PIRP            irp;\r
-    IO_STATUS_BLOCK iosb;\r
-    NTSTATUS        status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(connectionFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_DISASSOCIATE_ADDRESS, devObj, connectionFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    TdiBuildDisassociateAddress(irp, devObj, connectionFileObject, NULL, NULL);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    return status;\r
-}\r
-\r
-NTSTATUS tdi_connect(PFILE_OBJECT connectionFileObject, ULONG addr, USHORT port)\r
-{\r
-    PDEVICE_OBJECT              devObj;\r
-    KEVENT                      event;\r
-    PTDI_CONNECTION_INFORMATION remoteInfo;\r
-    PTA_IP_ADDRESS              remoteAddr;\r
-    PTDI_CONNECTION_INFORMATION returnInfo;\r
-    PTA_IP_ADDRESS              returnAddr;\r
-    PIRP                        irp;\r
-    IO_STATUS_BLOCK             iosb;\r
-    NTSTATUS                    status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(connectionFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, 2 * sizeof(TDI_CONNECTION_INFORMATION) + 2 * sizeof(TA_IP_ADDRESS));\r
-\r
-    if (remoteInfo == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    RtlZeroMemory(remoteInfo, 2 * sizeof(TDI_CONNECTION_INFORMATION) + 2 * sizeof(TA_IP_ADDRESS));\r
-\r
-    remoteInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);\r
-    remoteInfo->RemoteAddress = (PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION);\r
-\r
-    remoteAddr = (PTA_IP_ADDRESS) remoteInfo->RemoteAddress;\r
-\r
-    remoteAddr->TAAddressCount = 1;\r
-    remoteAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;\r
-    remoteAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;\r
-    remoteAddr->Address[0].Address[0].sin_port = port;\r
-    remoteAddr->Address[0].Address[0].in_addr = addr;\r
-\r
-    returnInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));\r
-\r
-    returnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);\r
-    returnInfo->RemoteAddress = (PUCHAR)returnInfo + sizeof(TDI_CONNECTION_INFORMATION);\r
-\r
-    returnAddr = (PTA_IP_ADDRESS) returnInfo->RemoteAddress;\r
-\r
-    returnAddr->TAAddressCount = 1;\r
-    returnAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;\r
-    returnAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT, devObj, connectionFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        ExFreePool(remoteInfo);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    TdiBuildConnect(irp, devObj, connectionFileObject, NULL, NULL, NULL, remoteInfo, returnInfo);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    ExFreePool(remoteInfo);\r
-\r
-    return status;\r
-}\r
-\r
-NTSTATUS tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags)\r
-{\r
-    PDEVICE_OBJECT  devObj;\r
-    KEVENT          event;\r
-    PIRP            irp;\r
-    IO_STATUS_BLOCK iosb;\r
-    NTSTATUS        status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(connectionFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_DISCONNECT, devObj, connectionFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    TdiBuildDisconnect(irp, devObj, connectionFileObject, NULL, NULL, NULL, flags, NULL, NULL);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    return status;\r
-}\r
-\r
-NTSTATUS tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len)\r
-{\r
-    PDEVICE_OBJECT              devObj;\r
-    KEVENT                      event;\r
-    PTDI_CONNECTION_INFORMATION remoteInfo;\r
-    PTA_IP_ADDRESS              remoteAddr;\r
-    PIRP                        irp;\r
-    PMDL                        mdl;\r
-    IO_STATUS_BLOCK             iosb;\r
-    NTSTATUS                    status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(addressFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));\r
-\r
-    if (remoteInfo == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    RtlZeroMemory(remoteInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));\r
-\r
-    remoteInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);\r
-    remoteInfo->RemoteAddress = (PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION);\r
-\r
-    remoteAddr = (PTA_IP_ADDRESS) remoteInfo->RemoteAddress;\r
-\r
-    remoteAddr->TAAddressCount = 1;\r
-    remoteAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;\r
-    remoteAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;\r
-    remoteAddr->Address[0].Address[0].sin_port = port;\r
-    remoteAddr->Address[0].Address[0].in_addr = addr;\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, devObj, addressFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        ExFreePool(remoteInfo);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    if (len)\r
-    {\r
-        mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);\r
-\r
-        if (mdl == NULL)\r
-        {\r
-            IoFreeIrp(irp);\r
-            ExFreePool(remoteInfo);\r
-            return STATUS_INSUFFICIENT_RESOURCES;\r
-        }\r
-\r
-        __try\r
-        {\r
-            MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);\r
-            status = STATUS_SUCCESS;\r
-        }\r
-        __except (EXCEPTION_EXECUTE_HANDLER)\r
-        {\r
-            IoFreeMdl(mdl);\r
-            IoFreeIrp(irp);\r
-            ExFreePool(remoteInfo);\r
-            status = STATUS_INVALID_USER_BUFFER;\r
-        }\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            return status;\r
-        }\r
-    }\r
-\r
-    TdiBuildSendDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    ExFreePool(remoteInfo);\r
-\r
-    return NT_SUCCESS(status) ? iosb.Information : status;\r
-}\r
-\r
-NTSTATUS tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags)\r
-{\r
-    PDEVICE_OBJECT              devObj;\r
-    KEVENT                      event;\r
-    PTDI_CONNECTION_INFORMATION remoteInfo;\r
-    PTDI_CONNECTION_INFORMATION returnInfo;\r
-    PTA_IP_ADDRESS              returnAddr;\r
-    PIRP                        irp;\r
-    PMDL                        mdl;\r
-    IO_STATUS_BLOCK             iosb;\r
-    NTSTATUS                    status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(addressFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));\r
-\r
-    if (remoteInfo == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    RtlZeroMemory(remoteInfo, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));\r
-\r
-    remoteInfo->RemoteAddressLength = 0;\r
-    remoteInfo->RemoteAddress = NULL;\r
-\r
-    returnInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION));\r
-\r
-    returnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);\r
-    returnInfo->RemoteAddress = (PUCHAR)returnInfo + sizeof(TDI_CONNECTION_INFORMATION);\r
-\r
-    returnAddr = (PTA_IP_ADDRESS) returnInfo->RemoteAddress;\r
-\r
-    returnAddr->TAAddressCount = 1;\r
-    returnAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;\r
-    returnAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, devObj, addressFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        ExFreePool(remoteInfo);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    if (len)\r
-    {\r
-        mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);\r
-\r
-        if (mdl == NULL)\r
-        {\r
-            IoFreeIrp(irp);\r
-            ExFreePool(remoteInfo);\r
-            return STATUS_INSUFFICIENT_RESOURCES;\r
-        }\r
-\r
-        __try\r
-        {\r
-            MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);\r
-            status = STATUS_SUCCESS;\r
-        }\r
-        __except (EXCEPTION_EXECUTE_HANDLER)\r
-        {\r
-            IoFreeMdl(mdl);\r
-            IoFreeIrp(irp);\r
-            ExFreePool(remoteInfo);\r
-            status = STATUS_INVALID_USER_BUFFER;\r
-        }\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            return status;\r
-        }\r
-    }\r
-\r
-    TdiBuildReceiveDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo, returnInfo, flags);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    if (addr)\r
-    {\r
-        *addr = returnAddr->Address[0].Address[0].in_addr;\r
-    }\r
-\r
-    if (port)\r
-    {\r
-        *port = returnAddr->Address[0].Address[0].sin_port;\r
-    }\r
-\r
-    ExFreePool(remoteInfo);\r
-\r
-    return NT_SUCCESS(status) ? iosb.Information : status;\r
-}\r
-\r
-NTSTATUS tdi_send_stream(PFILE_OBJECT connectionFileObject, const char *buf, int len, ULONG flags)\r
-{\r
-    PDEVICE_OBJECT  devObj;\r
-    KEVENT          event;\r
-    PIRP            irp;\r
-    PMDL            mdl;\r
-    IO_STATUS_BLOCK iosb;\r
-    NTSTATUS        status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(connectionFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_SEND, devObj, connectionFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    if (len)\r
-    {\r
-        mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);\r
-\r
-        if (mdl == NULL)\r
-        {\r
-            IoFreeIrp(irp);\r
-            return STATUS_INSUFFICIENT_RESOURCES;\r
-        }\r
-\r
-        __try\r
-        {\r
-            MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);\r
-            status = STATUS_SUCCESS;\r
-        }\r
-        __except (EXCEPTION_EXECUTE_HANDLER)\r
-        {\r
-            IoFreeMdl(mdl);\r
-            IoFreeIrp(irp);\r
-            status = STATUS_INVALID_USER_BUFFER;\r
-        }\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            return status;\r
-        }\r
-    }\r
-\r
-    TdiBuildSend(irp, devObj, connectionFileObject, NULL, NULL, len ? mdl : 0, flags, len);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    return NT_SUCCESS(status) ? iosb.Information : status;\r
-}\r
-\r
-NTSTATUS tdi_recv_stream(PFILE_OBJECT connectionFileObject, char *buf, int len, ULONG flags)\r
-{\r
-    PDEVICE_OBJECT  devObj;\r
-    KEVENT          event;\r
-    PIRP            irp;\r
-    PMDL            mdl;\r
-    IO_STATUS_BLOCK iosb;\r
-    NTSTATUS        status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(connectionFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE, devObj, connectionFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    if (len)\r
-    {\r
-        mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);\r
-\r
-        if (mdl == NULL)\r
-        {\r
-            IoFreeIrp(irp);\r
-            return STATUS_INSUFFICIENT_RESOURCES;\r
-        }\r
-\r
-        __try\r
-        {\r
-            MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);\r
-            status = STATUS_SUCCESS;\r
-        }\r
-        __except (EXCEPTION_EXECUTE_HANDLER)\r
-        {\r
-            IoFreeMdl(mdl);\r
-            IoFreeIrp(irp);\r
-            status = STATUS_INVALID_USER_BUFFER;\r
-        }\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            return status;\r
-        }\r
-    }\r
-\r
-    TdiBuildReceive(irp, devObj, connectionFileObject, NULL, NULL, len ? mdl : 0, flags, len);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    return NT_SUCCESS(status) ? iosb.Information : status;\r
-}\r
-\r
-NTSTATUS tdi_query_address(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port)\r
-{\r
-    PDEVICE_OBJECT              devObj;\r
-    KEVENT                      event;\r
-    PTRANSPORT_ADDRESS          localInfo;\r
-    PTA_IP_ADDRESS              localAddr;\r
-    PIRP                        irp;\r
-    PMDL                        mdl;\r
-    IO_STATUS_BLOCK             iosb;\r
-    NTSTATUS                    status;\r
-\r
-    devObj = IoGetRelatedDeviceObject(addressFileObject);\r
-\r
-    KeInitializeEvent(&event, NotificationEvent, FALSE);\r
-\r
-    localInfo = (PTRANSPORT_ADDRESS) ExAllocatePool(NonPagedPool, sizeof(TDI_ADDRESS_INFO)*10);\r
-\r
-    if (localInfo == NULL)\r
-    {\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    RtlZeroMemory(localInfo, sizeof(TDI_ADDRESS_INFO)*10);\r
-\r
-    irp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION, devObj, addressFileObject, &event, &iosb);\r
-\r
-    if (irp == NULL)\r
-    {\r
-        ExFreePool(localInfo);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    {\r
-        mdl = IoAllocateMdl((void*) localInfo, sizeof(TDI_ADDRESS_INFO)*10, FALSE, FALSE, NULL);\r
-\r
-        if (mdl == NULL)\r
-        {\r
-            IoFreeIrp(irp);\r
-            ExFreePool(localInfo);\r
-            return STATUS_INSUFFICIENT_RESOURCES;\r
-        }\r
-\r
-        __try\r
-        {\r
-            MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);\r
-            status = STATUS_SUCCESS;\r
-        }\r
-        __except (EXCEPTION_EXECUTE_HANDLER)\r
-        {\r
-            IoFreeMdl(mdl);\r
-            IoFreeIrp(irp);\r
-            ExFreePool(localInfo);\r
-            status = STATUS_INVALID_USER_BUFFER;\r
-        }\r
-\r
-        if (!NT_SUCCESS(status))\r
-        {\r
-            return status;\r
-        }\r
-    }\r
-\r
-    TdiBuildQueryInformation(irp, devObj, addressFileObject, NULL, NULL, TDI_QUERY_ADDRESS_INFO, mdl);\r
-\r
-    status = IoCallDriver(devObj, irp);\r
-\r
-    if (status == STATUS_PENDING)\r
-    {\r
-        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);\r
-        status = iosb.Status;\r
-    }\r
-\r
-    localAddr = (PTA_IP_ADDRESS)&localInfo->Address[0];\r
-\r
-    if (addr)\r
-    {\r
-        *addr = localAddr->Address[0].Address[0].in_addr;\r
-    }\r
-\r
-    if (port)\r
-    {\r
-        *port = localAddr->Address[0].Address[0].sin_port;\r
-    }\r
-\r
-    ExFreePool(localInfo);\r
-\r
-    return status;\r
-}\r
+/*
+    HTTP Virtual Disk.
+    Copyright (C) 2006 Bo Brantén.
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <ntddk.h>
+#include <tdikrnl.h>
+#include "ktdi.h"
+
+NTSTATUS tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, BOOLEAN shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject)
+{
+    OBJECT_ATTRIBUTES           attr;
+    PFILE_FULL_EA_INFORMATION   eaBuffer;
+    ULONG                       eaSize;
+    PTA_IP_ADDRESS              localAddr;
+    IO_STATUS_BLOCK             iosb;
+    NTSTATUS                    status;
+
+#if (VER_PRODUCTBUILD >= 2195)
+    InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
+#else
+    InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE, NULL, NULL);
+#endif
+
+    eaSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
+             TDI_TRANSPORT_ADDRESS_LENGTH                      +
+             1                                                 +
+             sizeof(TA_IP_ADDRESS);
+
+    eaBuffer = (PFILE_FULL_EA_INFORMATION) ExAllocatePool(PagedPool, eaSize);
+
+    if (eaBuffer == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    eaBuffer->NextEntryOffset = 0;
+    eaBuffer->Flags = 0;
+    eaBuffer->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+    eaBuffer->EaValueLength = sizeof(TA_IP_ADDRESS);
+
+    RtlCopyMemory(eaBuffer->EaName, TdiTransportAddress, eaBuffer->EaNameLength + 1);
+
+    localAddr = (PTA_IP_ADDRESS)(eaBuffer->EaName + eaBuffer->EaNameLength + 1);
+
+    localAddr->TAAddressCount = 1;
+    localAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+    localAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+    localAddr->Address[0].Address[0].sin_port = port;
+    localAddr->Address[0].Address[0].in_addr = addr;
+
+    RtlZeroMemory(localAddr->Address[0].Address[0].sin_zero, sizeof(localAddr->Address[0].Address[0].sin_zero));
+
+    status = ZwCreateFile(
+        addressHandle,
+        GENERIC_READ | GENERIC_WRITE,
+        &attr,
+        &iosb,
+        NULL,
+        FILE_ATTRIBUTE_NORMAL,
+        shared ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
+        FILE_OPEN,
+        0,
+        eaBuffer,
+        eaSize
+        );
+
+    ExFreePool(eaBuffer);
+
+    if (!NT_SUCCESS(status))
+    {
+        return status;
+    }
+
+    status = ObReferenceObjectByHandle(*addressHandle, FILE_ALL_ACCESS, NULL, KernelMode, addressFileObject, NULL);
+
+    if (!NT_SUCCESS(status))
+    {
+        ZwClose(*addressHandle);
+        return status;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS tdi_open_connection_endpoint(PUNICODE_STRING devName, PVOID connectionContext, BOOLEAN shared, PHANDLE connectionHandle, PFILE_OBJECT *connectionFileObject)
+{
+    OBJECT_ATTRIBUTES           attr;
+    PFILE_FULL_EA_INFORMATION   eaBuffer;
+    ULONG                       eaSize;
+    PVOID                       *context;
+    IO_STATUS_BLOCK             iosb;
+    NTSTATUS                    status;
+
+#if (VER_PRODUCTBUILD >= 2195)
+    InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
+#else
+    InitializeObjectAttributes(&attr, devName, OBJ_CASE_INSENSITIVE, NULL, NULL);
+#endif
+
+    eaSize = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
+             TDI_CONNECTION_CONTEXT_LENGTH                     +
+             1                                                 +
+             sizeof(int);
+
+    eaBuffer = (PFILE_FULL_EA_INFORMATION) ExAllocatePool(PagedPool, eaSize);
+
+    if (eaBuffer == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    eaBuffer->NextEntryOffset = 0;
+    eaBuffer->Flags = 0;
+    eaBuffer->EaNameLength = TDI_CONNECTION_CONTEXT_LENGTH;
+    eaBuffer->EaValueLength = sizeof(int);
+
+    RtlCopyMemory(eaBuffer->EaName, TdiConnectionContext, eaBuffer->EaNameLength + 1);
+
+    context = (PVOID*) &(eaBuffer->EaName[eaBuffer->EaNameLength + 1]);
+
+    *context = connectionContext;
+
+    status = ZwCreateFile(
+        connectionHandle,
+        GENERIC_READ | GENERIC_WRITE,
+        &attr,
+        &iosb,
+        NULL,
+        FILE_ATTRIBUTE_NORMAL,
+        shared ? FILE_SHARE_READ | FILE_SHARE_WRITE : 0,
+        FILE_OPEN,
+        0,
+        eaBuffer,
+        eaSize
+        );
+
+    ExFreePool(eaBuffer);
+
+    if (!NT_SUCCESS(status))
+    {
+        return status;
+    }
+
+    status = ObReferenceObjectByHandle(*connectionHandle, FILE_ALL_ACCESS, NULL, KernelMode, connectionFileObject, NULL);
+
+    if (!NT_SUCCESS(status))
+    {
+        ZwClose(*connectionHandle);
+        return status;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext)
+{
+    PDEVICE_OBJECT  devObj;
+    KEVENT          event;
+    PIRP            irp;
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS        status;
+
+    devObj = IoGetRelatedDeviceObject(addressFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_SET_EVENT_HANDLER, devObj, addressFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    TdiBuildSetEventHandler(irp, devObj, addressFileObject, NULL, NULL, eventType, eventHandler, eventContext);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    return status;
+}
+
+NTSTATUS tdi_unset_event_handler(PFILE_OBJECT addressFileObject, LONG eventType)
+{
+    return tdi_set_event_handler(addressFileObject, eventType, NULL, NULL);
+}
+
+NTSTATUS tdi_associate_address(PFILE_OBJECT connectionFileObject, HANDLE addressHandle)
+{
+    PDEVICE_OBJECT  devObj;
+    KEVENT          event;
+    PIRP            irp;
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS        status;
+
+    devObj = IoGetRelatedDeviceObject(connectionFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_ASSOCIATE_ADDRESS, devObj, connectionFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    TdiBuildAssociateAddress(irp, devObj, connectionFileObject, NULL, NULL, addressHandle);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    return status;
+}
+
+NTSTATUS tdi_disassociate_address(PFILE_OBJECT connectionFileObject)
+{
+    PDEVICE_OBJECT  devObj;
+    KEVENT          event;
+    PIRP            irp;
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS        status;
+
+    devObj = IoGetRelatedDeviceObject(connectionFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_DISASSOCIATE_ADDRESS, devObj, connectionFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    TdiBuildDisassociateAddress(irp, devObj, connectionFileObject, NULL, NULL);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    return status;
+}
+
+NTSTATUS tdi_connect(PFILE_OBJECT connectionFileObject, ULONG addr, USHORT port)
+{
+    PDEVICE_OBJECT              devObj;
+    KEVENT                      event;
+    PTDI_CONNECTION_INFORMATION remoteInfo;
+    PTA_IP_ADDRESS              remoteAddr;
+    PTDI_CONNECTION_INFORMATION returnInfo;
+    PTA_IP_ADDRESS              returnAddr;
+    PIRP                        irp;
+    IO_STATUS_BLOCK             iosb;
+    NTSTATUS                    status;
+
+    devObj = IoGetRelatedDeviceObject(connectionFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, 2 * sizeof(TDI_CONNECTION_INFORMATION) + 2 * sizeof(TA_IP_ADDRESS));
+
+    if (remoteInfo == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(remoteInfo, 2 * sizeof(TDI_CONNECTION_INFORMATION) + 2 * sizeof(TA_IP_ADDRESS));
+
+    remoteInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
+    remoteInfo->RemoteAddress = (PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION);
+
+    remoteAddr = (PTA_IP_ADDRESS) remoteInfo->RemoteAddress;
+
+    remoteAddr->TAAddressCount = 1;
+    remoteAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+    remoteAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+    remoteAddr->Address[0].Address[0].sin_port = port;
+    remoteAddr->Address[0].Address[0].in_addr = addr;
+
+    returnInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
+
+    returnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
+    returnInfo->RemoteAddress = (PUCHAR)returnInfo + sizeof(TDI_CONNECTION_INFORMATION);
+
+    returnAddr = (PTA_IP_ADDRESS) returnInfo->RemoteAddress;
+
+    returnAddr->TAAddressCount = 1;
+    returnAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+    returnAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_CONNECT, devObj, connectionFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        ExFreePool(remoteInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    TdiBuildConnect(irp, devObj, connectionFileObject, NULL, NULL, NULL, remoteInfo, returnInfo);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    ExFreePool(remoteInfo);
+
+    return status;
+}
+
+NTSTATUS tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags)
+{
+    PDEVICE_OBJECT  devObj;
+    KEVENT          event;
+    PIRP            irp;
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS        status;
+
+    devObj = IoGetRelatedDeviceObject(connectionFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_DISCONNECT, devObj, connectionFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    TdiBuildDisconnect(irp, devObj, connectionFileObject, NULL, NULL, NULL, flags, NULL, NULL);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    return status;
+}
+
+NTSTATUS tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len)
+{
+    PDEVICE_OBJECT              devObj;
+    KEVENT                      event;
+    PTDI_CONNECTION_INFORMATION remoteInfo;
+    PTA_IP_ADDRESS              remoteAddr;
+    PIRP                        irp;
+    PMDL                        mdl;
+    IO_STATUS_BLOCK             iosb;
+    NTSTATUS                    status;
+
+    devObj = IoGetRelatedDeviceObject(addressFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
+
+    if (remoteInfo == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(remoteInfo, sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
+
+    remoteInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
+    remoteInfo->RemoteAddress = (PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION);
+
+    remoteAddr = (PTA_IP_ADDRESS) remoteInfo->RemoteAddress;
+
+    remoteAddr->TAAddressCount = 1;
+    remoteAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+    remoteAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+    remoteAddr->Address[0].Address[0].sin_port = port;
+    remoteAddr->Address[0].Address[0].in_addr = addr;
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM, devObj, addressFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        ExFreePool(remoteInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (len)
+    {
+        mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
+
+        if (mdl == NULL)
+        {
+            IoFreeIrp(irp);
+            ExFreePool(remoteInfo);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        __try
+        {
+            MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
+            status = STATUS_SUCCESS;
+        }
+        __except (EXCEPTION_EXECUTE_HANDLER)
+        {
+            IoFreeMdl(mdl);
+            IoFreeIrp(irp);
+            ExFreePool(remoteInfo);
+            status = STATUS_INVALID_USER_BUFFER;
+        }
+
+        if (!NT_SUCCESS(status))
+        {
+            return status;
+        }
+    }
+
+    TdiBuildSendDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    ExFreePool(remoteInfo);
+
+    return NT_SUCCESS(status) ? iosb.Information : status;
+}
+
+NTSTATUS tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags)
+{
+    PDEVICE_OBJECT              devObj;
+    KEVENT                      event;
+    PTDI_CONNECTION_INFORMATION remoteInfo;
+    PTDI_CONNECTION_INFORMATION returnInfo;
+    PTA_IP_ADDRESS              returnAddr;
+    PIRP                        irp;
+    PMDL                        mdl;
+    IO_STATUS_BLOCK             iosb;
+    NTSTATUS                    status;
+
+    devObj = IoGetRelatedDeviceObject(addressFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    remoteInfo = (PTDI_CONNECTION_INFORMATION) ExAllocatePool(NonPagedPool, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
+
+    if (remoteInfo == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(remoteInfo, 2 * sizeof(TDI_CONNECTION_INFORMATION) + sizeof(TA_IP_ADDRESS));
+
+    remoteInfo->RemoteAddressLength = 0;
+    remoteInfo->RemoteAddress = NULL;
+
+    returnInfo = (PTDI_CONNECTION_INFORMATION)((PUCHAR)remoteInfo + sizeof(TDI_CONNECTION_INFORMATION));
+
+    returnInfo->RemoteAddressLength = sizeof(TA_IP_ADDRESS);
+    returnInfo->RemoteAddress = (PUCHAR)returnInfo + sizeof(TDI_CONNECTION_INFORMATION);
+
+    returnAddr = (PTA_IP_ADDRESS) returnInfo->RemoteAddress;
+
+    returnAddr->TAAddressCount = 1;
+    returnAddr->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
+    returnAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM, devObj, addressFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        ExFreePool(remoteInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (len)
+    {
+        mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
+
+        if (mdl == NULL)
+        {
+            IoFreeIrp(irp);
+            ExFreePool(remoteInfo);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        __try
+        {
+            MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
+            status = STATUS_SUCCESS;
+        }
+        __except (EXCEPTION_EXECUTE_HANDLER)
+        {
+            IoFreeMdl(mdl);
+            IoFreeIrp(irp);
+            ExFreePool(remoteInfo);
+            status = STATUS_INVALID_USER_BUFFER;
+        }
+
+        if (!NT_SUCCESS(status))
+        {
+            return status;
+        }
+    }
+
+    TdiBuildReceiveDatagram(irp, devObj, addressFileObject, NULL, NULL, len ? mdl : 0, len, remoteInfo, returnInfo, flags);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    if (addr)
+    {
+        *addr = returnAddr->Address[0].Address[0].in_addr;
+    }
+
+    if (port)
+    {
+        *port = returnAddr->Address[0].Address[0].sin_port;
+    }
+
+    ExFreePool(remoteInfo);
+
+    return NT_SUCCESS(status) ? iosb.Information : status;
+}
+
+NTSTATUS tdi_send_stream(PFILE_OBJECT connectionFileObject, const char *buf, int len, ULONG flags)
+{
+    PDEVICE_OBJECT  devObj;
+    KEVENT          event;
+    PIRP            irp;
+    PMDL            mdl;
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS        status;
+
+    devObj = IoGetRelatedDeviceObject(connectionFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_SEND, devObj, connectionFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (len)
+    {
+        mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
+
+        if (mdl == NULL)
+        {
+            IoFreeIrp(irp);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        __try
+        {
+            MmProbeAndLockPages(mdl, KernelMode, IoReadAccess);
+            status = STATUS_SUCCESS;
+        }
+        __except (EXCEPTION_EXECUTE_HANDLER)
+        {
+            IoFreeMdl(mdl);
+            IoFreeIrp(irp);
+            status = STATUS_INVALID_USER_BUFFER;
+        }
+
+        if (!NT_SUCCESS(status))
+        {
+            return status;
+        }
+    }
+
+    TdiBuildSend(irp, devObj, connectionFileObject, NULL, NULL, len ? mdl : 0, flags, len);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    return NT_SUCCESS(status) ? iosb.Information : status;
+}
+
+NTSTATUS tdi_recv_stream(PFILE_OBJECT connectionFileObject, char *buf, int len, ULONG flags)
+{
+    PDEVICE_OBJECT  devObj;
+    KEVENT          event;
+    PIRP            irp;
+    PMDL            mdl;
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS        status;
+
+    devObj = IoGetRelatedDeviceObject(connectionFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE, devObj, connectionFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    if (len)
+    {
+        mdl = IoAllocateMdl((void*) buf, len, FALSE, FALSE, NULL);
+
+        if (mdl == NULL)
+        {
+            IoFreeIrp(irp);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        __try
+        {
+            MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
+            status = STATUS_SUCCESS;
+        }
+        __except (EXCEPTION_EXECUTE_HANDLER)
+        {
+            IoFreeMdl(mdl);
+            IoFreeIrp(irp);
+            status = STATUS_INVALID_USER_BUFFER;
+        }
+
+        if (!NT_SUCCESS(status))
+        {
+            return status;
+        }
+    }
+
+    TdiBuildReceive(irp, devObj, connectionFileObject, NULL, NULL, len ? mdl : 0, flags, len);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    return NT_SUCCESS(status) ? iosb.Information : status;
+}
+
+NTSTATUS tdi_query_address(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port)
+{
+    PDEVICE_OBJECT              devObj;
+    KEVENT                      event;
+    PTRANSPORT_ADDRESS          localInfo;
+    PTA_IP_ADDRESS              localAddr;
+    PIRP                        irp;
+    PMDL                        mdl;
+    IO_STATUS_BLOCK             iosb;
+    NTSTATUS                    status;
+
+    devObj = IoGetRelatedDeviceObject(addressFileObject);
+
+    KeInitializeEvent(&event, NotificationEvent, FALSE);
+
+    localInfo = (PTRANSPORT_ADDRESS) ExAllocatePool(NonPagedPool, sizeof(TDI_ADDRESS_INFO)*10);
+
+    if (localInfo == NULL)
+    {
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(localInfo, sizeof(TDI_ADDRESS_INFO)*10);
+
+    irp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION, devObj, addressFileObject, &event, &iosb);
+
+    if (irp == NULL)
+    {
+        ExFreePool(localInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    {
+        mdl = IoAllocateMdl((void*) localInfo, sizeof(TDI_ADDRESS_INFO)*10, FALSE, FALSE, NULL);
+
+        if (mdl == NULL)
+        {
+            IoFreeIrp(irp);
+            ExFreePool(localInfo);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+
+        __try
+        {
+            MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess);
+            status = STATUS_SUCCESS;
+        }
+        __except (EXCEPTION_EXECUTE_HANDLER)
+        {
+            IoFreeMdl(mdl);
+            IoFreeIrp(irp);
+            ExFreePool(localInfo);
+            status = STATUS_INVALID_USER_BUFFER;
+        }
+
+        if (!NT_SUCCESS(status))
+        {
+            return status;
+        }
+    }
+
+    TdiBuildQueryInformation(irp, devObj, addressFileObject, NULL, NULL, TDI_QUERY_ADDRESS_INFO, mdl);
+
+    status = IoCallDriver(devObj, irp);
+
+    if (status == STATUS_PENDING)
+    {
+        KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
+        status = iosb.Status;
+    }
+
+    localAddr = (PTA_IP_ADDRESS)&localInfo->Address[0];
+
+    if (addr)
+    {
+        *addr = localAddr->Address[0].Address[0].in_addr;
+    }
+
+    if (port)
+    {
+        *port = localAddr->Address[0].Address[0].sin_port;
+    }
+
+    ExFreePool(localInfo);
+
+    return status;
+}
index 7cd018b..09ec2e5 100644 (file)
@@ -1,29 +1,29 @@
-/*\r
-    HTTP Virtual Disk.\r
-    Copyright (C) 2006 Bo Brantén.\r
-    This program is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-    This program is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-    You should have received a copy of the GNU General Public License\r
-    along with this program; if not, write to the Free Software\r
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-NTSTATUS tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, BOOLEAN shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject);\r
-NTSTATUS tdi_open_connection_endpoint(PUNICODE_STRING devName, PVOID connectionContext, BOOLEAN shared, PHANDLE connectionHandle, PFILE_OBJECT *connectionFileObject);\r
-NTSTATUS tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext);\r
-NTSTATUS tdi_unset_event_handler(PFILE_OBJECT addressFileObject, LONG eventType);\r
-NTSTATUS tdi_associate_address(PFILE_OBJECT connectionFileObject, HANDLE addressHandle);\r
-NTSTATUS tdi_disassociate_address(PFILE_OBJECT connectionFileObject);\r
-NTSTATUS tdi_connect(PFILE_OBJECT connectionFileObject, ULONG addr, USHORT port);\r
-NTSTATUS tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags);\r
-NTSTATUS tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len);\r
-NTSTATUS tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags);\r
-NTSTATUS tdi_send_stream(PFILE_OBJECT connectionFileObject, const char *buf, int len, ULONG flags);\r
-NTSTATUS tdi_recv_stream(PFILE_OBJECT connectionFileObject, char *buf, int len, ULONG flags);\r
-NTSTATUS tdi_query_address(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port);\r
+/*
+    HTTP Virtual Disk.
+    Copyright (C) 2006 Bo Brantén.
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+NTSTATUS tdi_open_transport_address(PUNICODE_STRING devName, ULONG addr, USHORT port, BOOLEAN shared, PHANDLE addressHandle, PFILE_OBJECT *addressFileObject);
+NTSTATUS tdi_open_connection_endpoint(PUNICODE_STRING devName, PVOID connectionContext, BOOLEAN shared, PHANDLE connectionHandle, PFILE_OBJECT *connectionFileObject);
+NTSTATUS tdi_set_event_handler(PFILE_OBJECT addressFileObject, LONG eventType, PVOID eventHandler, PVOID eventContext);
+NTSTATUS tdi_unset_event_handler(PFILE_OBJECT addressFileObject, LONG eventType);
+NTSTATUS tdi_associate_address(PFILE_OBJECT connectionFileObject, HANDLE addressHandle);
+NTSTATUS tdi_disassociate_address(PFILE_OBJECT connectionFileObject);
+NTSTATUS tdi_connect(PFILE_OBJECT connectionFileObject, ULONG addr, USHORT port);
+NTSTATUS tdi_disconnect(PFILE_OBJECT connectionFileObject, ULONG flags);
+NTSTATUS tdi_send_dgram(PFILE_OBJECT addressFileObject, ULONG addr, USHORT port, const char *buf, int len);
+NTSTATUS tdi_recv_dgram(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port, char *buf, int len, ULONG flags);
+NTSTATUS tdi_send_stream(PFILE_OBJECT connectionFileObject, const char *buf, int len, ULONG flags);
+NTSTATUS tdi_recv_stream(PFILE_OBJECT connectionFileObject, char *buf, int len, ULONG flags);
+NTSTATUS tdi_query_address(PFILE_OBJECT addressFileObject, PULONG addr, PUSHORT port);
index dd6b606..73a5e8e 100644 (file)
-/*\r
-    HTTP Virtual Disk.\r
-    Copyright (C) 2006 Bo Brantén.\r
-    This program is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-    This program is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-    You should have received a copy of the GNU General Public License\r
-    along with this program; if not, write to the Free Software\r
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-#include <windows.h>\r
-#include <winioctl.h>\r
-#include <winsock2.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include "httpdisk.h"\r
-\r
-int HttpDiskSyntax(void)\r
-{\r
-    fprintf(stderr, "syntax:\n");\r
-    fprintf(stderr, "httpdisk /mount  <devicenumber> <url> [/cd] <drive:>\n");\r
-    fprintf(stderr, "httpdisk /umount <drive:>\n");\r
-    fprintf(stderr, "\n");\r
-    fprintf(stderr, "example:\n");\r
-    fprintf(stderr, "httpdisk /mount  0 http://server.domain.com/path/diskimage.img d:\n");\r
-    fprintf(stderr, "httpdisk /mount  1 http://server.domain.com/path/cdimage.iso /cd e:\n");\r
-    fprintf(stderr, "...\n");\r
-    fprintf(stderr, "httpdisk /umount d:\n");\r
-    fprintf(stderr, "httpdisk /umount e:\n");\r
-\r
-    return -1;\r
-}\r
-\r
-void PrintLastError(char* Prefix)\r
-{\r
-    LPVOID lpMsgBuf;\r
-\r
-    FormatMessage( \r
-        FORMAT_MESSAGE_ALLOCATE_BUFFER |\r
-        FORMAT_MESSAGE_FROM_SYSTEM |\r
-        FORMAT_MESSAGE_IGNORE_INSERTS,\r
-        NULL,\r
-        GetLastError(),\r
-        0,\r
-        (LPTSTR) &lpMsgBuf,\r
-        0,\r
-        NULL\r
-        );\r
-\r
-    fprintf(stderr, "%s: %s", Prefix, (LPTSTR) lpMsgBuf);\r
-\r
-    LocalFree(lpMsgBuf);\r
-}\r
-\r
-int\r
-HttpDiskMount(\r
-    int                     DeviceNumber,\r
-    PHTTP_DISK_INFORMATION  HttpDiskInformation,\r
-    char                    DriveLetter,\r
-    BOOLEAN                 CdImage\r
-)\r
-{\r
-    char    VolumeName[] = "\\\\.\\ :";\r
-    char    DeviceName[255];\r
-    HANDLE  Device;\r
-    DWORD   BytesReturned;\r
-\r
-    VolumeName[4] = DriveLetter;\r
-\r
-    Device = CreateFile(\r
-        VolumeName,\r
-        GENERIC_READ | GENERIC_WRITE,\r
-        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
-        NULL,\r
-        OPEN_EXISTING,\r
-        FILE_FLAG_NO_BUFFERING,\r
-        NULL\r
-        );\r
-\r
-    if (Device != INVALID_HANDLE_VALUE)\r
-    {\r
-        SetLastError(ERROR_BUSY);\r
-        PrintLastError(&VolumeName[4]);\r
-        return -1;\r
-    }\r
-\r
-    if (CdImage)\r
-    {\r
-        sprintf(DeviceName, DEVICE_NAME_PREFIX "Cd" "%u", DeviceNumber);\r
-    }\r
-    else\r
-    {\r
-        sprintf(DeviceName, DEVICE_NAME_PREFIX "Disk" "%u", DeviceNumber);\r
-    }\r
-\r
-    if (!DefineDosDevice(\r
-        DDD_RAW_TARGET_PATH,\r
-        &VolumeName[4],\r
-        DeviceName\r
-        ))\r
-    {\r
-        PrintLastError(&VolumeName[4]);\r
-        return -1;\r
-    }\r
-\r
-    Device = CreateFile(\r
-        VolumeName,\r
-        GENERIC_READ | GENERIC_WRITE,\r
-        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
-        NULL,\r
-        OPEN_EXISTING,\r
-        FILE_FLAG_NO_BUFFERING,\r
-        NULL\r
-        );\r
-\r
-    if (Device == INVALID_HANDLE_VALUE)\r
-    {\r
-        PrintLastError(&VolumeName[4]);\r
-        DefineDosDevice(DDD_REMOVE_DEFINITION, &VolumeName[4], NULL);\r
-        return -1;\r
-    }\r
-\r
-    if (!DeviceIoControl(\r
-        Device,\r
-        IOCTL_HTTP_DISK_CONNECT,\r
-        HttpDiskInformation,\r
-        sizeof(HTTP_DISK_INFORMATION) + HttpDiskInformation->FileNameLength - 1,\r
-        NULL,\r
-        0,\r
-        &BytesReturned,\r
-        NULL\r
-        ))\r
-    {\r
-        PrintLastError("HttpDisk");\r
-        DefineDosDevice(DDD_REMOVE_DEFINITION, &VolumeName[4], NULL);\r
-        return -1;\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-int HttpDiskUmount(char DriveLetter)\r
-{\r
-    char    VolumeName[] = "\\\\.\\ :";\r
-    HANDLE  Device;\r
-    DWORD   BytesReturned;\r
-\r
-    VolumeName[4] = DriveLetter;\r
-\r
-    Device = CreateFile(\r
-        VolumeName,\r
-        GENERIC_READ | GENERIC_WRITE,\r
-        FILE_SHARE_READ | FILE_SHARE_WRITE,\r
-        NULL,\r
-        OPEN_EXISTING,\r
-        FILE_FLAG_NO_BUFFERING,\r
-        NULL\r
-        );\r
-\r
-    if (Device == INVALID_HANDLE_VALUE)\r
-    {\r
-        PrintLastError(&VolumeName[4]);\r
-        return -1;\r
-    }\r
-\r
-    if (!DeviceIoControl(\r
-        Device,\r
-        FSCTL_LOCK_VOLUME,\r
-        NULL,\r
-        0,\r
-        NULL,\r
-        0,\r
-        &BytesReturned,\r
-        NULL\r
-        ))\r
-    {\r
-        PrintLastError(&VolumeName[4]);\r
-        return -1;\r
-    }\r
-\r
-    if (!DeviceIoControl(\r
-        Device,\r
-        IOCTL_HTTP_DISK_DISCONNECT,\r
-        NULL,\r
-        0,\r
-        NULL,\r
-        0,\r
-        &BytesReturned,\r
-        NULL\r
-        ))\r
-    {\r
-        PrintLastError("HttpDisk");\r
-        return -1;\r
-    }\r
-\r
-    if (!DeviceIoControl(\r
-        Device,\r
-        FSCTL_DISMOUNT_VOLUME,\r
-        NULL,\r
-        0,\r
-        NULL,\r
-        0,\r
-        &BytesReturned,\r
-        NULL\r
-        ))\r
-    {\r
-        PrintLastError(&VolumeName[4]);\r
-        return -1;\r
-    }\r
-\r
-    if (!DeviceIoControl(\r
-        Device,\r
-        FSCTL_UNLOCK_VOLUME,\r
-        NULL,\r
-        0,\r
-        NULL,\r
-        0,\r
-        &BytesReturned,\r
-        NULL\r
-        ))\r
-    {\r
-        PrintLastError(&VolumeName[4]);\r
-        return -1;\r
-    }\r
-\r
-    CloseHandle(Device);\r
-\r
-    if (!DefineDosDevice(\r
-        DDD_REMOVE_DEFINITION,\r
-        &VolumeName[4],\r
-        NULL\r
-        ))\r
-    {\r
-        PrintLastError(&VolumeName[4]);\r
-        return -1;\r
-    }\r
-\r
-    return 0;\r
-}\r
-\r
-int __cdecl main(int argc, char* argv[])\r
-{\r
-    char*                   Command;\r
-    int                     DeviceNumber;\r
-    char*                   Url;\r
-    char*                   Option;\r
-    char                    DriveLetter;\r
-    BOOLEAN                 CdImage;\r
-    PHTTP_DISK_INFORMATION  HttpDiskInformation;\r
-    char*                   FileName;\r
-    char*                   PortStr;\r
-    struct hostent*         HostEnt;\r
-    WSADATA                 wsaData;\r
-\r
-    Command = argv[1];\r
-\r
-    if ((argc == 5 || argc == 6) && !strcmp(Command, "/mount"))\r
-    {\r
-        DeviceNumber = atoi(argv[2]);\r
-        Url = argv[3];\r
-\r
-        if (argc > 5)\r
-        {\r
-            Option = argv[4];\r
-            DriveLetter = argv[5][0];\r
-\r
-            if (!strcmp(Option, "/cd"))\r
-            {\r
-                CdImage = TRUE;\r
-            }\r
-            else\r
-            {\r
-                return HttpDiskSyntax();\r
-            }\r
-        }\r
-        else\r
-        {\r
-            Option = NULL;\r
-            DriveLetter = argv[4][0];\r
-            CdImage = FALSE;\r
-        }\r
-\r
-        HttpDiskInformation = malloc(sizeof(HTTP_DISK_INFORMATION) + strlen(Url));\r
-\r
-        memset(\r
-            HttpDiskInformation,\r
-            0,\r
-            sizeof(HTTP_DISK_INFORMATION) + strlen(Url)\r
-            );\r
-\r
-        if (strstr(Url, "//"))\r
-        {\r
-            if (strlen(Url) > 7 && !strncmp(Url, "http://", 7))\r
-            {\r
-                Url += 7;\r
-            }\r
-            else\r
-            {\r
-                fprintf(stderr, "Invalid protocol.\n");\r
-                return -1;\r
-            }\r
-        }\r
-\r
-        FileName = strstr(Url, "/");\r
-\r
-        if (!FileName)\r
-        {\r
-            fprintf(stderr, "%s: Invalid url.\n", Url);\r
-            return -1;\r
-        }\r
-\r
-        strcpy(HttpDiskInformation->FileName, FileName);\r
-\r
-        HttpDiskInformation->FileNameLength = (USHORT) strlen(HttpDiskInformation->FileName);\r
-\r
-        *FileName = '\0';\r
-\r
-        PortStr = strstr(Url, ":");\r
-\r
-        if (PortStr)\r
-        {\r
-            HttpDiskInformation->Port = htons((USHORT) atoi(PortStr + 1));\r
-\r
-            if (HttpDiskInformation->Port == 0)\r
-            {\r
-                fprintf(stderr, "%s: Invalid port.\n", PortStr + 1);\r
-                return -1;\r
-            }\r
-\r
-            *PortStr = '\0';\r
-        }\r
-        else\r
-        {\r
-            HttpDiskInformation->Port = htons(80);\r
-        }\r
-\r
-        HttpDiskInformation->HostNameLength = (USHORT) strlen(Url);\r
-\r
-        if (HttpDiskInformation->HostNameLength > 255)\r
-        {\r
-            fprintf(stderr, "%s: Host name to long.\n", Url);\r
-            return -1;\r
-        }\r
-\r
-        strcpy(HttpDiskInformation->HostName, Url);\r
-\r
-        HttpDiskInformation->Address = inet_addr(Url);\r
-\r
-        if (HttpDiskInformation->Address == INADDR_NONE)\r
-        {\r
-            if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)\r
-            {\r
-                PrintLastError("HttpDisk");\r
-                return -1;\r
-            }\r
-\r
-            HostEnt = gethostbyname(Url);\r
-\r
-            if (!HostEnt)\r
-            {\r
-                PrintLastError(Url);\r
-                return -1;\r
-            }\r
-\r
-            HttpDiskInformation->Address = ((struct in_addr*) HostEnt->h_addr)->s_addr;\r
-        }\r
-\r
-        return HttpDiskMount(DeviceNumber, HttpDiskInformation, DriveLetter, CdImage);\r
-    }\r
-    else if (argc == 3 && !strcmp(Command, "/umount"))\r
-    {\r
-        DriveLetter = argv[2][0];\r
-        return HttpDiskUmount(DriveLetter);\r
-    }\r
-    else\r
-    {\r
-        return HttpDiskSyntax();\r
-    }\r
-}\r
+/*
+    HTTP Virtual Disk.
+    Copyright (C) 2006 Bo Brantén.
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <windows.h>
+#include <winioctl.h>
+#include <winsock2.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "httpdisk.h"
+
+int HttpDiskSyntax(void)
+{
+    fprintf(stderr, "syntax:\n");
+    fprintf(stderr, "httpdisk /mount  <devicenumber> <url> [/cd] <drive:>\n");
+    fprintf(stderr, "httpdisk /umount <drive:>\n");
+    fprintf(stderr, "\n");
+    fprintf(stderr, "example:\n");
+    fprintf(stderr, "httpdisk /mount  0 http://server.domain.com/path/diskimage.img d:\n");
+    fprintf(stderr, "httpdisk /mount  1 http://server.domain.com/path/cdimage.iso /cd e:\n");
+    fprintf(stderr, "...\n");
+    fprintf(stderr, "httpdisk /umount d:\n");
+    fprintf(stderr, "httpdisk /umount e:\n");
+
+    return -1;
+}
+
+void PrintLastError(char* Prefix)
+{
+    LPVOID lpMsgBuf;
+
+    FormatMessage( 
+        FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_FROM_SYSTEM |
+        FORMAT_MESSAGE_IGNORE_INSERTS,
+        NULL,
+        GetLastError(),
+        0,
+        (LPTSTR) &lpMsgBuf,
+        0,
+        NULL
+        );
+
+    fprintf(stderr, "%s: %s", Prefix, (LPTSTR) lpMsgBuf);
+
+    LocalFree(lpMsgBuf);
+}
+
+int
+HttpDiskMount(
+    int                     DeviceNumber,
+    PHTTP_DISK_INFORMATION  HttpDiskInformation,
+    char                    DriveLetter,
+    BOOLEAN                 CdImage
+)
+{
+    char    VolumeName[] = "\\\\.\\ :";
+    char    DeviceName[255];
+    HANDLE  Device;
+    DWORD   BytesReturned;
+
+    VolumeName[4] = DriveLetter;
+
+    Device = CreateFile(
+        VolumeName,
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        NULL,
+        OPEN_EXISTING,
+        FILE_FLAG_NO_BUFFERING,
+        NULL
+        );
+
+    if (Device != INVALID_HANDLE_VALUE)
+    {
+        SetLastError(ERROR_BUSY);
+        PrintLastError(&VolumeName[4]);
+        return -1;
+    }
+
+    if (CdImage)
+    {
+        sprintf(DeviceName, DEVICE_NAME_PREFIX "Cd" "%u", DeviceNumber);
+    }
+    else
+    {
+        sprintf(DeviceName, DEVICE_NAME_PREFIX "Disk" "%u", DeviceNumber);
+    }
+
+    if (!DefineDosDevice(
+        DDD_RAW_TARGET_PATH,
+        &VolumeName[4],
+        DeviceName
+        ))
+    {
+        PrintLastError(&VolumeName[4]);
+        return -1;
+    }
+
+    Device = CreateFile(
+        VolumeName,
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        NULL,
+        OPEN_EXISTING,
+        FILE_FLAG_NO_BUFFERING,
+        NULL
+        );
+
+    if (Device == INVALID_HANDLE_VALUE)
+    {
+        PrintLastError(&VolumeName[4]);
+        DefineDosDevice(DDD_REMOVE_DEFINITION, &VolumeName[4], NULL);
+        return -1;
+    }
+
+    if (!DeviceIoControl(
+        Device,
+        IOCTL_HTTP_DISK_CONNECT,
+        HttpDiskInformation,
+        sizeof(HTTP_DISK_INFORMATION) + HttpDiskInformation->FileNameLength - 1,
+        NULL,
+        0,
+        &BytesReturned,
+        NULL
+        ))
+    {
+        PrintLastError("HttpDisk");
+        DefineDosDevice(DDD_REMOVE_DEFINITION, &VolumeName[4], NULL);
+        return -1;
+    }
+
+    return 0;
+}
+
+int HttpDiskUmount(char DriveLetter)
+{
+    char    VolumeName[] = "\\\\.\\ :";
+    HANDLE  Device;
+    DWORD   BytesReturned;
+
+    VolumeName[4] = DriveLetter;
+
+    Device = CreateFile(
+        VolumeName,
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_READ | FILE_SHARE_WRITE,
+        NULL,
+        OPEN_EXISTING,
+        FILE_FLAG_NO_BUFFERING,
+        NULL
+        );
+
+    if (Device == INVALID_HANDLE_VALUE)
+    {
+        PrintLastError(&VolumeName[4]);
+        return -1;
+    }
+
+    if (!DeviceIoControl(
+        Device,
+        FSCTL_LOCK_VOLUME,
+        NULL,
+        0,
+        NULL,
+        0,
+        &BytesReturned,
+        NULL
+        ))
+    {
+        PrintLastError(&VolumeName[4]);
+        return -1;
+    }
+
+    if (!DeviceIoControl(
+        Device,
+        IOCTL_HTTP_DISK_DISCONNECT,
+        NULL,
+        0,
+        NULL,
+        0,
+        &BytesReturned,
+        NULL
+        ))
+    {
+        PrintLastError("HttpDisk");
+        return -1;
+    }
+
+    if (!DeviceIoControl(
+        Device,
+        FSCTL_DISMOUNT_VOLUME,
+        NULL,
+        0,
+        NULL,
+        0,
+        &BytesReturned,
+        NULL
+        ))
+    {
+        PrintLastError(&VolumeName[4]);
+        return -1;
+    }
+
+    if (!DeviceIoControl(
+        Device,
+        FSCTL_UNLOCK_VOLUME,
+        NULL,
+        0,
+        NULL,
+        0,
+        &BytesReturned,
+        NULL
+        ))
+    {
+        PrintLastError(&VolumeName[4]);
+        return -1;
+    }
+
+    CloseHandle(Device);
+
+    if (!DefineDosDevice(
+        DDD_REMOVE_DEFINITION,
+        &VolumeName[4],
+        NULL
+        ))
+    {
+        PrintLastError(&VolumeName[4]);
+        return -1;
+    }
+
+    return 0;
+}
+
+int __cdecl main(int argc, char* argv[])
+{
+    char*                   Command;
+    int                     DeviceNumber;
+    char*                   Url;
+    char*                   Option;
+    char                    DriveLetter;
+    BOOLEAN                 CdImage;
+    PHTTP_DISK_INFORMATION  HttpDiskInformation;
+    char*                   FileName;
+    char*                   PortStr;
+    struct hostent*         HostEnt;
+    WSADATA                 wsaData;
+
+    Command = argv[1];
+
+    if ((argc == 5 || argc == 6) && !strcmp(Command, "/mount"))
+    {
+        DeviceNumber = atoi(argv[2]);
+        Url = argv[3];
+
+        if (argc > 5)
+        {
+            Option = argv[4];
+            DriveLetter = argv[5][0];
+
+            if (!strcmp(Option, "/cd"))
+            {
+                CdImage = TRUE;
+            }
+            else
+            {
+                return HttpDiskSyntax();
+            }
+        }
+        else
+        {
+            Option = NULL;
+            DriveLetter = argv[4][0];
+            CdImage = FALSE;
+        }
+
+        HttpDiskInformation = malloc(sizeof(HTTP_DISK_INFORMATION) + strlen(Url));
+
+        memset(
+            HttpDiskInformation,
+            0,
+            sizeof(HTTP_DISK_INFORMATION) + strlen(Url)
+            );
+
+        if (strstr(Url, "//"))
+        {
+            if (strlen(Url) > 7 && !strncmp(Url, "http://", 7))
+            {
+                Url += 7;
+            }
+            else
+            {
+                fprintf(stderr, "Invalid protocol.\n");
+                return -1;
+            }
+        }
+
+        FileName = strstr(Url, "/");
+
+        if (!FileName)
+        {
+            fprintf(stderr, "%s: Invalid url.\n", Url);
+            return -1;
+        }
+
+        strcpy(HttpDiskInformation->FileName, FileName);
+
+        HttpDiskInformation->FileNameLength = (USHORT) strlen(HttpDiskInformation->FileName);
+
+        *FileName = '\0';
+
+        PortStr = strstr(Url, ":");
+
+        if (PortStr)
+        {
+            HttpDiskInformation->Port = htons((USHORT) atoi(PortStr + 1));
+
+            if (HttpDiskInformation->Port == 0)
+            {
+                fprintf(stderr, "%s: Invalid port.\n", PortStr + 1);
+                return -1;
+            }
+
+            *PortStr = '\0';
+        }
+        else
+        {
+            HttpDiskInformation->Port = htons(80);
+        }
+
+        HttpDiskInformation->HostNameLength = (USHORT) strlen(Url);
+
+        if (HttpDiskInformation->HostNameLength > 255)
+        {
+            fprintf(stderr, "%s: Host name to long.\n", Url);
+            return -1;
+        }
+
+        strcpy(HttpDiskInformation->HostName, Url);
+
+        HttpDiskInformation->Address = inet_addr(Url);
+
+        if (HttpDiskInformation->Address == INADDR_NONE)
+        {
+            if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
+            {
+                PrintLastError("HttpDisk");
+                return -1;
+            }
+
+            HostEnt = gethostbyname(Url);
+
+            if (!HostEnt)
+            {
+                PrintLastError(Url);
+                return -1;
+            }
+
+            HttpDiskInformation->Address = ((struct in_addr*) HostEnt->h_addr)->s_addr;
+        }
+
+        return HttpDiskMount(DeviceNumber, HttpDiskInformation, DriveLetter, CdImage);
+    }
+    else if (argc == 3 && !strcmp(Command, "/umount"))
+    {
+        DriveLetter = argv[2][0];
+        return HttpDiskUmount(DriveLetter);
+    }
+    else
+    {
+        return HttpDiskSyntax();
+    }
+}
index ec74925..9f78555 100644 (file)
-//Microsoft Developer Studio generated resource script.\r
-//\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifndef _MAC\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION 1,0,0,0\r
- PRODUCTVERSION 1,0,0,0\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x40004L\r
- FILETYPE 0x1L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
-    BLOCK "StringFileInfo"\r
-    BEGIN\r
-        BLOCK "040904b0"\r
-        BEGIN\r
-            VALUE "CompanyName", "Bo Brantén\0"\r
-            VALUE "FileDescription", "HTTP Virtual Disk\0"\r
-            VALUE "FileVersion", "1.0.0.0\0"\r
-            VALUE "InternalName", "httpdisk\0"\r
-            VALUE "LegalCopyright", "Copyright © 2006 Bo Brantén\0"\r
-            VALUE "OriginalFilename", "httpdisk.exe\0"\r
-            VALUE "ProductName", "httpdisk\0"\r
-            VALUE "ProductVersion", "1.0.0.0\0"\r
-        END\r
-    END\r
-    BLOCK "VarFileInfo"\r
-    BEGIN\r
-        VALUE "Translation", 0x409, 1200\r
-    END\r
-END\r
-\r
-#endif    // !_MAC\r
-\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE DISCARDABLE \r
-BEGIN\r
-    "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE DISCARDABLE \r
-BEGIN\r
-    "#include ""afxres.h""\r\n"\r
-    "\0"\r
-END\r
-\r
-3 TEXTINCLUDE DISCARDABLE \r
-BEGIN\r
-    "\r\n"\r
-    "\0"\r
-END\r
-\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-#endif    // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif    // not APSTUDIO_INVOKED\r
-\r
+//Microsoft Developer Studio generated resource script.
+//
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,0
+ PRODUCTVERSION 1,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName", "Bo Brantén\0"
+            VALUE "FileDescription", "HTTP Virtual Disk\0"
+            VALUE "FileVersion", "1.0.0.0\0"
+            VALUE "InternalName", "httpdisk\0"
+            VALUE "LegalCopyright", "Copyright © 2006 Bo Brantén\0"
+            VALUE "OriginalFilename", "httpdisk.exe\0"
+            VALUE "ProductName", "httpdisk\0"
+            VALUE "ProductVersion", "1.0.0.0\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
+#endif    // !_MAC
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
index 2d2a5f6..c2beefb 100644 (file)
@@ -1,50 +1,50 @@
-/*\r
-    HTTP Virtual Disk.\r
-    Copyright (C) 2006 Bo Brantén.\r
-    This program is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; either version 2 of the License, or\r
-    (at your option) any later version.\r
-    This program is distributed in the hope that it will be useful,\r
-    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-    You should have received a copy of the GNU General Public License\r
-    along with this program; if not, write to the Free Software\r
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
-*/\r
-\r
-#ifndef _HTTP_DISK_\r
-#define _HTTP_DISK_\r
-\r
-#ifndef __T\r
-#ifdef _NTDDK_\r
-#define __T(x)  L ## x\r
-#else\r
-#define __T(x)  x\r
-#endif\r
-#endif\r
-\r
-#ifndef _T\r
-#define _T(x)   __T(x)\r
-#endif\r
-\r
-#define DEVICE_BASE_NAME    _T("\\HttpDisk")\r
-#define DEVICE_DIR_NAME     _T("\\Device")      DEVICE_BASE_NAME\r
-#define DEVICE_NAME_PREFIX  DEVICE_DIR_NAME     _T("\\Http")\r
-\r
-#define FILE_DEVICE_HTTP_DISK       0x8000\r
-\r
-#define IOCTL_HTTP_DISK_CONNECT     CTL_CODE(FILE_DEVICE_HTTP_DISK, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\r
-#define IOCTL_HTTP_DISK_DISCONNECT  CTL_CODE(FILE_DEVICE_HTTP_DISK, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)\r
-\r
-typedef struct _HTTP_DISK_INFORMATION {\r
-    ULONG   Address;\r
-    USHORT  Port;\r
-    USHORT  HostNameLength;\r
-    UCHAR   HostName[256];\r
-    USHORT  FileNameLength;\r
-    UCHAR   FileName[1];\r
-} HTTP_DISK_INFORMATION, *PHTTP_DISK_INFORMATION;\r
-\r
-#endif\r
+/*
+    HTTP Virtual Disk.
+    Copyright (C) 2006 Bo Brantén.
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef _HTTP_DISK_
+#define _HTTP_DISK_
+
+#ifndef __T
+#ifdef _NTDDK_
+#define __T(x)  L ## x
+#else
+#define __T(x)  x
+#endif
+#endif
+
+#ifndef _T
+#define _T(x)   __T(x)
+#endif
+
+#define DEVICE_BASE_NAME    _T("\\HttpDisk")
+#define DEVICE_DIR_NAME     _T("\\Device")      DEVICE_BASE_NAME
+#define DEVICE_NAME_PREFIX  DEVICE_DIR_NAME     _T("\\Http")
+
+#define FILE_DEVICE_HTTP_DISK       0x8000
+
+#define IOCTL_HTTP_DISK_CONNECT     CTL_CODE(FILE_DEVICE_HTTP_DISK, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_HTTP_DISK_DISCONNECT  CTL_CODE(FILE_DEVICE_HTTP_DISK, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+typedef struct _HTTP_DISK_INFORMATION {
+    ULONG   Address;
+    USHORT  Port;
+    USHORT  HostNameLength;
+    UCHAR   HostName[256];
+    USHORT  FileNameLength;
+    UCHAR   FileName[1];
+} HTTP_DISK_INFORMATION, *PHTTP_DISK_INFORMATION;
+
+#endif