Logo Search packages:      
Sourcecode: e2fsprogs version File versions

nt_io.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 Public
 * License.
 * %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 = {
      EXT2_ET_MAGIC_IO_MANAGER,
      "NT I/O Manager",
      nt_open,
      nt_close,
      nt_set_blksize,
      nt_read_blk,
      nt_write_blk,
      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 easyer
//

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 inlut 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; // Unpappable 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 letted 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)
                  {
                        if(NULL != io->name)
                        {
                              free(io->name);
                        }

                        free(io);
                  }

                  if (NULL != NtData)
                  {
                        if(NULL != NtData->Handle)
                        {
                              _UnlockDrive(NtData->Handle);
                              _CloseDisk(NtData->Handle);
                        }

                        if(NULL != NtData->Buffer)
                        {
                              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;
      }

      if(NULL != channel->name)
      {
            free(channel->name);
      }


      free(channel);

      if (NULL != NtData)
      {
            if(NULL != NtData->Handle)
            {
                  _DismountDrive(NtData->Handle);
                  _UnlockDrive(NtData->Handle);
                  _CloseDisk(NtData->Handle);
            }

            if(NULL != NtData->Buffer)
            {
                  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;
}



Generated by  Doxygen 1.6.0   Back to index