zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/app/e2fsprogs/e2fsprogs-1.42.9/lib/ext2fs/nt_io.c b/ap/app/e2fsprogs/e2fsprogs-1.42.9/lib/ext2fs/nt_io.c
new file mode 100644
index 0000000..0f10543
--- /dev/null
+++ b/ap/app/e2fsprogs/e2fsprogs-1.42.9/lib/ext2fs/nt_io.c
@@ -0,0 +1,1496 @@
+/*
+ * nt_io.c --- This is the Nt I/O interface to the I/O manager.
+ *
+ * Implements a one-block write-through cache.
+ *
+ * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
+ * Copyright (C) 1998 Andrey Shedel (andreys@ns.cr.cyco.com)
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Library
+ * General Public License, version 2.
+ * %End-Header%
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+//
+// I need some warnings to disable...
+//
+
+
+#pragma warning(disable:4514) // unreferenced inline function has been removed
+#pragma warning(push,4)
+
+#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union)
+#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
+#pragma warning(disable:4115) // named type definition in parentheses
+
+#include <ntddk.h>
+#include <ntdddisk.h>
+#include <ntstatus.h>
+
+#pragma warning(pop)
+
+
+//
+// Some native APIs.
+//
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlNtStatusToDosError(
+    IN NTSTATUS Status
+   );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtClose(
+    IN HANDLE Handle
+   );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtOpenFile(
+    OUT PHANDLE FileHandle,
+    IN ACCESS_MASK DesiredAccess,
+    IN POBJECT_ATTRIBUTES ObjectAttributes,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    IN ULONG ShareAccess,
+    IN ULONG OpenOptions
+    );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtFlushBuffersFile(
+    IN HANDLE FileHandle,
+    OUT PIO_STATUS_BLOCK IoStatusBlock
+   );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtReadFile(
+    IN HANDLE FileHandle,
+    IN HANDLE Event OPTIONAL,
+    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+    IN PVOID ApcContext OPTIONAL,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    OUT PVOID Buffer,
+    IN ULONG Length,
+    IN PLARGE_INTEGER ByteOffset OPTIONAL,
+    IN PULONG Key OPTIONAL
+    );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtWriteFile(
+    IN HANDLE FileHandle,
+    IN HANDLE Event OPTIONAL,
+    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+    IN PVOID ApcContext OPTIONAL,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    IN PVOID Buffer,
+    IN ULONG Length,
+    IN PLARGE_INTEGER ByteOffset OPTIONAL,
+    IN PULONG Key OPTIONAL
+    );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtDeviceIoControlFile(
+    IN HANDLE FileHandle,
+    IN HANDLE Event OPTIONAL,
+    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+    IN PVOID ApcContext OPTIONAL,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    IN ULONG IoControlCode,
+    IN PVOID InputBuffer OPTIONAL,
+    IN ULONG InputBufferLength,
+    OUT PVOID OutputBuffer OPTIONAL,
+    IN ULONG OutputBufferLength
+    );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtFsControlFile(
+    IN HANDLE FileHandle,
+    IN HANDLE Event OPTIONAL,
+    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+    IN PVOID ApcContext OPTIONAL,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    IN ULONG IoControlCode,
+    IN PVOID InputBuffer OPTIONAL,
+    IN ULONG InputBufferLength,
+    OUT PVOID OutputBuffer OPTIONAL,
+    IN ULONG OutputBufferLength
+    );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtDelayExecution(
+    IN BOOLEAN Alertable,
+    IN PLARGE_INTEGER Interval
+    );
+
+
+#define FSCTL_LOCK_VOLUME               CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_UNLOCK_VOLUME             CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_DISMOUNT_VOLUME           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_IS_VOLUME_MOUNTED         CTL_CODE(FILE_DEVICE_FILE_SYSTEM,10, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+//
+// useful macros
+//
+
+#define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
+
+
+//
+// Include Win32 error codes.
+//
+
+#include <winerror.h>
+
+//
+// standard stuff
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#include <linux/types.h>
+#include "ext2_fs.h"
+#include <errno.h>
+
+#include "et/com_err.h"
+#include "ext2fs/ext2fs.h"
+#include "ext2fs/ext2_err.h"
+
+
+
+
+//
+// For checking structure magic numbers...
+//
+
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+	  if ((struct)->magic != (code)) return (code)
+
+#define EXT2_ET_MAGIC_NT_IO_CHANNEL  0x10ed
+
+
+//
+// Private data block
+//
+
+typedef struct _NT_PRIVATE_DATA {
+	int	   magic;
+	HANDLE Handle;
+	int	   Flags;
+	PCHAR  Buffer;
+	__u32  BufferBlockNumber;
+	ULONG  BufferSize;
+	BOOLEAN OpenedReadonly;
+	BOOLEAN Written;
+}NT_PRIVATE_DATA, *PNT_PRIVATE_DATA;
+
+
+
+//
+// Standard interface prototypes
+//
+
+static errcode_t nt_open(const char *name, int flags, io_channel *channel);
+static errcode_t nt_close(io_channel channel);
+static errcode_t nt_set_blksize(io_channel channel, int blksize);
+static errcode_t nt_read_blk(io_channel channel, unsigned long block,
+			       int count, void *data);
+static errcode_t nt_write_blk(io_channel channel, unsigned long block,
+				int count, const void *data);
+static errcode_t nt_flush(io_channel channel);
+
+static struct struct_io_manager struct_nt_manager = {
+	EXT2_ET_MAGIC_IO_MANAGER,
+	"NT I/O Manager",
+	nt_open,
+	nt_close,
+	nt_set_blksize,
+	nt_read_blk,
+	nt_write_blk,
+	nt_flush
+};
+
+
+
+//
+// function to get API
+//
+
+io_manager nt_io_manager()
+{
+	return &struct_nt_manager;
+}
+
+
+
+
+
+//
+// This is a code to convert Win32 errors to unix errno
+//
+
+typedef struct {
+	ULONG WinError;
+	int errnocode;
+}ERROR_ENTRY;
+
+static ERROR_ENTRY ErrorTable[] = {
+        {  ERROR_INVALID_FUNCTION,       EINVAL    },
+        {  ERROR_FILE_NOT_FOUND,         ENOENT    },
+        {  ERROR_PATH_NOT_FOUND,         ENOENT    },
+        {  ERROR_TOO_MANY_OPEN_FILES,    EMFILE    },
+        {  ERROR_ACCESS_DENIED,          EACCES    },
+        {  ERROR_INVALID_HANDLE,         EBADF     },
+        {  ERROR_ARENA_TRASHED,          ENOMEM    },
+        {  ERROR_NOT_ENOUGH_MEMORY,      ENOMEM    },
+        {  ERROR_INVALID_BLOCK,          ENOMEM    },
+        {  ERROR_BAD_ENVIRONMENT,        E2BIG     },
+        {  ERROR_BAD_FORMAT,             ENOEXEC   },
+        {  ERROR_INVALID_ACCESS,         EINVAL    },
+        {  ERROR_INVALID_DATA,           EINVAL    },
+        {  ERROR_INVALID_DRIVE,          ENOENT    },
+        {  ERROR_CURRENT_DIRECTORY,      EACCES    },
+        {  ERROR_NOT_SAME_DEVICE,        EXDEV     },
+        {  ERROR_NO_MORE_FILES,          ENOENT    },
+        {  ERROR_LOCK_VIOLATION,         EACCES    },
+        {  ERROR_BAD_NETPATH,            ENOENT    },
+        {  ERROR_NETWORK_ACCESS_DENIED,  EACCES    },
+        {  ERROR_BAD_NET_NAME,           ENOENT    },
+        {  ERROR_FILE_EXISTS,            EEXIST    },
+        {  ERROR_CANNOT_MAKE,            EACCES    },
+        {  ERROR_FAIL_I24,               EACCES    },
+        {  ERROR_INVALID_PARAMETER,      EINVAL    },
+        {  ERROR_NO_PROC_SLOTS,          EAGAIN    },
+        {  ERROR_DRIVE_LOCKED,           EACCES    },
+        {  ERROR_BROKEN_PIPE,            EPIPE     },
+        {  ERROR_DISK_FULL,              ENOSPC    },
+        {  ERROR_INVALID_TARGET_HANDLE,  EBADF     },
+        {  ERROR_INVALID_HANDLE,         EINVAL    },
+        {  ERROR_WAIT_NO_CHILDREN,       ECHILD    },
+        {  ERROR_CHILD_NOT_COMPLETE,     ECHILD    },
+        {  ERROR_DIRECT_ACCESS_HANDLE,   EBADF     },
+        {  ERROR_NEGATIVE_SEEK,          EINVAL    },
+        {  ERROR_SEEK_ON_DEVICE,         EACCES    },
+        {  ERROR_DIR_NOT_EMPTY,          ENOTEMPTY },
+        {  ERROR_NOT_LOCKED,             EACCES    },
+        {  ERROR_BAD_PATHNAME,           ENOENT    },
+        {  ERROR_MAX_THRDS_REACHED,      EAGAIN    },
+        {  ERROR_LOCK_FAILED,            EACCES    },
+        {  ERROR_ALREADY_EXISTS,         EEXIST    },
+        {  ERROR_FILENAME_EXCED_RANGE,   ENOENT    },
+        {  ERROR_NESTING_NOT_ALLOWED,    EAGAIN    },
+        {  ERROR_NOT_ENOUGH_QUOTA,       ENOMEM    }
+};
+
+
+
+
+static
+unsigned
+_MapDosError (
+    IN ULONG WinError
+   )
+{
+	int i;
+
+	//
+	// Lookup
+	//
+
+	for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i)
+	{
+		if (WinError == ErrorTable[i].WinError)
+		{
+			return ErrorTable[i].errnocode;
+		}
+	}
+
+	//
+	// not in table. Check ranges
+	//
+
+	if ((WinError >= ERROR_WRITE_PROTECT) &&
+		(WinError <= ERROR_SHARING_BUFFER_EXCEEDED))
+	{
+		return EACCES;
+	}
+	else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) &&
+			 (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN))
+	{
+		return ENOEXEC;
+	}
+	else
+	{
+		return EINVAL;
+	}
+}
+
+
+
+
+
+
+
+//
+// Function to map NT status to dos error.
+//
+
+static
+__inline
+unsigned
+_MapNtStatus(
+    IN NTSTATUS Status
+   )
+{
+	return _MapDosError(RtlNtStatusToDosError(Status));
+}
+
+
+
+
+
+//
+// Helper functions to make things easyer
+//
+
+static
+NTSTATUS
+_OpenNtName(
+    IN PCSTR Name,
+    IN BOOLEAN Readonly,
+    OUT PHANDLE Handle,
+    OUT PBOOLEAN OpenedReadonly OPTIONAL
+   )
+{
+	UNICODE_STRING UnicodeString;
+	ANSI_STRING    AnsiString;
+	WCHAR Buffer[512];
+	NTSTATUS Status;
+	OBJECT_ATTRIBUTES ObjectAttributes;
+	IO_STATUS_BLOCK IoStatusBlock;
+
+	//
+	// Make Unicode name from inlut string
+	//
+
+	UnicodeString.Buffer = &Buffer[0];
+	UnicodeString.Length = 0;
+	UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!!
+
+	RtlInitAnsiString(&AnsiString, Name);
+
+	Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
+
+	if(!NT_SUCCESS(Status))
+	{
+		return Status; // Unpappable character?
+	}
+
+	//
+	// Initialize object
+	//
+
+	InitializeObjectAttributes(&ObjectAttributes,
+							   &UnicodeString,
+							   OBJ_CASE_INSENSITIVE,
+							   NULL,
+							   NULL );
+
+	//
+	// Try to open it in initial mode
+	//
+
+	if(ARGUMENT_PRESENT(OpenedReadonly))
+	{
+		*OpenedReadonly = Readonly;
+	}
+
+
+	Status = NtOpenFile(Handle,
+						SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
+						&ObjectAttributes,
+						&IoStatusBlock,
+						FILE_SHARE_WRITE | FILE_SHARE_READ,
+						FILE_SYNCHRONOUS_IO_NONALERT);
+
+	if(!NT_SUCCESS(Status))
+	{
+		//
+		// Maybe was just mounted? wait 0.5 sec and retry.
+		//
+
+		LARGE_INTEGER Interval;
+		Interval.QuadPart = -5000000; // 0.5 sec. from now
+
+		NtDelayExecution(FALSE, &Interval);
+
+		Status = NtOpenFile(Handle,
+							SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
+							&ObjectAttributes,
+							&IoStatusBlock,
+							FILE_SHARE_WRITE | FILE_SHARE_READ,
+							FILE_SYNCHRONOUS_IO_NONALERT);
+
+		//
+		// Try to satisfy mode
+		//
+
+		if((STATUS_ACCESS_DENIED == Status) && !Readonly)
+		{
+			if(ARGUMENT_PRESENT(OpenedReadonly))
+			{
+				*OpenedReadonly = TRUE;
+			}
+
+			Status = NtOpenFile(Handle,
+							SYNCHRONIZE | FILE_READ_DATA,
+							&ObjectAttributes,
+							&IoStatusBlock,
+							FILE_SHARE_WRITE | FILE_SHARE_READ,
+							FILE_SYNCHRONOUS_IO_NONALERT);
+		}
+	}
+
+
+
+	//
+	// done
+	//
+
+	return Status;
+}
+
+
+static
+NTSTATUS
+_OpenDriveLetter(
+    IN CHAR Letter,
+    IN BOOLEAN ReadOnly,
+    OUT PHANDLE Handle,
+    OUT PBOOLEAN OpenedReadonly OPTIONAL
+   )
+{
+	CHAR Buffer[100];
+
+	sprintf(Buffer, "\\DosDevices\\%c:", Letter);
+
+	return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly);
+}
+
+
+//
+// Flush device
+//
+
+static
+__inline
+NTSTATUS
+_FlushDrive(
+		IN HANDLE Handle
+		)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return NtFlushBuffersFile(Handle, &IoStatusBlock);
+}
+
+
+//
+// lock drive
+//
+
+static
+__inline
+NTSTATUS
+_LockDrive(
+		IN HANDLE Handle
+		)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0);
+}
+
+
+//
+// unlock drive
+//
+
+static
+__inline
+NTSTATUS
+_UnlockDrive(
+	IN HANDLE Handle
+	)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0);
+}
+
+static
+__inline
+NTSTATUS
+_DismountDrive(
+	IN HANDLE Handle
+	)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0);
+}
+
+
+//
+// is mounted
+//
+
+static
+__inline
+BOOLEAN
+_IsMounted(
+	IN HANDLE Handle
+	)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	NTSTATUS Status;
+	Status = NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0);
+	return (BOOLEAN)(STATUS_SUCCESS == Status);
+}
+
+
+static
+__inline
+NTSTATUS
+_CloseDisk(
+		IN HANDLE Handle
+		)
+{
+	return NtClose(Handle);
+}
+
+
+
+
+//
+// Make NT name from any recognized name
+//
+
+static
+PCSTR
+_NormalizeDeviceName(
+    IN PCSTR Device,
+    IN PSTR NormalizedDeviceNameBuffer
+   )
+{
+	int PartitionNumber = -1;
+	UCHAR DiskNumber;
+	PSTR p;
+
+
+	//
+	// Do not try to parse NT name
+	//
+
+	if('\\' == *Device)
+		return Device;
+
+
+
+	//
+	// Strip leading '/dev/' if any
+	//
+
+	if(('/' == *(Device)) &&
+		('d' == *(Device + 1)) &&
+		('e' == *(Device + 2)) &&
+		('v' == *(Device + 3)) &&
+		('/' == *(Device + 4)))
+	{
+		Device += 5;
+	}
+
+	if('\0' == *Device)
+	{
+		return NULL;
+	}
+
+
+	//
+	// forms: hda[n], fd[n]
+	//
+
+	if('d' != *(Device + 1))
+	{
+		return NULL;
+	}
+
+	if('h' == *Device)
+	{
+		if((*(Device + 2) < 'a') || (*(Device + 2) > ('a' + 9)) ||
+		   ((*(Device + 3) != '\0') &&
+			((*(Device + 4) != '\0') ||
+			 ((*(Device + 3) < '0') || (*(Device + 3) > '9'))
+			)
+		   )
+		  )
+		{
+			return NULL;
+		}
+
+		DiskNumber = (UCHAR)(*(Device + 2) - 'a');
+
+		if(*(Device + 3) != '\0')
+		{
+			PartitionNumber = (*(Device + 3) - '0');
+		}
+
+	}
+	else if('f' == *Device)
+	{
+		//
+		// 3-d letted should be a digit.
+		//
+
+		if((*(Device + 3) != '\0') ||
+		   (*(Device + 2) < '0') || (*(Device + 2) > '9'))
+		{
+			return NULL;
+		}
+
+		DiskNumber = (UCHAR)(*(Device + 2) - '0');
+
+	}
+	else
+	{
+		//
+		// invalid prefix
+		//
+
+		return NULL;
+	}
+
+
+
+	//
+	// Prefix
+	//
+
+	strcpy(NormalizedDeviceNameBuffer, "\\Device\\");
+
+	//
+	// Media name
+	//
+
+	switch(*Device)
+	{
+
+	case 'f':
+		strcat(NormalizedDeviceNameBuffer, "Floppy0");
+		break;
+
+	case 'h':
+		strcat(NormalizedDeviceNameBuffer, "Harddisk0");
+		break;
+	}
+
+
+	p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
+	*p = (CHAR)(*p + DiskNumber);
+
+
+	//
+	// Partition nr.
+	//
+
+	if(PartitionNumber >= 0)
+	{
+		strcat(NormalizedDeviceNameBuffer, "\\Partition0");
+
+		p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
+		*p = (CHAR)(*p + PartitionNumber);
+	}
+
+
+	return NormalizedDeviceNameBuffer;
+}
+
+
+
+
+static
+VOID
+_GetDeviceSize(
+    IN HANDLE h,
+    OUT unsigned __int64 *FsSize
+   )
+{
+	PARTITION_INFORMATION pi;
+	DISK_GEOMETRY gi;
+	NTSTATUS Status;
+	IO_STATUS_BLOCK IoStatusBlock;
+
+	//
+	// Zero it
+	//
+
+	*FsSize = 0;
+
+	//
+	// Call driver
+	//
+
+	RtlZeroMemory(&pi, sizeof(PARTITION_INFORMATION));
+
+	Status = NtDeviceIoControlFile(
+		h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO,
+		&pi, sizeof(PARTITION_INFORMATION),
+		&pi, sizeof(PARTITION_INFORMATION));
+
+
+	if(NT_SUCCESS(Status))
+	{
+		*FsSize = pi.PartitionLength.QuadPart;
+	}
+	else if(STATUS_INVALID_DEVICE_REQUEST == Status)
+	{
+		//
+		// No partitions: get device info.
+		//
+
+		RtlZeroMemory(&gi, sizeof(DISK_GEOMETRY));
+
+		Status = NtDeviceIoControlFile(
+				h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+				&gi, sizeof(DISK_GEOMETRY),
+				&gi, sizeof(DISK_GEOMETRY));
+
+
+		if(NT_SUCCESS(Status))
+		{
+			*FsSize =
+				gi.BytesPerSector *
+				gi.SectorsPerTrack *
+				gi.TracksPerCylinder *
+				gi.Cylinders.QuadPart;
+		}
+
+	}
+}
+
+
+
+//
+// Open device by name.
+//
+
+static
+BOOLEAN
+_Ext2OpenDevice(
+    IN PCSTR Name,
+    IN BOOLEAN ReadOnly,
+    OUT PHANDLE Handle,
+    OUT PBOOLEAN OpenedReadonly OPTIONAL,
+    OUT unsigned *Errno OPTIONAL
+   )
+{
+	CHAR NormalizedDeviceName[512];
+	NTSTATUS Status;
+
+	if(NULL == Name)
+	{
+		//
+		// Set not found
+		//
+
+		if(ARGUMENT_PRESENT(Errno))
+			*Errno = ENOENT;
+
+		return FALSE;
+	}
+
+
+	if((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') &&
+		(':' == *(Name + 1)) && ('\0' == *(Name + 2)))
+	{
+		Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly);
+	}
+	else
+	{
+		//
+		// Make name
+		//
+
+		Name = _NormalizeDeviceName(Name, NormalizedDeviceName);
+
+		if(NULL == Name)
+		{
+			//
+			// Set not found
+			//
+
+			if(ARGUMENT_PRESENT(Errno))
+				*Errno = ENOENT;
+
+			return FALSE;
+		}
+
+		//
+		// Try to open it
+		//
+
+		Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly);
+	}
+
+
+	if(!NT_SUCCESS(Status))
+	{
+		if(ARGUMENT_PRESENT(Errno))
+			*Errno = _MapNtStatus(Status);
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+//
+// Raw block io. Sets dos errno
+//
+
+static
+BOOLEAN
+_BlockIo(
+    IN HANDLE Handle,
+    IN LARGE_INTEGER Offset,
+    IN ULONG Bytes,
+    IN OUT PCHAR Buffer,
+    IN BOOLEAN Read,
+    OUT unsigned* Errno
+   )
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	NTSTATUS Status;
+
+	//
+	// Should be aligned
+	//
+
+	ASSERT(0 == (Bytes % 512));
+	ASSERT(0 == (Offset.LowPart % 512));
+
+
+	//
+	// perform io
+	//
+
+	if(Read)
+	{
+		Status = NtReadFile(Handle, NULL, NULL, NULL,
+			&IoStatusBlock, Buffer, Bytes, &Offset, NULL);
+	}
+	else
+	{
+		Status = NtWriteFile(Handle, NULL, NULL, NULL,
+			&IoStatusBlock, Buffer, Bytes, &Offset, NULL);
+	}
+
+
+	//
+	// translate error
+	//
+
+	if(NT_SUCCESS(Status))
+	{
+		*Errno = 0;
+		return TRUE;
+	}
+
+	*Errno = _MapNtStatus(Status);
+
+	return FALSE;
+}
+
+
+
+__inline
+BOOLEAN
+_RawWrite(
+    IN HANDLE Handle,
+    IN LARGE_INTEGER Offset,
+    IN ULONG Bytes,
+    OUT const CHAR* Buffer,
+    OUT unsigned* Errno
+   )
+{
+	return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno);
+}
+
+__inline
+BOOLEAN
+_RawRead(
+    IN HANDLE Handle,
+    IN LARGE_INTEGER Offset,
+    IN ULONG Bytes,
+    IN PCHAR Buffer,
+    OUT unsigned* Errno
+   )
+{
+	return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno);
+}
+
+
+
+__inline
+BOOLEAN
+_SetPartType(
+    IN HANDLE Handle,
+    IN UCHAR Type
+   )
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return STATUS_SUCCESS == NtDeviceIoControlFile(
+												   Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_PARTITION_INFO,
+												   &Type, sizeof(Type),
+												   NULL, 0);
+}
+
+
+
+//--------------------- interface part
+
+//
+// Interface functions.
+// Is_mounted is set to 1 if the device is mounted, 0 otherwise
+//
+
+errcode_t
+ext2fs_check_if_mounted(const char *file, int *mount_flags)
+{
+	HANDLE h;
+	BOOLEAN Readonly;
+
+	*mount_flags = 0;
+
+	if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
+	{
+		return 0;
+	}
+
+
+	__try{
+		*mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0;
+	}
+	__finally{
+		_CloseDisk(h);
+	}
+
+	return 0;
+}
+
+
+
+//
+// Returns the number of blocks in a partition
+//
+
+static __int64 FsSize = 0;
+static char knowndevice[1024] = "";
+
+
+errcode_t
+ext2fs_get_device_size(const char *file, int blocksize,
+				 blk_t *retblocks)
+{
+	HANDLE h;
+	BOOLEAN Readonly;
+
+	if((0 == FsSize) || (0 != strcmp(knowndevice, file)))
+	{
+
+		if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
+		{
+			return 0;
+		}
+
+
+		__try{
+
+			//
+			// Get size
+			//
+
+			_GetDeviceSize(h, &FsSize);
+			strcpy(knowndevice, file);
+		}
+		__finally{
+			_CloseDisk(h);
+		}
+
+	}
+
+	*retblocks = (blk_t)(unsigned __int64)(FsSize / blocksize);
+	UNREFERENCED_PARAMETER(file);
+	return 0;
+}
+
+
+
+
+
+
+//
+// Table elements
+//
+
+
+static
+errcode_t
+nt_open(const char *name, int flags, io_channel *channel)
+{
+	io_channel      io = NULL;
+	PNT_PRIVATE_DATA NtData = NULL;
+	errcode_t Errno = 0;
+
+	//
+	// Check name
+	//
+
+	if (NULL == name)
+	{
+		return EXT2_ET_BAD_DEVICE_NAME;
+	}
+
+	__try{
+
+		//
+		// Allocate channel handle
+		//
+
+		io = (io_channel) malloc(sizeof(struct struct_io_channel));
+
+		if (NULL == io)
+		{
+			Errno = ENOMEM;
+			__leave;
+		}
+
+		RtlZeroMemory(io, sizeof(struct struct_io_channel));
+		io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+
+		NtData = (PNT_PRIVATE_DATA)malloc(sizeof(NT_PRIVATE_DATA));
+
+		if (NULL == NtData)
+		{
+			Errno = ENOMEM;
+			__leave;
+		}
+
+
+		io->manager = nt_io_manager();
+		io->name = malloc(strlen(name) + 1);
+		if (NULL == io->name)
+		{
+			Errno = ENOMEM;
+			__leave;
+		}
+
+		strcpy(io->name, name);
+		io->private_data = NtData;
+		io->block_size = 1024;
+		io->read_error = 0;
+		io->write_error = 0;
+		io->refcount = 1;
+
+		//
+		// Initialize data
+		//
+
+		RtlZeroMemory(NtData, sizeof(NT_PRIVATE_DATA));
+
+		NtData->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL;
+		NtData->BufferBlockNumber = 0xffffffff;
+		NtData->BufferSize = 1024;
+		NtData->Buffer = malloc(NtData->BufferSize);
+
+		if (NULL == NtData->Buffer)
+		{
+			Errno = ENOMEM;
+			__leave;
+		}
+
+		//
+		// Open it
+		//
+
+		if(!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &NtData->Handle, &NtData->OpenedReadonly, &Errno))
+		{
+			__leave;
+		}
+
+
+		//
+		// get size
+		//
+
+		_GetDeviceSize(NtData->Handle, &FsSize);
+		strcpy(knowndevice, name);
+
+
+		//
+		// Lock/dismount
+		//
+
+		if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
+		{
+			NtData->OpenedReadonly = TRUE;
+		}
+
+		//
+		// Done
+		//
+
+		*channel = io;
+
+
+	}
+	__finally{
+
+		if(0 != Errno)
+		{
+			//
+			// Cleanup
+			//
+
+			if (NULL != io)
+			{
+				free(io->name);
+				free(io);
+			}
+
+			if (NULL != NtData)
+			{
+				if(NULL != NtData->Handle)
+				{
+					_UnlockDrive(NtData->Handle);
+					_CloseDisk(NtData->Handle);
+				}
+
+				free(NtData->Buffer);
+				free(NtData);
+			}
+		}
+	}
+
+	return Errno;
+}
+
+
+//
+// Close api
+//
+
+static
+errcode_t
+nt_close(io_channel channel)
+{
+	PNT_PRIVATE_DATA NtData = NULL;
+
+	if(NULL == channel)
+	{
+		return 0;
+	}
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	if (--channel->refcount > 0)
+	{
+		return 0;
+	}
+
+	free(channel->name);
+	free(channel);
+
+	if (NULL != NtData)
+	{
+		if(NULL != NtData->Handle)
+		{
+			_DismountDrive(NtData->Handle);
+			_UnlockDrive(NtData->Handle);
+			_CloseDisk(NtData->Handle);
+		}
+
+		free(NtData->Buffer);
+		free(NtData);
+	}
+
+	return 0;
+}
+
+
+
+//
+// set block size
+//
+
+static
+errcode_t
+nt_set_blksize(io_channel channel, int blksize)
+{
+	PNT_PRIVATE_DATA NtData = NULL;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	if (channel->block_size != blksize)
+	{
+		channel->block_size = blksize;
+
+		free(NtData->Buffer);
+		NtData->BufferBlockNumber = 0xffffffff;
+		NtData->BufferSize = channel->block_size;
+		ASSERT(0 == (NtData->BufferSize % 512));
+
+		NtData->Buffer = malloc(NtData->BufferSize);
+
+		if (NULL == NtData->Buffer)
+		{
+			return ENOMEM;
+		}
+
+	}
+
+	return 0;
+}
+
+
+//
+// read block
+//
+
+static
+errcode_t
+nt_read_blk(io_channel channel, unsigned long block,
+			       int count, void *buf)
+{
+	PVOID BufferToRead;
+	ULONG SizeToRead;
+	ULONG Size;
+	LARGE_INTEGER Offset;
+	PNT_PRIVATE_DATA NtData = NULL;
+	unsigned Errno = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	//
+	// If it's in the cache, use it!
+	//
+
+	if ((1 == count) &&
+		(block == NtData->BufferBlockNumber) &&
+		(NtData->BufferBlockNumber != 0xffffffff))
+	{
+		memcpy(buf, NtData->Buffer, channel->block_size);
+		return 0;
+	}
+
+	Size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size);
+
+	Offset.QuadPart = block * channel->block_size;
+
+	//
+	// If not fit to the block
+	//
+
+	if(Size <= NtData->BufferSize)
+	{
+		//
+		// Update the cache
+		//
+
+		NtData->BufferBlockNumber = block;
+		BufferToRead = NtData->Buffer;
+		SizeToRead = NtData->BufferSize;
+	}
+	else
+	{
+		SizeToRead = Size;
+		BufferToRead = buf;
+		ASSERT(0 == (SizeToRead % channel->block_size));
+	}
+
+	if(!_RawRead(NtData->Handle, Offset, SizeToRead, BufferToRead, &Errno))
+	{
+
+		if (channel->read_error)
+		{
+			return (channel->read_error)(channel, block, count, buf,
+					       Size, 0, Errno);
+		}
+		else
+		{
+			return Errno;
+		}
+	}
+
+
+	if(BufferToRead != buf)
+	{
+		ASSERT(Size <= SizeToRead);
+		memcpy(buf, BufferToRead, Size);
+	}
+
+	return 0;
+}
+
+
+//
+// write block
+//
+
+static
+errcode_t
+nt_write_blk(io_channel channel, unsigned long block,
+				int count, const void *buf)
+{
+	ULONG SizeToWrite;
+	LARGE_INTEGER Offset;
+	PNT_PRIVATE_DATA NtData = NULL;
+	unsigned Errno = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	if(NtData->OpenedReadonly)
+	{
+		return EACCES;
+	}
+
+	if (count == 1)
+	{
+		SizeToWrite = channel->block_size;
+	}
+	else
+	{
+		NtData->BufferBlockNumber = 0xffffffff;
+
+		if (count < 0)
+		{
+			SizeToWrite = (ULONG)(-count);
+		}
+		else
+		{
+			SizeToWrite = (ULONG)(count * channel->block_size);
+		}
+	}
+
+
+	ASSERT(0 == (SizeToWrite % 512));
+	Offset.QuadPart = block * channel->block_size;
+
+	if(!_RawWrite(NtData->Handle, Offset, SizeToWrite, buf, &Errno))
+	{
+		if (channel->write_error)
+		{
+			return (channel->write_error)(channel, block, count, buf,
+						SizeToWrite, 0, Errno);
+		}
+		else
+		{
+			return Errno;
+		}
+	}
+
+
+	//
+	// Stash a copy.
+	//
+
+	if(SizeToWrite >= NtData->BufferSize)
+	{
+		NtData->BufferBlockNumber = block;
+		memcpy(NtData->Buffer, buf, NtData->BufferSize);
+	}
+
+	NtData->Written = TRUE;
+
+	return 0;
+
+}
+
+
+
+//
+// Flush data buffers to disk.  Since we are currently using a
+// write-through cache, this is a no-op.
+//
+
+static
+errcode_t
+nt_flush(io_channel channel)
+{
+	PNT_PRIVATE_DATA NtData = NULL;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	if(NtData->OpenedReadonly)
+	{
+		return 0; // EACCESS;
+	}
+
+
+	//
+	// Flush file buffers.
+	//
+
+	_FlushDrive(NtData->Handle);
+
+
+	//
+	// Test and correct partition type.
+	//
+
+	if(NtData->Written)
+	{
+		_SetPartType(NtData->Handle, 0x83);
+	}
+
+	return 0;
+}
+
+