diff options
Diffstat (limited to 'lib/ext2fs/nt_io.c')
-rw-r--r-- | lib/ext2fs/nt_io.c | 1494 |
1 files changed, 1494 insertions, 0 deletions
diff --git a/lib/ext2fs/nt_io.c b/lib/ext2fs/nt_io.c new file mode 100644 index 0000000..234f6b1 --- /dev/null +++ b/lib/ext2fs/nt_io.c @@ -0,0 +1,1494 @@ +/* + * 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; +} + + |