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