Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * nt_io.c --- This is the Nt I/O interface to the I/O manager.
      3  *
      4  * Implements a one-block write-through cache.
      5  *
      6  * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
      7  * Copyright (C) 1998 Andrey Shedel (andreys (at) ns.cr.cyco.com)
      8  *
      9  * %Begin-Header%
     10  * This file may be redistributed under the terms of the GNU Library
     11  * General Public License, version 2.
     12  * %End-Header%
     13  */
     14 
     15 #ifdef HAVE_CONFIG_H
     16 #include "config.h"
     17 #endif
     18 
     19 
     20 //
     21 // I need some warnings to disable...
     22 //
     23 
     24 
     25 #pragma warning(disable:4514) // unreferenced inline function has been removed
     26 #pragma warning(push,4)
     27 
     28 #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union)
     29 #pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
     30 #pragma warning(disable:4115) // named type definition in parentheses
     31 
     32 #include <ntddk.h>
     33 #include <ntdddisk.h>
     34 #include <ntstatus.h>
     35 
     36 #pragma warning(pop)
     37 
     38 
     39 //
     40 // Some native APIs.
     41 //
     42 
     43 NTSYSAPI
     44 ULONG
     45 NTAPI
     46 RtlNtStatusToDosError(
     47     IN NTSTATUS Status
     48    );
     49 
     50 NTSYSAPI
     51 NTSTATUS
     52 NTAPI
     53 NtClose(
     54     IN HANDLE Handle
     55    );
     56 
     57 
     58 NTSYSAPI
     59 NTSTATUS
     60 NTAPI
     61 NtOpenFile(
     62     OUT PHANDLE FileHandle,
     63     IN ACCESS_MASK DesiredAccess,
     64     IN POBJECT_ATTRIBUTES ObjectAttributes,
     65     OUT PIO_STATUS_BLOCK IoStatusBlock,
     66     IN ULONG ShareAccess,
     67     IN ULONG OpenOptions
     68     );
     69 
     70 NTSYSAPI
     71 NTSTATUS
     72 NTAPI
     73 NtFlushBuffersFile(
     74     IN HANDLE FileHandle,
     75     OUT PIO_STATUS_BLOCK IoStatusBlock
     76    );
     77 
     78 
     79 NTSYSAPI
     80 NTSTATUS
     81 NTAPI
     82 NtReadFile(
     83     IN HANDLE FileHandle,
     84     IN HANDLE Event OPTIONAL,
     85     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
     86     IN PVOID ApcContext OPTIONAL,
     87     OUT PIO_STATUS_BLOCK IoStatusBlock,
     88     OUT PVOID Buffer,
     89     IN ULONG Length,
     90     IN PLARGE_INTEGER ByteOffset OPTIONAL,
     91     IN PULONG Key OPTIONAL
     92     );
     93 
     94 NTSYSAPI
     95 NTSTATUS
     96 NTAPI
     97 NtWriteFile(
     98     IN HANDLE FileHandle,
     99     IN HANDLE Event OPTIONAL,
    100     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
    101     IN PVOID ApcContext OPTIONAL,
    102     OUT PIO_STATUS_BLOCK IoStatusBlock,
    103     IN PVOID Buffer,
    104     IN ULONG Length,
    105     IN PLARGE_INTEGER ByteOffset OPTIONAL,
    106     IN PULONG Key OPTIONAL
    107     );
    108 
    109 NTSYSAPI
    110 NTSTATUS
    111 NTAPI
    112 NtDeviceIoControlFile(
    113     IN HANDLE FileHandle,
    114     IN HANDLE Event OPTIONAL,
    115     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
    116     IN PVOID ApcContext OPTIONAL,
    117     OUT PIO_STATUS_BLOCK IoStatusBlock,
    118     IN ULONG IoControlCode,
    119     IN PVOID InputBuffer OPTIONAL,
    120     IN ULONG InputBufferLength,
    121     OUT PVOID OutputBuffer OPTIONAL,
    122     IN ULONG OutputBufferLength
    123     );
    124 
    125 NTSYSAPI
    126 NTSTATUS
    127 NTAPI
    128 NtFsControlFile(
    129     IN HANDLE FileHandle,
    130     IN HANDLE Event OPTIONAL,
    131     IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
    132     IN PVOID ApcContext OPTIONAL,
    133     OUT PIO_STATUS_BLOCK IoStatusBlock,
    134     IN ULONG IoControlCode,
    135     IN PVOID InputBuffer OPTIONAL,
    136     IN ULONG InputBufferLength,
    137     OUT PVOID OutputBuffer OPTIONAL,
    138     IN ULONG OutputBufferLength
    139     );
    140 
    141 
    142 NTSYSAPI
    143 NTSTATUS
    144 NTAPI
    145 NtDelayExecution(
    146     IN BOOLEAN Alertable,
    147     IN PLARGE_INTEGER Interval
    148     );
    149 
    150 
    151 #define FSCTL_LOCK_VOLUME               CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
    152 #define FSCTL_UNLOCK_VOLUME             CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
    153 #define FSCTL_DISMOUNT_VOLUME           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
    154 #define FSCTL_IS_VOLUME_MOUNTED         CTL_CODE(FILE_DEVICE_FILE_SYSTEM,10, METHOD_BUFFERED, FILE_ANY_ACCESS)
    155 
    156 
    157 //
    158 // useful macros
    159 //
    160 
    161 #define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
    162 
    163 
    164 //
    165 // Include Win32 error codes.
    166 //
    167 
    168 #include <winerror.h>
    169 
    170 //
    171 // standard stuff
    172 //
    173 
    174 #include <assert.h>
    175 #include <stdio.h>
    176 #include <string.h>
    177 #include <stdlib.h>
    178 #include <malloc.h>
    179 
    180 #include <linux/types.h>
    181 #include "ext2_fs.h"
    182 #include <errno.h>
    183 
    184 #include "et/com_err.h"
    185 #include "ext2fs/ext2fs.h"
    186 #include "ext2fs/ext2_err.h"
    187 
    188 
    189 
    190 
    191 //
    192 // For checking structure magic numbers...
    193 //
    194 
    195 
    196 #define EXT2_CHECK_MAGIC(struct, code) \
    197 	  if ((struct)->magic != (code)) return (code)
    198 
    199 #define EXT2_ET_MAGIC_NT_IO_CHANNEL  0x10ed
    200 
    201 
    202 //
    203 // Private data block
    204 //
    205 
    206 typedef struct _NT_PRIVATE_DATA {
    207 	int	   magic;
    208 	HANDLE Handle;
    209 	int	   Flags;
    210 	PCHAR  Buffer;
    211 	__u32  BufferBlockNumber;
    212 	ULONG  BufferSize;
    213 	BOOLEAN OpenedReadonly;
    214 	BOOLEAN Written;
    215 }NT_PRIVATE_DATA, *PNT_PRIVATE_DATA;
    216 
    217 
    218 
    219 //
    220 // Standard interface prototypes
    221 //
    222 
    223 static errcode_t nt_open(const char *name, int flags, io_channel *channel);
    224 static errcode_t nt_close(io_channel channel);
    225 static errcode_t nt_set_blksize(io_channel channel, int blksize);
    226 static errcode_t nt_read_blk(io_channel channel, unsigned long block,
    227 			       int count, void *data);
    228 static errcode_t nt_write_blk(io_channel channel, unsigned long block,
    229 				int count, const void *data);
    230 static errcode_t nt_flush(io_channel channel);
    231 
    232 static struct struct_io_manager struct_nt_manager = {
    233 	.magic		= EXT2_ET_MAGIC_IO_MANAGER,
    234 	.name		= "NT I/O Manager",
    235 	.open		= nt_open,
    236 	.close		= nt_close,
    237 	.set_blksize	= nt_set_blksize,
    238 	.read_blk	= nt_read_blk,
    239 	.write_blk	= nt_write_blk,
    240 	.flush		= nt_flush
    241 };
    242 
    243 //
    244 // function to get API
    245 //
    246 
    247 io_manager nt_io_manager()
    248 {
    249 	return &struct_nt_manager;
    250 }
    251 
    252 
    253 
    254 
    255 
    256 //
    257 // This is a code to convert Win32 errors to unix errno
    258 //
    259 
    260 typedef struct {
    261 	ULONG WinError;
    262 	int errnocode;
    263 }ERROR_ENTRY;
    264 
    265 static ERROR_ENTRY ErrorTable[] = {
    266         {  ERROR_INVALID_FUNCTION,       EINVAL    },
    267         {  ERROR_FILE_NOT_FOUND,         ENOENT    },
    268         {  ERROR_PATH_NOT_FOUND,         ENOENT    },
    269         {  ERROR_TOO_MANY_OPEN_FILES,    EMFILE    },
    270         {  ERROR_ACCESS_DENIED,          EACCES    },
    271         {  ERROR_INVALID_HANDLE,         EBADF     },
    272         {  ERROR_ARENA_TRASHED,          ENOMEM    },
    273         {  ERROR_NOT_ENOUGH_MEMORY,      ENOMEM    },
    274         {  ERROR_INVALID_BLOCK,          ENOMEM    },
    275         {  ERROR_BAD_ENVIRONMENT,        E2BIG     },
    276         {  ERROR_BAD_FORMAT,             ENOEXEC   },
    277         {  ERROR_INVALID_ACCESS,         EINVAL    },
    278         {  ERROR_INVALID_DATA,           EINVAL    },
    279         {  ERROR_INVALID_DRIVE,          ENOENT    },
    280         {  ERROR_CURRENT_DIRECTORY,      EACCES    },
    281         {  ERROR_NOT_SAME_DEVICE,        EXDEV     },
    282         {  ERROR_NO_MORE_FILES,          ENOENT    },
    283         {  ERROR_LOCK_VIOLATION,         EACCES    },
    284         {  ERROR_BAD_NETPATH,            ENOENT    },
    285         {  ERROR_NETWORK_ACCESS_DENIED,  EACCES    },
    286         {  ERROR_BAD_NET_NAME,           ENOENT    },
    287         {  ERROR_FILE_EXISTS,            EEXIST    },
    288         {  ERROR_CANNOT_MAKE,            EACCES    },
    289         {  ERROR_FAIL_I24,               EACCES    },
    290         {  ERROR_INVALID_PARAMETER,      EINVAL    },
    291         {  ERROR_NO_PROC_SLOTS,          EAGAIN    },
    292         {  ERROR_DRIVE_LOCKED,           EACCES    },
    293         {  ERROR_BROKEN_PIPE,            EPIPE     },
    294         {  ERROR_DISK_FULL,              ENOSPC    },
    295         {  ERROR_INVALID_TARGET_HANDLE,  EBADF     },
    296         {  ERROR_INVALID_HANDLE,         EINVAL    },
    297         {  ERROR_WAIT_NO_CHILDREN,       ECHILD    },
    298         {  ERROR_CHILD_NOT_COMPLETE,     ECHILD    },
    299         {  ERROR_DIRECT_ACCESS_HANDLE,   EBADF     },
    300         {  ERROR_NEGATIVE_SEEK,          EINVAL    },
    301         {  ERROR_SEEK_ON_DEVICE,         EACCES    },
    302         {  ERROR_DIR_NOT_EMPTY,          ENOTEMPTY },
    303         {  ERROR_NOT_LOCKED,             EACCES    },
    304         {  ERROR_BAD_PATHNAME,           ENOENT    },
    305         {  ERROR_MAX_THRDS_REACHED,      EAGAIN    },
    306         {  ERROR_LOCK_FAILED,            EACCES    },
    307         {  ERROR_ALREADY_EXISTS,         EEXIST    },
    308         {  ERROR_FILENAME_EXCED_RANGE,   ENOENT    },
    309         {  ERROR_NESTING_NOT_ALLOWED,    EAGAIN    },
    310         {  ERROR_NOT_ENOUGH_QUOTA,       ENOMEM    }
    311 };
    312 
    313 
    314 
    315 
    316 static
    317 unsigned
    318 _MapDosError (
    319     IN ULONG WinError
    320    )
    321 {
    322 	int i;
    323 
    324 	//
    325 	// Lookup
    326 	//
    327 
    328 	for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i)
    329 	{
    330 		if (WinError == ErrorTable[i].WinError)
    331 		{
    332 			return ErrorTable[i].errnocode;
    333 		}
    334 	}
    335 
    336 	//
    337 	// not in table. Check ranges
    338 	//
    339 
    340 	if ((WinError >= ERROR_WRITE_PROTECT) &&
    341 		(WinError <= ERROR_SHARING_BUFFER_EXCEEDED))
    342 	{
    343 		return EACCES;
    344 	}
    345 	else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) &&
    346 			 (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN))
    347 	{
    348 		return ENOEXEC;
    349 	}
    350 	else
    351 	{
    352 		return EINVAL;
    353 	}
    354 }
    355 
    356 
    357 
    358 
    359 
    360 
    361 
    362 //
    363 // Function to map NT status to dos error.
    364 //
    365 
    366 static
    367 __inline
    368 unsigned
    369 _MapNtStatus(
    370     IN NTSTATUS Status
    371    )
    372 {
    373 	return _MapDosError(RtlNtStatusToDosError(Status));
    374 }
    375 
    376 
    377 
    378 
    379 
    380 //
    381 // Helper functions to make things easier
    382 //
    383 
    384 static
    385 NTSTATUS
    386 _OpenNtName(
    387     IN PCSTR Name,
    388     IN BOOLEAN Readonly,
    389     OUT PHANDLE Handle,
    390     OUT PBOOLEAN OpenedReadonly OPTIONAL
    391    )
    392 {
    393 	UNICODE_STRING UnicodeString;
    394 	ANSI_STRING    AnsiString;
    395 	WCHAR Buffer[512];
    396 	NTSTATUS Status;
    397 	OBJECT_ATTRIBUTES ObjectAttributes;
    398 	IO_STATUS_BLOCK IoStatusBlock;
    399 
    400 	//
    401 	// Make Unicode name from input string
    402 	//
    403 
    404 	UnicodeString.Buffer = &Buffer[0];
    405 	UnicodeString.Length = 0;
    406 	UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!!
    407 
    408 	RtlInitAnsiString(&AnsiString, Name);
    409 
    410 	Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
    411 
    412 	if(!NT_SUCCESS(Status))
    413 	{
    414 		return Status; // Unmappable character?
    415 	}
    416 
    417 	//
    418 	// Initialize object
    419 	//
    420 
    421 	InitializeObjectAttributes(&ObjectAttributes,
    422 							   &UnicodeString,
    423 							   OBJ_CASE_INSENSITIVE,
    424 							   NULL,
    425 							   NULL );
    426 
    427 	//
    428 	// Try to open it in initial mode
    429 	//
    430 
    431 	if(ARGUMENT_PRESENT(OpenedReadonly))
    432 	{
    433 		*OpenedReadonly = Readonly;
    434 	}
    435 
    436 
    437 	Status = NtOpenFile(Handle,
    438 						SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
    439 						&ObjectAttributes,
    440 						&IoStatusBlock,
    441 						FILE_SHARE_WRITE | FILE_SHARE_READ,
    442 						FILE_SYNCHRONOUS_IO_NONALERT);
    443 
    444 	if(!NT_SUCCESS(Status))
    445 	{
    446 		//
    447 		// Maybe was just mounted? wait 0.5 sec and retry.
    448 		//
    449 
    450 		LARGE_INTEGER Interval;
    451 		Interval.QuadPart = -5000000; // 0.5 sec. from now
    452 
    453 		NtDelayExecution(FALSE, &Interval);
    454 
    455 		Status = NtOpenFile(Handle,
    456 							SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
    457 							&ObjectAttributes,
    458 							&IoStatusBlock,
    459 							FILE_SHARE_WRITE | FILE_SHARE_READ,
    460 							FILE_SYNCHRONOUS_IO_NONALERT);
    461 
    462 		//
    463 		// Try to satisfy mode
    464 		//
    465 
    466 		if((STATUS_ACCESS_DENIED == Status) && !Readonly)
    467 		{
    468 			if(ARGUMENT_PRESENT(OpenedReadonly))
    469 			{
    470 				*OpenedReadonly = TRUE;
    471 			}
    472 
    473 			Status = NtOpenFile(Handle,
    474 							SYNCHRONIZE | FILE_READ_DATA,
    475 							&ObjectAttributes,
    476 							&IoStatusBlock,
    477 							FILE_SHARE_WRITE | FILE_SHARE_READ,
    478 							FILE_SYNCHRONOUS_IO_NONALERT);
    479 		}
    480 	}
    481 
    482 
    483 
    484 	//
    485 	// done
    486 	//
    487 
    488 	return Status;
    489 }
    490 
    491 
    492 static
    493 NTSTATUS
    494 _OpenDriveLetter(
    495     IN CHAR Letter,
    496     IN BOOLEAN ReadOnly,
    497     OUT PHANDLE Handle,
    498     OUT PBOOLEAN OpenedReadonly OPTIONAL
    499    )
    500 {
    501 	CHAR Buffer[100];
    502 
    503 	sprintf(Buffer, "\\DosDevices\\%c:", Letter);
    504 
    505 	return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly);
    506 }
    507 
    508 
    509 //
    510 // Flush device
    511 //
    512 
    513 static
    514 __inline
    515 NTSTATUS
    516 _FlushDrive(
    517 		IN HANDLE Handle
    518 		)
    519 {
    520 	IO_STATUS_BLOCK IoStatusBlock;
    521 	return NtFlushBuffersFile(Handle, &IoStatusBlock);
    522 }
    523 
    524 
    525 //
    526 // lock drive
    527 //
    528 
    529 static
    530 __inline
    531 NTSTATUS
    532 _LockDrive(
    533 		IN HANDLE Handle
    534 		)
    535 {
    536 	IO_STATUS_BLOCK IoStatusBlock;
    537 	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0);
    538 }
    539 
    540 
    541 //
    542 // unlock drive
    543 //
    544 
    545 static
    546 __inline
    547 NTSTATUS
    548 _UnlockDrive(
    549 	IN HANDLE Handle
    550 	)
    551 {
    552 	IO_STATUS_BLOCK IoStatusBlock;
    553 	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0);
    554 }
    555 
    556 static
    557 __inline
    558 NTSTATUS
    559 _DismountDrive(
    560 	IN HANDLE Handle
    561 	)
    562 {
    563 	IO_STATUS_BLOCK IoStatusBlock;
    564 	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0);
    565 }
    566 
    567 
    568 //
    569 // is mounted
    570 //
    571 
    572 static
    573 __inline
    574 BOOLEAN
    575 _IsMounted(
    576 	IN HANDLE Handle
    577 	)
    578 {
    579 	IO_STATUS_BLOCK IoStatusBlock;
    580 	NTSTATUS Status;
    581 	Status = NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0);
    582 	return (BOOLEAN)(STATUS_SUCCESS == Status);
    583 }
    584 
    585 
    586 static
    587 __inline
    588 NTSTATUS
    589 _CloseDisk(
    590 		IN HANDLE Handle
    591 		)
    592 {
    593 	return NtClose(Handle);
    594 }
    595 
    596 
    597 
    598 
    599 //
    600 // Make NT name from any recognized name
    601 //
    602 
    603 static
    604 PCSTR
    605 _NormalizeDeviceName(
    606     IN PCSTR Device,
    607     IN PSTR NormalizedDeviceNameBuffer
    608    )
    609 {
    610 	int PartitionNumber = -1;
    611 	UCHAR DiskNumber;
    612 	PSTR p;
    613 
    614 
    615 	//
    616 	// Do not try to parse NT name
    617 	//
    618 
    619 	if('\\' == *Device)
    620 		return Device;
    621 
    622 
    623 
    624 	//
    625 	// Strip leading '/dev/' if any
    626 	//
    627 
    628 	if(('/' == *(Device)) &&
    629 		('d' == *(Device + 1)) &&
    630 		('e' == *(Device + 2)) &&
    631 		('v' == *(Device + 3)) &&
    632 		('/' == *(Device + 4)))
    633 	{
    634 		Device += 5;
    635 	}
    636 
    637 	if('\0' == *Device)
    638 	{
    639 		return NULL;
    640 	}
    641 
    642 
    643 	//
    644 	// forms: hda[n], fd[n]
    645 	//
    646 
    647 	if('d' != *(Device + 1))
    648 	{
    649 		return NULL;
    650 	}
    651 
    652 	if('h' == *Device)
    653 	{
    654 		if((*(Device + 2) < 'a') || (*(Device + 2) > ('a' + 9)) ||
    655 		   ((*(Device + 3) != '\0') &&
    656 			((*(Device + 4) != '\0') ||
    657 			 ((*(Device + 3) < '0') || (*(Device + 3) > '9'))
    658 			)
    659 		   )
    660 		  )
    661 		{
    662 			return NULL;
    663 		}
    664 
    665 		DiskNumber = (UCHAR)(*(Device + 2) - 'a');
    666 
    667 		if(*(Device + 3) != '\0')
    668 		{
    669 			PartitionNumber = (*(Device + 3) - '0');
    670 		}
    671 
    672 	}
    673 	else if('f' == *Device)
    674 	{
    675 		//
    676 		// 3-d letter should be a digit.
    677 		//
    678 
    679 		if((*(Device + 3) != '\0') ||
    680 		   (*(Device + 2) < '0') || (*(Device + 2) > '9'))
    681 		{
    682 			return NULL;
    683 		}
    684 
    685 		DiskNumber = (UCHAR)(*(Device + 2) - '0');
    686 
    687 	}
    688 	else
    689 	{
    690 		//
    691 		// invalid prefix
    692 		//
    693 
    694 		return NULL;
    695 	}
    696 
    697 
    698 
    699 	//
    700 	// Prefix
    701 	//
    702 
    703 	strcpy(NormalizedDeviceNameBuffer, "\\Device\\");
    704 
    705 	//
    706 	// Media name
    707 	//
    708 
    709 	switch(*Device)
    710 	{
    711 
    712 	case 'f':
    713 		strcat(NormalizedDeviceNameBuffer, "Floppy0");
    714 		break;
    715 
    716 	case 'h':
    717 		strcat(NormalizedDeviceNameBuffer, "Harddisk0");
    718 		break;
    719 	}
    720 
    721 
    722 	p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
    723 	*p = (CHAR)(*p + DiskNumber);
    724 
    725 
    726 	//
    727 	// Partition nr.
    728 	//
    729 
    730 	if(PartitionNumber >= 0)
    731 	{
    732 		strcat(NormalizedDeviceNameBuffer, "\\Partition0");
    733 
    734 		p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
    735 		*p = (CHAR)(*p + PartitionNumber);
    736 	}
    737 
    738 
    739 	return NormalizedDeviceNameBuffer;
    740 }
    741 
    742 
    743 
    744 
    745 static
    746 VOID
    747 _GetDeviceSize(
    748     IN HANDLE h,
    749     OUT unsigned __int64 *FsSize
    750    )
    751 {
    752 	PARTITION_INFORMATION pi;
    753 	DISK_GEOMETRY gi;
    754 	NTSTATUS Status;
    755 	IO_STATUS_BLOCK IoStatusBlock;
    756 
    757 	//
    758 	// Zero it
    759 	//
    760 
    761 	*FsSize = 0;
    762 
    763 	//
    764 	// Call driver
    765 	//
    766 
    767 	RtlZeroMemory(&pi, sizeof(PARTITION_INFORMATION));
    768 
    769 	Status = NtDeviceIoControlFile(
    770 		h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO,
    771 		&pi, sizeof(PARTITION_INFORMATION),
    772 		&pi, sizeof(PARTITION_INFORMATION));
    773 
    774 
    775 	if(NT_SUCCESS(Status))
    776 	{
    777 		*FsSize = pi.PartitionLength.QuadPart;
    778 	}
    779 	else if(STATUS_INVALID_DEVICE_REQUEST == Status)
    780 	{
    781 		//
    782 		// No partitions: get device info.
    783 		//
    784 
    785 		RtlZeroMemory(&gi, sizeof(DISK_GEOMETRY));
    786 
    787 		Status = NtDeviceIoControlFile(
    788 				h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_GEOMETRY,
    789 				&gi, sizeof(DISK_GEOMETRY),
    790 				&gi, sizeof(DISK_GEOMETRY));
    791 
    792 
    793 		if(NT_SUCCESS(Status))
    794 		{
    795 			*FsSize =
    796 				gi.BytesPerSector *
    797 				gi.SectorsPerTrack *
    798 				gi.TracksPerCylinder *
    799 				gi.Cylinders.QuadPart;
    800 		}
    801 
    802 	}
    803 }
    804 
    805 
    806 
    807 //
    808 // Open device by name.
    809 //
    810 
    811 static
    812 BOOLEAN
    813 _Ext2OpenDevice(
    814     IN PCSTR Name,
    815     IN BOOLEAN ReadOnly,
    816     OUT PHANDLE Handle,
    817     OUT PBOOLEAN OpenedReadonly OPTIONAL,
    818     OUT unsigned *Errno OPTIONAL
    819    )
    820 {
    821 	CHAR NormalizedDeviceName[512];
    822 	NTSTATUS Status;
    823 
    824 	if(NULL == Name)
    825 	{
    826 		//
    827 		// Set not found
    828 		//
    829 
    830 		if(ARGUMENT_PRESENT(Errno))
    831 			*Errno = ENOENT;
    832 
    833 		return FALSE;
    834 	}
    835 
    836 
    837 	if((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') &&
    838 		(':' == *(Name + 1)) && ('\0' == *(Name + 2)))
    839 	{
    840 		Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly);
    841 	}
    842 	else
    843 	{
    844 		//
    845 		// Make name
    846 		//
    847 
    848 		Name = _NormalizeDeviceName(Name, NormalizedDeviceName);
    849 
    850 		if(NULL == Name)
    851 		{
    852 			//
    853 			// Set not found
    854 			//
    855 
    856 			if(ARGUMENT_PRESENT(Errno))
    857 				*Errno = ENOENT;
    858 
    859 			return FALSE;
    860 		}
    861 
    862 		//
    863 		// Try to open it
    864 		//
    865 
    866 		Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly);
    867 	}
    868 
    869 
    870 	if(!NT_SUCCESS(Status))
    871 	{
    872 		if(ARGUMENT_PRESENT(Errno))
    873 			*Errno = _MapNtStatus(Status);
    874 
    875 		return FALSE;
    876 	}
    877 
    878 	return TRUE;
    879 }
    880 
    881 
    882 //
    883 // Raw block io. Sets dos errno
    884 //
    885 
    886 static
    887 BOOLEAN
    888 _BlockIo(
    889     IN HANDLE Handle,
    890     IN LARGE_INTEGER Offset,
    891     IN ULONG Bytes,
    892     IN OUT PCHAR Buffer,
    893     IN BOOLEAN Read,
    894     OUT unsigned* Errno
    895    )
    896 {
    897 	IO_STATUS_BLOCK IoStatusBlock;
    898 	NTSTATUS Status;
    899 
    900 	//
    901 	// Should be aligned
    902 	//
    903 
    904 	ASSERT(0 == (Bytes % 512));
    905 	ASSERT(0 == (Offset.LowPart % 512));
    906 
    907 
    908 	//
    909 	// perform io
    910 	//
    911 
    912 	if(Read)
    913 	{
    914 		Status = NtReadFile(Handle, NULL, NULL, NULL,
    915 			&IoStatusBlock, Buffer, Bytes, &Offset, NULL);
    916 	}
    917 	else
    918 	{
    919 		Status = NtWriteFile(Handle, NULL, NULL, NULL,
    920 			&IoStatusBlock, Buffer, Bytes, &Offset, NULL);
    921 	}
    922 
    923 
    924 	//
    925 	// translate error
    926 	//
    927 
    928 	if(NT_SUCCESS(Status))
    929 	{
    930 		*Errno = 0;
    931 		return TRUE;
    932 	}
    933 
    934 	*Errno = _MapNtStatus(Status);
    935 
    936 	return FALSE;
    937 }
    938 
    939 
    940 
    941 __inline
    942 BOOLEAN
    943 _RawWrite(
    944     IN HANDLE Handle,
    945     IN LARGE_INTEGER Offset,
    946     IN ULONG Bytes,
    947     OUT const CHAR* Buffer,
    948     OUT unsigned* Errno
    949    )
    950 {
    951 	return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno);
    952 }
    953 
    954 __inline
    955 BOOLEAN
    956 _RawRead(
    957     IN HANDLE Handle,
    958     IN LARGE_INTEGER Offset,
    959     IN ULONG Bytes,
    960     IN PCHAR Buffer,
    961     OUT unsigned* Errno
    962    )
    963 {
    964 	return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno);
    965 }
    966 
    967 
    968 
    969 __inline
    970 BOOLEAN
    971 _SetPartType(
    972     IN HANDLE Handle,
    973     IN UCHAR Type
    974    )
    975 {
    976 	IO_STATUS_BLOCK IoStatusBlock;
    977 	return STATUS_SUCCESS == NtDeviceIoControlFile(
    978 												   Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_PARTITION_INFO,
    979 												   &Type, sizeof(Type),
    980 												   NULL, 0);
    981 }
    982 
    983 
    984 
    985 //--------------------- interface part
    986 
    987 //
    988 // Interface functions.
    989 // Is_mounted is set to 1 if the device is mounted, 0 otherwise
    990 //
    991 
    992 errcode_t
    993 ext2fs_check_if_mounted(const char *file, int *mount_flags)
    994 {
    995 	HANDLE h;
    996 	BOOLEAN Readonly;
    997 
    998 	*mount_flags = 0;
    999 
   1000 	if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
   1001 	{
   1002 		return 0;
   1003 	}
   1004 
   1005 
   1006 	__try{
   1007 		*mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0;
   1008 	}
   1009 	__finally{
   1010 		_CloseDisk(h);
   1011 	}
   1012 
   1013 	return 0;
   1014 }
   1015 
   1016 
   1017 
   1018 //
   1019 // Returns the number of blocks in a partition
   1020 //
   1021 
   1022 static __int64 FsSize = 0;
   1023 static char knowndevice[1024] = "";
   1024 
   1025 
   1026 errcode_t
   1027 ext2fs_get_device_size(const char *file, int blocksize,
   1028 				 blk_t *retblocks)
   1029 {
   1030 	HANDLE h;
   1031 	BOOLEAN Readonly;
   1032 
   1033 	if((0 == FsSize) || (0 != strcmp(knowndevice, file)))
   1034 	{
   1035 
   1036 		if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
   1037 		{
   1038 			return 0;
   1039 		}
   1040 
   1041 
   1042 		__try{
   1043 
   1044 			//
   1045 			// Get size
   1046 			//
   1047 
   1048 			_GetDeviceSize(h, &FsSize);
   1049 			strcpy(knowndevice, file);
   1050 		}
   1051 		__finally{
   1052 			_CloseDisk(h);
   1053 		}
   1054 
   1055 	}
   1056 
   1057 	*retblocks = (blk_t)(unsigned __int64)(FsSize / blocksize);
   1058 	UNREFERENCED_PARAMETER(file);
   1059 	return 0;
   1060 }
   1061 
   1062 
   1063 
   1064 
   1065 
   1066 
   1067 //
   1068 // Table elements
   1069 //
   1070 
   1071 
   1072 static
   1073 errcode_t
   1074 nt_open(const char *name, int flags, io_channel *channel)
   1075 {
   1076 	io_channel      io = NULL;
   1077 	PNT_PRIVATE_DATA NtData = NULL;
   1078 	errcode_t Errno = 0;
   1079 
   1080 	//
   1081 	// Check name
   1082 	//
   1083 
   1084 	if (NULL == name)
   1085 	{
   1086 		return EXT2_ET_BAD_DEVICE_NAME;
   1087 	}
   1088 
   1089 	__try{
   1090 
   1091 		//
   1092 		// Allocate channel handle
   1093 		//
   1094 
   1095 		io = (io_channel) malloc(sizeof(struct struct_io_channel));
   1096 
   1097 		if (NULL == io)
   1098 		{
   1099 			Errno = ENOMEM;
   1100 			__leave;
   1101 		}
   1102 
   1103 		RtlZeroMemory(io, sizeof(struct struct_io_channel));
   1104 		io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
   1105 
   1106 		NtData = (PNT_PRIVATE_DATA)malloc(sizeof(NT_PRIVATE_DATA));
   1107 
   1108 		if (NULL == NtData)
   1109 		{
   1110 			Errno = ENOMEM;
   1111 			__leave;
   1112 		}
   1113 
   1114 
   1115 		io->manager = nt_io_manager();
   1116 		io->name = malloc(strlen(name) + 1);
   1117 		if (NULL == io->name)
   1118 		{
   1119 			Errno = ENOMEM;
   1120 			__leave;
   1121 		}
   1122 
   1123 		strcpy(io->name, name);
   1124 		io->private_data = NtData;
   1125 		io->block_size = 1024;
   1126 		io->read_error = 0;
   1127 		io->write_error = 0;
   1128 		io->refcount = 1;
   1129 
   1130 		//
   1131 		// Initialize data
   1132 		//
   1133 
   1134 		RtlZeroMemory(NtData, sizeof(NT_PRIVATE_DATA));
   1135 
   1136 		NtData->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL;
   1137 		NtData->BufferBlockNumber = 0xffffffff;
   1138 		NtData->BufferSize = 1024;
   1139 		NtData->Buffer = malloc(NtData->BufferSize);
   1140 
   1141 		if (NULL == NtData->Buffer)
   1142 		{
   1143 			Errno = ENOMEM;
   1144 			__leave;
   1145 		}
   1146 
   1147 		//
   1148 		// Open it
   1149 		//
   1150 
   1151 		if(!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &NtData->Handle, &NtData->OpenedReadonly, &Errno))
   1152 		{
   1153 			__leave;
   1154 		}
   1155 
   1156 
   1157 		//
   1158 		// get size
   1159 		//
   1160 
   1161 		_GetDeviceSize(NtData->Handle, &FsSize);
   1162 		strcpy(knowndevice, name);
   1163 
   1164 
   1165 		//
   1166 		// Lock/dismount
   1167 		//
   1168 
   1169 		if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
   1170 		{
   1171 			NtData->OpenedReadonly = TRUE;
   1172 		}
   1173 
   1174 		//
   1175 		// Done
   1176 		//
   1177 
   1178 		*channel = io;
   1179 
   1180 
   1181 	}
   1182 	__finally{
   1183 
   1184 		if(0 != Errno)
   1185 		{
   1186 			//
   1187 			// Cleanup
   1188 			//
   1189 
   1190 			if (NULL != io)
   1191 			{
   1192 				free(io->name);
   1193 				free(io);
   1194 			}
   1195 
   1196 			if (NULL != NtData)
   1197 			{
   1198 				if(NULL != NtData->Handle)
   1199 				{
   1200 					_UnlockDrive(NtData->Handle);
   1201 					_CloseDisk(NtData->Handle);
   1202 				}
   1203 
   1204 				free(NtData->Buffer);
   1205 				free(NtData);
   1206 			}
   1207 		}
   1208 	}
   1209 
   1210 	return Errno;
   1211 }
   1212 
   1213 
   1214 //
   1215 // Close api
   1216 //
   1217 
   1218 static
   1219 errcode_t
   1220 nt_close(io_channel channel)
   1221 {
   1222 	PNT_PRIVATE_DATA NtData = NULL;
   1223 
   1224 	if(NULL == channel)
   1225 	{
   1226 		return 0;
   1227 	}
   1228 
   1229 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
   1230 	NtData = (PNT_PRIVATE_DATA) channel->private_data;
   1231 	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
   1232 
   1233 	if (--channel->refcount > 0)
   1234 	{
   1235 		return 0;
   1236 	}
   1237 
   1238 	free(channel->name);
   1239 	free(channel);
   1240 
   1241 	if (NULL != NtData)
   1242 	{
   1243 		if(NULL != NtData->Handle)
   1244 		{
   1245 			_DismountDrive(NtData->Handle);
   1246 			_UnlockDrive(NtData->Handle);
   1247 			_CloseDisk(NtData->Handle);
   1248 		}
   1249 
   1250 		free(NtData->Buffer);
   1251 		free(NtData);
   1252 	}
   1253 
   1254 	return 0;
   1255 }
   1256 
   1257 
   1258 
   1259 //
   1260 // set block size
   1261 //
   1262 
   1263 static
   1264 errcode_t
   1265 nt_set_blksize(io_channel channel, int blksize)
   1266 {
   1267 	PNT_PRIVATE_DATA NtData = NULL;
   1268 
   1269 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
   1270 	NtData = (PNT_PRIVATE_DATA) channel->private_data;
   1271 	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
   1272 
   1273 	if (channel->block_size != blksize)
   1274 	{
   1275 		channel->block_size = blksize;
   1276 
   1277 		free(NtData->Buffer);
   1278 		NtData->BufferBlockNumber = 0xffffffff;
   1279 		NtData->BufferSize = channel->block_size;
   1280 		ASSERT(0 == (NtData->BufferSize % 512));
   1281 
   1282 		NtData->Buffer = malloc(NtData->BufferSize);
   1283 
   1284 		if (NULL == NtData->Buffer)
   1285 		{
   1286 			return ENOMEM;
   1287 		}
   1288 
   1289 	}
   1290 
   1291 	return 0;
   1292 }
   1293 
   1294 
   1295 //
   1296 // read block
   1297 //
   1298 
   1299 static
   1300 errcode_t
   1301 nt_read_blk(io_channel channel, unsigned long block,
   1302 			       int count, void *buf)
   1303 {
   1304 	PVOID BufferToRead;
   1305 	ULONG SizeToRead;
   1306 	ULONG Size;
   1307 	LARGE_INTEGER Offset;
   1308 	PNT_PRIVATE_DATA NtData = NULL;
   1309 	unsigned Errno = 0;
   1310 
   1311 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
   1312 	NtData = (PNT_PRIVATE_DATA) channel->private_data;
   1313 	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
   1314 
   1315 	//
   1316 	// If it's in the cache, use it!
   1317 	//
   1318 
   1319 	if ((1 == count) &&
   1320 		(block == NtData->BufferBlockNumber) &&
   1321 		(NtData->BufferBlockNumber != 0xffffffff))
   1322 	{
   1323 		memcpy(buf, NtData->Buffer, channel->block_size);
   1324 		return 0;
   1325 	}
   1326 
   1327 	Size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size);
   1328 
   1329 	Offset.QuadPart = block * channel->block_size;
   1330 
   1331 	//
   1332 	// If not fit to the block
   1333 	//
   1334 
   1335 	if(Size <= NtData->BufferSize)
   1336 	{
   1337 		//
   1338 		// Update the cache
   1339 		//
   1340 
   1341 		NtData->BufferBlockNumber = block;
   1342 		BufferToRead = NtData->Buffer;
   1343 		SizeToRead = NtData->BufferSize;
   1344 	}
   1345 	else
   1346 	{
   1347 		SizeToRead = Size;
   1348 		BufferToRead = buf;
   1349 		ASSERT(0 == (SizeToRead % channel->block_size));
   1350 	}
   1351 
   1352 	if(!_RawRead(NtData->Handle, Offset, SizeToRead, BufferToRead, &Errno))
   1353 	{
   1354 
   1355 		if (channel->read_error)
   1356 		{
   1357 			return (channel->read_error)(channel, block, count, buf,
   1358 					       Size, 0, Errno);
   1359 		}
   1360 		else
   1361 		{
   1362 			return Errno;
   1363 		}
   1364 	}
   1365 
   1366 
   1367 	if(BufferToRead != buf)
   1368 	{
   1369 		ASSERT(Size <= SizeToRead);
   1370 		memcpy(buf, BufferToRead, Size);
   1371 	}
   1372 
   1373 	return 0;
   1374 }
   1375 
   1376 
   1377 //
   1378 // write block
   1379 //
   1380 
   1381 static
   1382 errcode_t
   1383 nt_write_blk(io_channel channel, unsigned long block,
   1384 				int count, const void *buf)
   1385 {
   1386 	ULONG SizeToWrite;
   1387 	LARGE_INTEGER Offset;
   1388 	PNT_PRIVATE_DATA NtData = NULL;
   1389 	unsigned Errno = 0;
   1390 
   1391 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
   1392 	NtData = (PNT_PRIVATE_DATA) channel->private_data;
   1393 	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
   1394 
   1395 	if(NtData->OpenedReadonly)
   1396 	{
   1397 		return EACCES;
   1398 	}
   1399 
   1400 	if (count == 1)
   1401 	{
   1402 		SizeToWrite = channel->block_size;
   1403 	}
   1404 	else
   1405 	{
   1406 		NtData->BufferBlockNumber = 0xffffffff;
   1407 
   1408 		if (count < 0)
   1409 		{
   1410 			SizeToWrite = (ULONG)(-count);
   1411 		}
   1412 		else
   1413 		{
   1414 			SizeToWrite = (ULONG)(count * channel->block_size);
   1415 		}
   1416 	}
   1417 
   1418 
   1419 	ASSERT(0 == (SizeToWrite % 512));
   1420 	Offset.QuadPart = block * channel->block_size;
   1421 
   1422 	if(!_RawWrite(NtData->Handle, Offset, SizeToWrite, buf, &Errno))
   1423 	{
   1424 		if (channel->write_error)
   1425 		{
   1426 			return (channel->write_error)(channel, block, count, buf,
   1427 						SizeToWrite, 0, Errno);
   1428 		}
   1429 		else
   1430 		{
   1431 			return Errno;
   1432 		}
   1433 	}
   1434 
   1435 
   1436 	//
   1437 	// Stash a copy.
   1438 	//
   1439 
   1440 	if(SizeToWrite >= NtData->BufferSize)
   1441 	{
   1442 		NtData->BufferBlockNumber = block;
   1443 		memcpy(NtData->Buffer, buf, NtData->BufferSize);
   1444 	}
   1445 
   1446 	NtData->Written = TRUE;
   1447 
   1448 	return 0;
   1449 
   1450 }
   1451 
   1452 
   1453 
   1454 //
   1455 // Flush data buffers to disk.  Since we are currently using a
   1456 // write-through cache, this is a no-op.
   1457 //
   1458 
   1459 static
   1460 errcode_t
   1461 nt_flush(io_channel channel)
   1462 {
   1463 	PNT_PRIVATE_DATA NtData = NULL;
   1464 
   1465 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
   1466 	NtData = (PNT_PRIVATE_DATA) channel->private_data;
   1467 	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
   1468 
   1469 	if(NtData->OpenedReadonly)
   1470 	{
   1471 		return 0; // EACCESS;
   1472 	}
   1473 
   1474 
   1475 	//
   1476 	// Flush file buffers.
   1477 	//
   1478 
   1479 	_FlushDrive(NtData->Handle);
   1480 
   1481 
   1482 	//
   1483 	// Test and correct partition type.
   1484 	//
   1485 
   1486 	if(NtData->Written)
   1487 	{
   1488 		_SetPartType(NtData->Handle, 0x83);
   1489 	}
   1490 
   1491 	return 0;
   1492 }
   1493 
   1494 
   1495