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