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