"Fossies" - the Fresh Open Source Software Archive

Member "ntfs-3g_ntfsprogs-2017.3.23/libntfs-3g/win32_io.c" (23 Mar 2017, 56061 Bytes) of package /linux/misc/ntfs-3g_ntfsprogs-2017.3.23.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "win32_io.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3g_ntfsprogs-2016.2.22_vs_3g_ntfsprogs-2017.3.23.

    1 /*
    2  * win32_io.c - A stdio-like disk I/O implementation for low-level disk access
    3  *      on Win32.  Can access an NTFS volume while it is mounted.
    4  *      Originated from the Linux-NTFS project.
    5  *
    6  * Copyright (c) 2003-2004 Lode Leroy
    7  * Copyright (c) 2003-2006 Anton Altaparmakov
    8  * Copyright (c) 2004-2005 Yuval Fledel
    9  * Copyright (c) 2012-2014 Jean-Pierre Andre
   10  *
   11  * This program/include file is free software; you can redistribute it and/or
   12  * modify it under the terms of the GNU General Public License as published
   13  * by the Free Software Foundation; either version 2 of the License, or
   14  * (at your option) any later version.
   15  *
   16  * This program/include file is distributed in the hope that it will be
   17  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
   18  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19  * GNU General Public License for more details.
   20  *
   21  * You should have received a copy of the GNU General Public License
   22  * along with this program (in the main directory of the NTFS-3G
   23  * distribution in the file COPYING); if not, write to the Free Software
   24  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   25  */
   26 
   27 #include "config.h"
   28 
   29 #ifdef HAVE_WINDOWS_H
   30 #define BOOL WINBOOL /* avoid conflicting definitions of BOOL */
   31 #include <windows.h>
   32 #undef BOOL
   33 #endif
   34 
   35 #ifdef HAVE_STDLIB_H
   36 #include <stdlib.h>
   37 #endif
   38 
   39 /*
   40  *      Definitions needed for <winioctl.h>
   41  */
   42 #ifndef _ANONYMOUS_UNION
   43 #define _ANONYMOUS_UNION
   44 #define _ANONYMOUS_STRUCT
   45 typedef unsigned long long DWORD64;
   46 #endif
   47 
   48 typedef struct {
   49         DWORD data1;     /* The first eight hexadecimal digits of the GUID. */
   50         WORD data2;     /* The first group of four hexadecimal digits. */
   51         WORD data3;     /* The second group of four hexadecimal digits. */ 
   52         char data4[8];    /* The first two bytes are the third group of four
   53                            hexadecimal digits. The remaining six bytes are the
   54                            final 12 hexadecimal digits. */
   55 } GUID;
   56 
   57 #include <winioctl.h>
   58 
   59 #ifdef HAVE_STDIO_H
   60 #include <stdio.h>
   61 #endif
   62 #ifdef HAVE_CTYPE_H
   63 #include <ctype.h>
   64 #endif
   65 #ifdef HAVE_ERRNO_H
   66 #include <errno.h>
   67 #endif
   68 #ifdef HAVE_FCNTL_H
   69 #include <fcntl.h>
   70 #endif
   71 #ifdef HAVE_SYS_STAT_H
   72 #include <sys/stat.h>
   73 #define stat stat64
   74 #define st_blocks  st_rdev /* emulate st_blocks, missing in Windows */
   75 #endif
   76 
   77 /* Prevent volume.h from being be loaded, as it conflicts with winnt.h. */
   78 #define _NTFS_VOLUME_H
   79 struct ntfs_volume;
   80 typedef struct ntfs_volume ntfs_volume;
   81 
   82 #include "debug.h"
   83 #include "types.h"
   84 #include "device.h"
   85 #include "misc.h"
   86 
   87 #define cpu_to_le16(x) (x)
   88 #define const_cpu_to_le16(x) (x)
   89 
   90 #ifndef MAX_PATH
   91 #define MAX_PATH 1024
   92 #endif
   93 
   94 #ifndef NTFS_BLOCK_SIZE
   95 #define NTFS_BLOCK_SIZE     512
   96 #define NTFS_BLOCK_SIZE_BITS    9
   97 #endif
   98 
   99 #ifndef INVALID_SET_FILE_POINTER
  100 #define INVALID_SET_FILE_POINTER ((DWORD)-1)
  101 #endif
  102 
  103 #ifndef IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
  104 #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096
  105 #endif
  106 
  107 #ifndef IOCTL_DISK_GET_DRIVE_GEOMETRY
  108 #define IOCTL_DISK_GET_DRIVE_GEOMETRY 0x70000
  109 #endif
  110 
  111 #ifndef IOCTL_GET_DISK_LENGTH_INFO
  112 #define IOCTL_GET_DISK_LENGTH_INFO 0x7405c
  113 #endif
  114 
  115 #ifndef FSCTL_ALLOW_EXTENDED_DASD_IO
  116 #define FSCTL_ALLOW_EXTENDED_DASD_IO 0x90083
  117 #endif
  118 
  119 /* Windows 2k+ imports. */
  120 typedef HANDLE (WINAPI *LPFN_FINDFIRSTVOLUME)(LPTSTR, DWORD);
  121 typedef BOOL (WINAPI *LPFN_FINDNEXTVOLUME)(HANDLE, LPTSTR, DWORD);
  122 typedef BOOL (WINAPI *LPFN_FINDVOLUMECLOSE)(HANDLE);
  123 typedef BOOL (WINAPI *LPFN_SETFILEPOINTEREX)(HANDLE, LARGE_INTEGER,
  124         PLARGE_INTEGER, DWORD);
  125 
  126 static LPFN_FINDFIRSTVOLUME fnFindFirstVolume = NULL;
  127 static LPFN_FINDNEXTVOLUME fnFindNextVolume = NULL;
  128 static LPFN_FINDVOLUMECLOSE fnFindVolumeClose = NULL;
  129 static LPFN_SETFILEPOINTEREX fnSetFilePointerEx = NULL;
  130 
  131 #ifdef UNICODE
  132 #define FNPOSTFIX "W"
  133 #else
  134 #define FNPOSTFIX "A"
  135 #endif
  136 
  137 enum { /* see http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx */
  138    STATUS_UNKNOWN = -1,
  139    STATUS_SUCCESS =              0x00000000,
  140    STATUS_BUFFER_OVERFLOW =      0x80000005,
  141    STATUS_INVALID_HANDLE =       0xC0000008,
  142    STATUS_INVALID_PARAMETER =    0xC000000D,
  143    STATUS_INVALID_DEVICE_REQUEST = 0xC0000010,
  144    STATUS_END_OF_FILE =          0xC0000011,
  145    STATUS_CONFLICTING_ADDRESSES = 0xC0000018,
  146    STATUS_NO_MATCH =             0xC000001E,
  147    STATUS_ACCESS_DENIED =        0xC0000022,
  148    STATUS_BUFFER_TOO_SMALL =     0xC0000023,
  149    STATUS_OBJECT_TYPE_MISMATCH = 0xC0000024,
  150    STATUS_FILE_NOT_FOUND =       0xC0000028,
  151    STATUS_OBJECT_NAME_INVALID =  0xC0000033,
  152    STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
  153    STATUS_SHARING_VIOLATION =    0xC0000043,
  154    STATUS_INVALID_PARAMETER_1 =  0xC00000EF,
  155    STATUS_IO_DEVICE_ERROR =      0xC0000185,
  156    STATUS_GUARD_PAGE_VIOLATION = 0x80000001
  157  } ;
  158 
  159 typedef u32 NTSTATUS; /* do not let the compiler choose the size */
  160 #ifdef __x86_64__
  161 typedef unsigned long long ULONG_PTR; /* an integer the same size as a pointer */
  162 #else
  163 typedef unsigned long ULONG_PTR; /* an integer the same size as a pointer */
  164 #endif
  165 
  166 HANDLE get_osfhandle(int); /* from msvcrt.dll */
  167 
  168 /*
  169  *      A few needed definitions not included in <windows.h>
  170  */
  171 
  172 typedef struct _IO_STATUS_BLOCK {
  173     union {
  174         NTSTATUS Status;
  175         PVOID    Pointer;
  176     };
  177     ULONG_PTR Information;
  178 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
  179 
  180 typedef struct _UNICODE_STRING {
  181     USHORT Length;
  182     USHORT MaximumLength;
  183 #ifdef __x86_64__
  184     u32    padding;
  185 #endif
  186     PWSTR  Buffer;
  187 } UNICODE_STRING, *PUNICODE_STRING;
  188 
  189 typedef struct _OBJECT_ATTRIBUTES {
  190     ULONG           Length;
  191 #ifdef __x86_64__
  192     u32     padding1;
  193     HANDLE          RootDirectory;
  194     PUNICODE_STRING ObjectName;
  195     ULONG           Attributes;
  196     u32     padding2;
  197 #else
  198     HANDLE          RootDirectory;
  199     PUNICODE_STRING ObjectName;
  200     ULONG           Attributes;
  201 #endif
  202     PVOID           SecurityDescriptor;
  203     PVOID           SecurityQualityOfService;
  204 }  OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
  205 
  206 #define FILE_OPEN 1
  207 #define FILE_CREATE 2
  208 #define FILE_OVERWRITE 4
  209 #define FILE_SYNCHRONOUS_IO_ALERT    0x10
  210 #define FILE_SYNCHRONOUS_IO_NONALERT 0x20
  211 #define OBJ_CASE_INSENSITIVE 0x40
  212 
  213 typedef void (WINAPI *PIO_APC_ROUTINE)(void*, PIO_STATUS_BLOCK, ULONG);
  214 
  215 extern WINAPI NTSTATUS NtOpenFile(
  216     PHANDLE FileHandle,
  217     ACCESS_MASK DesiredAccess,
  218     POBJECT_ATTRIBUTES ObjectAttributes,
  219     PIO_STATUS_BLOCK IoStatusBlock,
  220     ULONG ShareAccess,
  221     ULONG OpenOptions
  222 );
  223 
  224 extern WINAPI NTSTATUS NtReadFile(
  225     HANDLE FileHandle,
  226     HANDLE Event,
  227     PIO_APC_ROUTINE ApcRoutine,
  228     PVOID ApcContext,
  229     PIO_STATUS_BLOCK IoStatusBlock,
  230     PVOID Buffer,
  231     ULONG Length,
  232     PLARGE_INTEGER ByteOffset,
  233     PULONG Key
  234 );
  235 
  236 extern WINAPI NTSTATUS NtWriteFile(
  237     HANDLE FileHandle,
  238     HANDLE Event,
  239     PIO_APC_ROUTINE ApcRoutine,
  240     PVOID ApcContext,
  241     PIO_STATUS_BLOCK IoStatusBlock,
  242     LPCVOID Buffer,
  243     ULONG Length,
  244     PLARGE_INTEGER ByteOffset,
  245     PULONG Key
  246 );
  247 
  248 extern NTSTATUS WINAPI NtClose(
  249     HANDLE Handle
  250 );
  251 
  252 extern NTSTATUS WINAPI NtDeviceIoControlFile(
  253     HANDLE FileHandle,
  254     HANDLE Event,
  255     PIO_APC_ROUTINE ApcRoutine,
  256     PVOID ApcContext,
  257     PIO_STATUS_BLOCK IoStatusBlock,
  258     ULONG IoControlCode,
  259     PVOID InputBuffer,
  260     ULONG InputBufferLength,
  261     PVOID OutputBuffer,
  262     ULONG OutputBufferLength
  263 );
  264 
  265 extern NTSTATUS WINAPI NtFsControlFile(
  266     HANDLE FileHandle,
  267     HANDLE Event,
  268     PIO_APC_ROUTINE ApcRoutine,
  269     PVOID ApcContext,
  270     PIO_STATUS_BLOCK IoStatusBlock,
  271     ULONG FsControlCode,
  272     PVOID InputBuffer,
  273     ULONG InputBufferLength,
  274     PVOID OutputBuffer,
  275     ULONG OutputBufferLength
  276 );
  277 
  278 /**
  279  * struct win32_fd -
  280  */
  281 typedef struct {
  282     HANDLE handle;
  283     s64 pos;        /* Logical current position on the volume. */
  284     s64 part_start;
  285     s64 part_length;
  286     int part_hidden_sectors;
  287     s64 geo_size, geo_cylinders;
  288     s32 geo_sector_size;
  289     s64 volume_size;
  290     DWORD geo_sectors, geo_heads;
  291     HANDLE vol_handle;
  292     BOOL ntdll;
  293 } win32_fd;
  294 
  295 /**
  296  * ntfs_w32error_to_errno - convert a win32 error code to the unix one
  297  * @w32error:   the win32 error code
  298  *
  299  * Limited to a relatively small but useful number of codes.
  300  */
  301 static int ntfs_w32error_to_errno(unsigned int w32error)
  302 {
  303     ntfs_log_trace("Converting w32error 0x%x.\n",w32error);
  304     switch (w32error) {
  305         case ERROR_INVALID_FUNCTION:
  306             return EBADRQC;
  307         case ERROR_FILE_NOT_FOUND:
  308         case ERROR_PATH_NOT_FOUND:
  309         case ERROR_INVALID_NAME:
  310             return ENOENT;
  311         case ERROR_TOO_MANY_OPEN_FILES:
  312             return EMFILE;
  313         case ERROR_ACCESS_DENIED:
  314             return EACCES;
  315         case ERROR_INVALID_HANDLE:
  316             return EBADF;
  317         case ERROR_NOT_ENOUGH_MEMORY:
  318             return ENOMEM;
  319         case ERROR_OUTOFMEMORY:
  320             return ENOSPC;
  321         case ERROR_INVALID_DRIVE:
  322         case ERROR_BAD_UNIT:
  323             return ENODEV;
  324         case ERROR_WRITE_PROTECT:
  325             return EROFS;
  326         case ERROR_NOT_READY:
  327         case ERROR_SHARING_VIOLATION:
  328             return EBUSY;
  329         case ERROR_BAD_COMMAND:
  330             return EINVAL;
  331         case ERROR_SEEK:
  332         case ERROR_NEGATIVE_SEEK:
  333             return ESPIPE;
  334         case ERROR_NOT_SUPPORTED:
  335             return EOPNOTSUPP;
  336         case ERROR_BAD_NETPATH:
  337             return ENOSHARE;
  338         default:
  339             /* generic message */
  340             return ENOMSG;
  341     }
  342 }
  343 
  344 static int ntfs_ntstatus_to_errno(NTSTATUS status)
  345 {
  346     ntfs_log_trace("Converting w32error 0x%x.\n",w32error);
  347     switch (status) {
  348         case STATUS_INVALID_HANDLE :
  349         case STATUS_INVALID_PARAMETER :
  350         case STATUS_OBJECT_NAME_INVALID :
  351         case STATUS_INVALID_DEVICE_REQUEST :
  352             return (EINVAL);
  353         case STATUS_ACCESS_DENIED :
  354             return (EACCES);
  355         case STATUS_IO_DEVICE_ERROR :
  356         case STATUS_END_OF_FILE :
  357             return (EIO);
  358         case STATUS_SHARING_VIOLATION :
  359             return (EBUSY);
  360         default:
  361             /* generic message */
  362             return ENOMSG;
  363     }
  364 }
  365 
  366 /**
  367  * libntfs_SetFilePointerEx - emulation for SetFilePointerEx()
  368  *
  369  * We use this to emulate SetFilePointerEx() when it is not present.  This can
  370  * happen since SetFilePointerEx() only exists in Win2k+.
  371  */
  372 static BOOL WINAPI libntfs_SetFilePointerEx(HANDLE hFile,
  373         LARGE_INTEGER liDistanceToMove,
  374         PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
  375 {
  376     liDistanceToMove.u.LowPart = SetFilePointer(hFile,
  377             liDistanceToMove.u.LowPart,
  378             &liDistanceToMove.u.HighPart, dwMoveMethod);
  379     SetLastError(NO_ERROR);
  380     if (liDistanceToMove.u.LowPart == INVALID_SET_FILE_POINTER &&
  381             GetLastError() != NO_ERROR) {
  382         if (lpNewFilePointer)
  383             lpNewFilePointer->QuadPart = -1;
  384         return FALSE;
  385     }
  386     if (lpNewFilePointer)
  387         lpNewFilePointer->QuadPart = liDistanceToMove.QuadPart;
  388     return TRUE;
  389 }
  390 
  391 /**
  392  * ntfs_device_win32_init_imports - initialize the function pointers
  393  *
  394  * The Find*Volume and SetFilePointerEx functions exist only on win2k+, as such
  395  * we cannot just staticly import them.
  396  *
  397  * This function initializes the imports if the functions do exist and in the
  398  * SetFilePointerEx case, we emulate the function ourselves if it is not
  399  * present.
  400  *
  401  * Note: The values are cached, do be afraid to run it more than once.
  402  */
  403 static void ntfs_device_win32_init_imports(void)
  404 {
  405     HMODULE kernel32 = GetModuleHandle("kernel32");
  406     if (!kernel32) {
  407         errno = ntfs_w32error_to_errno(GetLastError());
  408         ntfs_log_trace("kernel32.dll could not be imported.\n");
  409     }
  410     if (!fnSetFilePointerEx) {
  411         if (kernel32)
  412             fnSetFilePointerEx = (LPFN_SETFILEPOINTEREX)
  413                     GetProcAddress(kernel32,
  414                     "SetFilePointerEx");
  415         /*
  416          * If we did not get kernel32.dll or it is not Win2k+, emulate
  417          * SetFilePointerEx().
  418          */
  419         if (!fnSetFilePointerEx) {
  420             ntfs_log_debug("SetFilePointerEx() not found in "
  421                     "kernel32.dll: Enabling emulation.\n");
  422             fnSetFilePointerEx = libntfs_SetFilePointerEx;
  423         }
  424     }
  425     /* Cannot do lookups if we could not get kernel32.dll... */
  426     if (!kernel32)
  427         return;
  428     if (!fnFindFirstVolume)
  429         fnFindFirstVolume = (LPFN_FINDFIRSTVOLUME)
  430                 GetProcAddress(kernel32, "FindFirstVolume"
  431                 FNPOSTFIX);
  432     if (!fnFindNextVolume)
  433         fnFindNextVolume = (LPFN_FINDNEXTVOLUME)
  434                 GetProcAddress(kernel32, "FindNextVolume"
  435                 FNPOSTFIX);
  436     if (!fnFindVolumeClose)
  437         fnFindVolumeClose = (LPFN_FINDVOLUMECLOSE)
  438                 GetProcAddress(kernel32, "FindVolumeClose");
  439 }
  440 
  441 /**
  442  * ntfs_device_unix_status_flags_to_win32 - convert unix->win32 open flags
  443  * @flags:  unix open status flags
  444  *
  445  * Supported flags are O_RDONLY, O_WRONLY and O_RDWR.
  446  */
  447 static __inline__ int ntfs_device_unix_status_flags_to_win32(int flags)
  448 {
  449     int win_mode;
  450 
  451     switch (flags & O_ACCMODE) {
  452     case O_RDONLY:
  453         win_mode = GENERIC_READ;
  454         break;
  455     case O_WRONLY:
  456         win_mode = GENERIC_WRITE;
  457         break;
  458     case O_RDWR:
  459         win_mode = GENERIC_READ | GENERIC_WRITE;
  460         break;
  461     default:
  462         /* error */
  463         ntfs_log_trace("Unknown status flags.\n");
  464         win_mode = 0;
  465     }
  466     return win_mode;
  467 }
  468 
  469 
  470 /**
  471  * ntfs_device_win32_simple_open_file - just open a file via win32 API
  472  * @filename:   name of the file to open
  473  * @handle: pointer the a HANDLE in which to put the result
  474  * @flags:  unix open status flags
  475  * @locking:    will the function gain an exclusive lock on the file?
  476  *
  477  * Supported flags are O_RDONLY, O_WRONLY and O_RDWR.
  478  *
  479  * Return 0 if o.k.
  480  *   -1 if not, and errno set.  In this case handle is trashed.
  481  */
  482 static int ntfs_device_win32_simple_open_file(const char *filename,
  483         HANDLE *handle, int flags, BOOL locking)
  484 {
  485     *handle = CreateFile(filename,
  486             ntfs_device_unix_status_flags_to_win32(flags),
  487             locking ? 0 : (FILE_SHARE_WRITE | FILE_SHARE_READ),
  488             NULL, (flags & O_CREAT ? OPEN_ALWAYS : OPEN_EXISTING),
  489             0, NULL);
  490     if (*handle == INVALID_HANDLE_VALUE) {
  491         errno = ntfs_w32error_to_errno(GetLastError());
  492         ntfs_log_trace("CreateFile(%s) failed.\n", filename);
  493         return -1;
  494     }
  495     return 0;
  496 }
  497 
  498 /**
  499  * ntfs_device_win32_lock - lock the volume
  500  * @handle: a win32 HANDLE for a volume to lock
  501  *
  502  * Locking a volume means no one can access its contents.
  503  * Exiting the process automatically unlocks the volume, except in old NT4s.
  504  *
  505  * Return 0 if o.k.
  506  *   -1 if not, and errno set.
  507  */
  508 static int ntfs_device_win32_lock(HANDLE handle)
  509 {
  510     DWORD i;
  511 
  512     if (!DeviceIoControl(handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &i,
  513             NULL)) {
  514         errno = ntfs_w32error_to_errno(GetLastError());
  515         ntfs_log_trace("Couldn't lock volume.\n");
  516         return -1;
  517     }
  518     ntfs_log_debug("Volume locked.\n");
  519     return 0;
  520 }
  521 
  522 /**
  523  * ntfs_device_win32_unlock - unlock the volume
  524  * @handle: the win32 HANDLE which the volume was locked with
  525  *
  526  * Return 0 if o.k.
  527  *   -1 if not, and errno set.
  528  */
  529 static int ntfs_device_win32_unlock(HANDLE handle)
  530 {
  531     DWORD i;
  532 
  533     if (!DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &i,
  534             NULL)) {
  535         errno = ntfs_w32error_to_errno(GetLastError());
  536         ntfs_log_trace("Couldn't unlock volume.\n");
  537         return -1;
  538     }
  539     ntfs_log_debug("Volume unlocked.\n");
  540     return 0;
  541 }
  542 
  543 static int ntfs_device_win32_setlock(HANDLE handle, ULONG code)
  544 {
  545     IO_STATUS_BLOCK io_status;
  546     NTSTATUS res;
  547 
  548     io_status.Status = STATUS_SUCCESS;
  549     io_status.Information = 0;
  550     res = NtFsControlFile(handle,(HANDLE)NULL,
  551                 (PIO_APC_ROUTINE)NULL,(void*)NULL,
  552                 &io_status, code,
  553                 (char*)NULL,0,(char*)NULL,0);
  554     if (res != STATUS_SUCCESS)
  555         errno = ntfs_ntstatus_to_errno(res);
  556     return (res == STATUS_SUCCESS ? 0 : -1);
  557 }
  558 
  559 /**
  560  * ntfs_device_win32_dismount - dismount a volume
  561  * @handle: a win32 HANDLE for a volume to dismount
  562  *
  563  * Dismounting means the system will refresh the volume in the first change it
  564  * gets.  Usefull after altering the file structures.
  565  * The volume must be locked by the current process while dismounting.
  566  * A side effect is that the volume is also unlocked, but you must not rely om
  567  * this.
  568  *
  569  * Return 0 if o.k.
  570  *   -1 if not, and errno set.
  571  */
  572 static int ntfs_device_win32_dismount(HANDLE handle)
  573 {
  574     DWORD i;
  575 
  576     if (!DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0,
  577             &i, NULL)) {
  578         errno = ntfs_w32error_to_errno(GetLastError());
  579         ntfs_log_trace("Couldn't dismount volume.\n");
  580         return -1;
  581     }
  582     ntfs_log_debug("Volume dismounted.\n");
  583     return 0;
  584 }
  585 
  586 /**
  587  * ntfs_device_win32_getsize - get file size via win32 API
  588  * @handle: pointer the file HANDLE obtained via open
  589  *
  590  * Only works on ordinary files.
  591  *
  592  * Return The file size if o.k.
  593  *   -1 if not, and errno set.
  594  */
  595 static s64 ntfs_device_win32_getsize(HANDLE handle)
  596 {
  597     LONG loword, hiword;
  598 
  599     SetLastError(NO_ERROR);
  600     hiword = 0;
  601     loword = SetFilePointer(handle, 0, &hiword, 2);
  602     if ((loword == INVALID_SET_FILE_POINTER)
  603         && (GetLastError() != NO_ERROR)) {
  604         errno = ntfs_w32error_to_errno(GetLastError());
  605         ntfs_log_trace("Couldn't get file size.\n");
  606         return -1;
  607     }
  608     return ((s64)hiword << 32) + (ULONG)loword;
  609 }
  610 
  611 /**
  612  * ntfs_device_win32_getdisklength - get disk size via win32 API
  613  * @handle: pointer the file HANDLE obtained via open
  614  * @argp:   pointer to result buffer
  615  *
  616  * Only works on PhysicalDriveX type handles.
  617  *
  618  * Return The disk size if o.k.
  619  *   -1 if not, and errno set.
  620  */
  621 static s64 ntfs_device_win32_getdisklength(HANDLE handle)
  622 {
  623     GET_LENGTH_INFORMATION buf;
  624     DWORD i;
  625 
  626     if (!DeviceIoControl(handle, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf,
  627             sizeof(buf), &i, NULL)) {
  628         errno = ntfs_w32error_to_errno(GetLastError());
  629         ntfs_log_trace("Couldn't get disk length.\n");
  630         return -1;
  631     }
  632     ntfs_log_debug("Disk length: %lld.\n", buf.Length.QuadPart);
  633     return buf.Length.QuadPart;
  634 }
  635 
  636 /**
  637  * ntfs_device_win32_getntfssize - get NTFS volume size via win32 API
  638  * @handle: pointer the file HANDLE obtained via open
  639  * @argp:   pointer to result buffer
  640  *
  641  * Only works on NTFS volume handles.
  642  * An annoying bug in windows is that an NTFS volume does not occupy the entire
  643  * partition, namely not the last sector (which holds the backup boot sector,
  644  * and normally not interesting).
  645  * Use this function to get the length of the accessible space through a given
  646  * volume handle.
  647  *
  648  * Return The volume size if o.k.
  649  *   -1 if not, and errno set.
  650  */
  651 static s64 ntfs_device_win32_getntfssize(HANDLE handle)
  652 {
  653     s64 rvl;
  654 #ifdef FSCTL_GET_NTFS_VOLUME_DATA
  655     DWORD i;
  656     NTFS_VOLUME_DATA_BUFFER buf;
  657 
  658     if (!DeviceIoControl(handle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &buf,
  659             sizeof(buf), &i, NULL)) {
  660         errno = ntfs_w32error_to_errno(GetLastError());
  661         ntfs_log_trace("Couldn't get NTFS volume length.\n");
  662         return -1;
  663     }
  664     rvl = buf.NumberSectors.QuadPart * buf.BytesPerSector;
  665     ntfs_log_debug("NTFS volume length: 0x%llx.\n", (long long)rvl);
  666 #else
  667     errno = EINVAL;
  668     rvl = -1;
  669 #endif
  670     return rvl;
  671 }
  672 
  673 /**
  674  * ntfs_device_win32_getgeo - get CHS information of a drive
  675  * @handle: an open handle to the PhysicalDevice
  676  * @fd:     a win_fd structure that will be filled
  677  *
  678  * Return 0 if o.k.
  679  *   -1 if not, and errno  set.
  680  *
  681  * In Windows NT+: fills size, sectors, and cylinders and sets heads to -1.
  682  * In Windows XP+: fills size, sectors, cylinders, and heads.
  683  *
  684  * Note: In pre XP, this requires write permission, even though nothing is
  685  * actually written.
  686  *
  687  * If fails, sets sectors, cylinders, heads, and size to -1.
  688  */
  689 static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd)
  690 {
  691     DWORD i;
  692     BOOL rvl;
  693     BYTE b[sizeof(DISK_GEOMETRY) + sizeof(DISK_PARTITION_INFO) +
  694             sizeof(DISK_DETECTION_INFO) + 512];
  695 
  696     rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL,
  697             0, &b, sizeof(b), &i, NULL);
  698     if (rvl) {
  699         ntfs_log_debug("GET_DRIVE_GEOMETRY_EX detected.\n");
  700         DISK_DETECTION_INFO *ddi = (PDISK_DETECTION_INFO)
  701                 (((PBYTE)(&((PDISK_GEOMETRY_EX)b)->Data)) +
  702                 (((PDISK_PARTITION_INFO)
  703                 (&((PDISK_GEOMETRY_EX)b)->Data))->
  704                 SizeOfPartitionInfo));
  705         fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart;
  706         fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack;
  707         fd->geo_size = ((DISK_GEOMETRY_EX*)&b)->DiskSize.QuadPart;
  708         fd->geo_sector_size = NTFS_BLOCK_SIZE;
  709         switch (ddi->DetectionType) {
  710         case DetectInt13:
  711             fd->geo_cylinders = ddi->Int13.MaxCylinders;
  712             fd->geo_sectors = ddi->Int13.SectorsPerTrack;
  713             fd->geo_heads = ddi->Int13.MaxHeads;
  714             return 0;
  715         case DetectExInt13:
  716             fd->geo_cylinders = ddi->ExInt13.ExCylinders;
  717             fd->geo_sectors = ddi->ExInt13.ExSectorsPerTrack;
  718             fd->geo_heads = ddi->ExInt13.ExHeads;
  719             return 0;
  720         case DetectNone:
  721         default:
  722             break;
  723         }
  724     } else
  725         fd->geo_heads = -1;
  726     rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
  727             &b, sizeof(b), &i, NULL);
  728     if (rvl) {
  729         ntfs_log_debug("GET_DRIVE_GEOMETRY detected.\n");
  730         fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart;
  731         fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack;
  732         fd->geo_size = fd->geo_cylinders * fd->geo_sectors *
  733                 ((DISK_GEOMETRY*)&b)->TracksPerCylinder *
  734                 ((DISK_GEOMETRY*)&b)->BytesPerSector;
  735         fd->geo_sector_size = ((DISK_GEOMETRY*)&b)->BytesPerSector;
  736         return 0;
  737     }
  738     errno = ntfs_w32error_to_errno(GetLastError());
  739     ntfs_log_trace("Couldn't retrieve disk geometry.\n");
  740     fd->geo_cylinders = -1;
  741     fd->geo_sectors = -1;
  742     fd->geo_size = -1;
  743     fd->geo_sector_size = NTFS_BLOCK_SIZE;
  744     return -1;
  745 }
  746 
  747 static int ntfs_device_win32_getntgeo(HANDLE handle, win32_fd *fd)
  748 {
  749     DISK_GEOMETRY geo;
  750     NTSTATUS st;
  751     IO_STATUS_BLOCK status;
  752     u64 bytes;
  753     int res;
  754 
  755     res = -1;
  756     fd->geo_cylinders = 0;
  757     fd->geo_sectors = 0;
  758     fd->geo_size = 1073741824;
  759     fd->geo_sectors = fd->geo_size >> 9;
  760     fd->geo_sector_size = NTFS_BLOCK_SIZE;
  761 
  762     st = NtDeviceIoControlFile(handle, (HANDLE)NULL,
  763             (PIO_APC_ROUTINE)NULL, (void*)NULL,
  764             &status, IOCTL_DISK_GET_DRIVE_GEOMETRY, (void*)NULL, 0,
  765             (void*)&geo, sizeof(geo));
  766     if (st == STATUS_SUCCESS) {
  767         /* over-estimate the (rounded) number of cylinders */
  768         fd->geo_cylinders = geo.Cylinders.QuadPart + 1;
  769         fd->geo_sectors = fd->geo_cylinders
  770                 *geo.TracksPerCylinder*geo.SectorsPerTrack;
  771         fd->geo_size = fd->geo_sectors*geo.BytesPerSector;
  772         fd->geo_sector_size = geo.BytesPerSector;
  773         res = 0;
  774             /* try to get the exact sector count */
  775         st = NtDeviceIoControlFile(handle, (HANDLE)NULL,
  776                 (PIO_APC_ROUTINE)NULL, (void*)NULL,
  777                 &status, IOCTL_GET_DISK_LENGTH_INFO,
  778                 (void*)NULL, 0,
  779                 (void*)&bytes, sizeof(bytes));
  780         if (st == STATUS_SUCCESS) {
  781             fd->geo_size = bytes;
  782             fd->geo_sectors = bytes/geo.BytesPerSector;
  783         }
  784     }
  785     return (res);
  786 }
  787 
  788 /**
  789  * ntfs_device_win32_open_file - open a file via win32 API
  790  * @filename:   name of the file to open
  791  * @fd:     pointer to win32 file device in which to put the result
  792  * @flags:  unix open status flags
  793  *
  794  * Return 0 if o.k.
  795  *   -1 if not, and errno set.
  796  */
  797 static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd,
  798         int flags)
  799 {
  800     HANDLE handle;
  801     int mode;
  802 
  803     if (ntfs_device_win32_simple_open_file(filename, &handle, flags,
  804             FALSE)) {
  805         /* open error */
  806         return -1;
  807     }
  808     mode = flags & O_ACCMODE;
  809     if ((mode == O_RDWR) || (mode == O_WRONLY)) {
  810         DWORD bytes;
  811 
  812         /* try making sparse (but ignore errors) */
  813         DeviceIoControl(handle, FSCTL_SET_SPARSE,
  814                 (void*)NULL, 0, (void*)NULL, 0,
  815                 &bytes, (LPOVERLAPPED)NULL);
  816     }
  817     /* fill fd */
  818     fd->handle = handle;
  819     fd->part_start = 0;
  820     fd->part_length = ntfs_device_win32_getsize(handle);
  821     fd->pos = 0;
  822     fd->part_hidden_sectors = -1;
  823     fd->geo_size = -1;  /* used as a marker that this is a file */
  824     fd->vol_handle = INVALID_HANDLE_VALUE;
  825     fd->geo_sector_size = 512;  /* will be adjusted from the boot sector */
  826     fd->ntdll = FALSE;
  827     return 0;
  828 }
  829 
  830 /**
  831  * ntfs_device_win32_open_drive - open a drive via win32 API
  832  * @drive_id:   drive to open
  833  * @fd:     pointer to win32 file device in which to put the result
  834  * @flags:  unix open status flags
  835  *
  836  * return 0 if o.k.
  837  *        -1 if not, and errno set.
  838  */
  839 static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd,
  840         int flags)
  841 {
  842     HANDLE handle;
  843     int err;
  844     char filename[MAX_PATH];
  845 
  846     sprintf(filename, "\\\\.\\PhysicalDrive%d", drive_id);
  847     if ((err = ntfs_device_win32_simple_open_file(filename, &handle, flags,
  848             TRUE))) {
  849         /* open error */
  850         return err;
  851     }
  852     /* store the drive geometry */
  853     ntfs_device_win32_getgeo(handle, fd);
  854     /* Just to be sure */
  855     if (fd->geo_size == -1)
  856         fd->geo_size = ntfs_device_win32_getdisklength(handle);
  857     /* fill fd */
  858     fd->ntdll = FALSE;
  859     fd->handle = handle;
  860     fd->part_start = 0;
  861     fd->part_length = fd->geo_size;
  862     fd->pos = 0;
  863     fd->part_hidden_sectors = -1;
  864     fd->vol_handle = INVALID_HANDLE_VALUE;
  865     return 0;
  866 }
  867 
  868 /**
  869  * ntfs_device_win32_open_lowlevel - open a drive via low level win32 API
  870  * @drive_id:   drive to open
  871  * @fd:     pointer to win32 file device in which to put the result
  872  * @flags:  unix open status flags
  873  *
  874  * return 0 if o.k.
  875  *        -1 if not, and errno set.
  876  */
  877 static __inline__ int ntfs_device_win32_open_lowlevel(int drive_id,
  878         win32_fd *fd, int flags)
  879 {
  880     HANDLE handle;
  881     NTSTATUS st;
  882     ACCESS_MASK access;
  883     ULONG share;
  884     OBJECT_ATTRIBUTES attr;
  885     IO_STATUS_BLOCK io_status;
  886     UNICODE_STRING unicode_name;
  887     ntfschar unicode_buffer[7];
  888     int mode;
  889     static const ntfschar unicode_init[] = {
  890         const_cpu_to_le16('\\'), const_cpu_to_le16('?'),
  891         const_cpu_to_le16('?'), const_cpu_to_le16('\\'),
  892         const_cpu_to_le16(' '), const_cpu_to_le16(':'),
  893         const_cpu_to_le16(0)
  894     };
  895 
  896     memcpy(unicode_buffer, unicode_init, sizeof(unicode_buffer));
  897     unicode_buffer[4] = cpu_to_le16(drive_id + 'A');
  898     unicode_name.Buffer = unicode_buffer;
  899     unicode_name.Length = 6*sizeof(ntfschar);
  900     unicode_name.MaximumLength = 6*sizeof(ntfschar);
  901 
  902     attr.Length = sizeof(OBJECT_ATTRIBUTES);
  903     attr.RootDirectory = (HANDLE*)NULL;
  904     attr.ObjectName = &unicode_name;
  905     attr.Attributes = OBJ_CASE_INSENSITIVE;
  906     attr.SecurityDescriptor = (void*)NULL;
  907     attr.SecurityQualityOfService = (void*)NULL;
  908 
  909     io_status.Status = 0;
  910     io_status.Information = 0;
  911     mode = flags & O_ACCMODE;
  912     share = (mode == O_RDWR ?
  913             0 : FILE_SHARE_READ | FILE_SHARE_WRITE);
  914     access = (mode == O_RDWR ?
  915              FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE
  916             : FILE_READ_DATA | SYNCHRONIZE);
  917 
  918     st = NtOpenFile(&handle, access,
  919             &attr, &io_status,
  920             share,
  921             FILE_SYNCHRONOUS_IO_ALERT);
  922     if (st != STATUS_SUCCESS) {
  923         errno = ntfs_ntstatus_to_errno(st);
  924         return (-1);
  925     }
  926     ntfs_device_win32_setlock(handle,FSCTL_LOCK_VOLUME);
  927     /* store the drive geometry */
  928     ntfs_device_win32_getntgeo(handle, fd);
  929     fd->ntdll = TRUE;
  930     /* allow accessing the full partition */
  931     st = NtFsControlFile(handle, (HANDLE)NULL,
  932             (PIO_APC_ROUTINE)NULL,
  933             (PVOID)NULL, &io_status,
  934             FSCTL_ALLOW_EXTENDED_DASD_IO,
  935             NULL, 0, NULL, 0);
  936     if (st != STATUS_SUCCESS) {
  937         errno = ntfs_ntstatus_to_errno(st);
  938         NtClose(handle);
  939         return (-1);
  940     }
  941     /* fill fd */
  942     fd->handle = handle;
  943     fd->part_start = 0;
  944     fd->part_length = fd->geo_size;
  945     fd->pos = 0;
  946     fd->part_hidden_sectors = -1;
  947     fd->vol_handle = INVALID_HANDLE_VALUE;
  948     return 0;
  949 }
  950 
  951 /**
  952  * ntfs_device_win32_open_volume_for_partition - find and open a volume
  953  *
  954  * Windows NT/2k/XP handles volumes instead of partitions.
  955  * This function gets the partition details and return an open volume handle.
  956  * That volume is the one whose only physical location on disk is the described
  957  * partition.
  958  *
  959  * The function required Windows 2k/XP, otherwise it fails (gracefully).
  960  *
  961  * Return success: a valid open volume handle.
  962  *        fail   : INVALID_HANDLE_VALUE
  963  */
  964 static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id,
  965         s64 part_offset, s64 part_length, int flags)
  966 {
  967     HANDLE vol_find_handle;
  968     TCHAR vol_name[MAX_PATH];
  969 
  970     /* Make sure all the required imports exist. */
  971     if (!fnFindFirstVolume || !fnFindNextVolume || !fnFindVolumeClose) {
  972         ntfs_log_trace("Required dll imports not found.\n");
  973         return INVALID_HANDLE_VALUE;
  974     }
  975     /* Start iterating through volumes. */
  976     ntfs_log_trace("Entering with drive_id=%d, part_offset=%lld, "
  977             "path_length=%lld, flags=%d.\n", drive_id,
  978             (unsigned long long)part_offset,
  979             (unsigned long long)part_length, flags);
  980     vol_find_handle = fnFindFirstVolume(vol_name, MAX_PATH);
  981     /* If a valid handle could not be aquired, reply with "don't know". */
  982     if (vol_find_handle == INVALID_HANDLE_VALUE) {
  983         ntfs_log_trace("FindFirstVolume failed.\n");
  984         return INVALID_HANDLE_VALUE;
  985     }
  986     do {
  987         int vol_name_length;
  988         HANDLE handle;
  989 
  990         /* remove trailing '/' from vol_name */
  991 #ifdef UNICODE
  992         vol_name_length = wcslen(vol_name);
  993 #else
  994         vol_name_length = strlen(vol_name);
  995 #endif
  996         if (vol_name_length>0)
  997             vol_name[vol_name_length-1]=0;
  998 
  999         ntfs_log_debug("Processing %s.\n", vol_name);
 1000         /* open the file */
 1001         handle = CreateFile(vol_name,
 1002                 ntfs_device_unix_status_flags_to_win32(flags),
 1003                 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
 1004                 OPEN_EXISTING, 0, NULL);
 1005         if (handle != INVALID_HANDLE_VALUE) {
 1006             DWORD bytesReturned;
 1007 #define EXTENTS_SIZE sizeof(VOLUME_DISK_EXTENTS) + 9 * sizeof(DISK_EXTENT)
 1008             char extents[EXTENTS_SIZE];
 1009 
 1010             /* Check physical locations. */
 1011             if (DeviceIoControl(handle,
 1012                     IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
 1013                     NULL, 0, extents, EXTENTS_SIZE,
 1014                     &bytesReturned, NULL)) {
 1015                 if (((VOLUME_DISK_EXTENTS *)extents)->
 1016                         NumberOfDiskExtents == 1) {
 1017                     DISK_EXTENT *extent = &((
 1018                             VOLUME_DISK_EXTENTS *)
 1019                             extents)->Extents[0];
 1020                     if ((extent->DiskNumber==drive_id) &&
 1021                             (extent->StartingOffset.
 1022                             QuadPart==part_offset)
 1023                             && (extent->
 1024                             ExtentLength.QuadPart
 1025                             == part_length)) {
 1026                         /*
 1027                          * Eureka! (Archimedes, 287 BC,
 1028                          * "I have found it!")
 1029                          */
 1030                         fnFindVolumeClose(
 1031                             vol_find_handle);
 1032                         return handle;
 1033                     }
 1034                 }
 1035             }
 1036         } else
 1037             ntfs_log_trace("getExtents() Failed.\n");
 1038     } while (fnFindNextVolume(vol_find_handle, vol_name, MAX_PATH));
 1039     /* End of iteration through volumes. */
 1040     ntfs_log_trace("Closing, volume was not found.\n");
 1041     fnFindVolumeClose(vol_find_handle);
 1042     return INVALID_HANDLE_VALUE;
 1043 }
 1044 
 1045 /**
 1046  * ntfs_device_win32_find_partition - locates partition details by id.
 1047  * @handle:     HANDLE to the PhysicalDrive
 1048  * @partition_id:   the partition number to locate
 1049  * @part_offset:    pointer to where to put the offset to the partition
 1050  * @part_length:    pointer to where to put the length of the partition
 1051  * @hidden_sectors: pointer to where to put the hidden sectors
 1052  *
 1053  * This function requires an open PhysicalDrive handle and a partition_id.
 1054  * If a partition with the required id is found on the supplied device,
 1055  * the partition attributes are returned back.
 1056  *
 1057  * Returns: TRUE  if found, and sets the output parameters.
 1058  *          FALSE if not and errno is set to the error code.
 1059  */
 1060 static BOOL ntfs_device_win32_find_partition(HANDLE handle, DWORD partition_id,
 1061         s64 *part_offset, s64 *part_length, int *hidden_sectors)
 1062 {
 1063     DRIVE_LAYOUT_INFORMATION *drive_layout;
 1064     unsigned int err, buf_size, part_count;
 1065     DWORD i;
 1066 
 1067     /*
 1068      * There is no way to know the required buffer, so if the ioctl fails,
 1069      * try doubling the buffer size each time until the ioctl succeeds.
 1070      */
 1071     part_count = 8;
 1072     do {
 1073         buf_size = sizeof(DRIVE_LAYOUT_INFORMATION) +
 1074                 part_count * sizeof(PARTITION_INFORMATION);
 1075         drive_layout = (DRIVE_LAYOUT_INFORMATION*)ntfs_malloc(buf_size);
 1076         if (!drive_layout) {
 1077             errno = ENOMEM;
 1078             return FALSE;
 1079         }
 1080         if (DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL,
 1081                 0, (BYTE*)drive_layout, buf_size, &i, NULL))
 1082             break;
 1083         err = GetLastError();
 1084         free(drive_layout);
 1085         if (err != ERROR_INSUFFICIENT_BUFFER) {
 1086             ntfs_log_trace("GetDriveLayout failed.\n");
 1087             errno = ntfs_w32error_to_errno(err);
 1088             return FALSE;
 1089         }
 1090         ntfs_log_debug("More than %u partitions.\n", part_count);
 1091         part_count <<= 1;
 1092         if (part_count > 512) {
 1093             ntfs_log_trace("GetDriveLayout failed: More than 512 "
 1094                     "partitions?\n");
 1095             errno = ENOBUFS;
 1096             return FALSE;
 1097         }
 1098     } while (1);
 1099     for (i = 0; i < drive_layout->PartitionCount; i++) {
 1100         if (drive_layout->PartitionEntry[i].PartitionNumber ==
 1101                 partition_id) {
 1102             *part_offset = drive_layout->PartitionEntry[i].
 1103                     StartingOffset.QuadPart;
 1104             *part_length = drive_layout->PartitionEntry[i].
 1105                     PartitionLength.QuadPart;
 1106             *hidden_sectors = drive_layout->PartitionEntry[i].
 1107                     HiddenSectors;
 1108             free(drive_layout);
 1109             return TRUE;
 1110         }
 1111     }
 1112     free(drive_layout);
 1113     errno = ENOENT;
 1114     return FALSE;
 1115 }
 1116 
 1117 /**
 1118  * ntfs_device_win32_open_partition - open a partition via win32 API
 1119  * @drive_id:       drive to open
 1120  * @partition_id:   partition to open
 1121  * @fd:         win32 file device to return
 1122  * @flags:      unix open status flags
 1123  *
 1124  * Return  0 if o.k.
 1125  *        -1 if not, and errno set.
 1126  *
 1127  * When fails, fd contents may have not been preserved.
 1128  */
 1129 static int ntfs_device_win32_open_partition(int drive_id,
 1130         unsigned int partition_id, win32_fd *fd, int flags)
 1131 {
 1132     s64 part_start, part_length;
 1133     HANDLE handle;
 1134     int err, hidden_sectors;
 1135     char drive_name[MAX_PATH];
 1136 
 1137     sprintf(drive_name, "\\\\.\\PhysicalDrive%d", drive_id);
 1138     /* Open the entire device without locking, ask questions later */
 1139     if ((err = ntfs_device_win32_simple_open_file(drive_name, &handle,
 1140             flags, FALSE))) {
 1141         /* error */
 1142         return err;
 1143     }
 1144     if (ntfs_device_win32_find_partition(handle, partition_id, &part_start,
 1145             &part_length, &hidden_sectors)) {
 1146         s64 tmp;
 1147         HANDLE vol_handle = ntfs_device_win32_open_volume_for_partition(
 1148             drive_id, part_start, part_length, flags);
 1149         /* Store the drive geometry. */
 1150         ntfs_device_win32_getgeo(handle, fd);
 1151         fd->handle = handle;
 1152         fd->pos = 0;
 1153         fd->part_start = part_start;
 1154         fd->part_length = part_length;
 1155         fd->part_hidden_sectors = hidden_sectors;
 1156         fd->geo_sector_size = 512;
 1157         fd->ntdll = FALSE;
 1158         tmp = ntfs_device_win32_getntfssize(vol_handle);
 1159         if (tmp > 0)
 1160             fd->geo_size = tmp;
 1161         else
 1162             fd->geo_size = fd->part_length;
 1163         if (vol_handle != INVALID_HANDLE_VALUE) {
 1164             if (((flags & O_RDWR) == O_RDWR) &&
 1165                     ntfs_device_win32_lock(vol_handle)) {
 1166                 CloseHandle(vol_handle);
 1167                 CloseHandle(handle);
 1168                 return -1;
 1169             }
 1170             fd->vol_handle = vol_handle;
 1171         } else {
 1172             if ((flags & O_RDWR) == O_RDWR) {
 1173                 /* Access if read-write, no volume found. */
 1174                 ntfs_log_trace("Partitions containing Spanned/"
 1175                         "Mirrored volumes are not "
 1176                         "supported in R/W status "
 1177                         "yet.\n");
 1178                 CloseHandle(handle);
 1179                 errno = EOPNOTSUPP;
 1180                 return -1;
 1181             }
 1182             fd->vol_handle = INVALID_HANDLE_VALUE;
 1183         }
 1184         return 0;
 1185     } else {
 1186         ntfs_log_debug("Partition %u not found on drive %d.\n",
 1187                 partition_id, drive_id);
 1188         CloseHandle(handle);
 1189         errno = ENODEV;
 1190         return -1;
 1191     }
 1192 }
 1193 
 1194 /**
 1195  * ntfs_device_win32_open - open a device
 1196  * @dev:    a pointer to the NTFS_DEVICE to open
 1197  * @flags:  unix open status flags
 1198  *
 1199  * @dev->d_name must hold the device name, the rest is ignored.
 1200  * Supported flags are O_RDONLY, O_WRONLY and O_RDWR.
 1201  *
 1202  * If name is in format "(hd[0-9],[0-9])" then open a partition.
 1203  * If name is in format "(hd[0-9])" then open a volume.
 1204  * Otherwise open a file.
 1205  */
 1206 static int ntfs_device_win32_open(struct ntfs_device *dev, int flags)
 1207 {
 1208     int drive_id = 0, numparams;
 1209     unsigned int part = 0;
 1210     char drive_char;
 1211     win32_fd fd;
 1212     int err;
 1213 
 1214     if (NDevOpen(dev)) {
 1215         errno = EBUSY;
 1216         return -1;
 1217     }
 1218     ntfs_device_win32_init_imports();
 1219     numparams = sscanf(dev->d_name, "/dev/hd%c%u", &drive_char, &part);
 1220     if (!numparams
 1221         && (dev->d_name[1] == ':')
 1222         && (dev->d_name[2] == '\0')) {
 1223         drive_char = dev->d_name[0];
 1224         numparams = 3;
 1225         drive_id = toupper(drive_char) - 'A';
 1226     }
 1227     switch (numparams) {
 1228     case 0:
 1229         ntfs_log_debug("win32_open(%s) -> file.\n", dev->d_name);
 1230         err = ntfs_device_win32_open_file(dev->d_name, &fd, flags);
 1231         break;
 1232     case 1:
 1233         ntfs_log_debug("win32_open(%s) -> drive %d.\n", dev->d_name,
 1234                 drive_id);
 1235         err = ntfs_device_win32_open_drive(drive_id, &fd, flags);
 1236         break;
 1237     case 2:
 1238         ntfs_log_debug("win32_open(%s) -> drive %d, part %u.\n",
 1239                 dev->d_name, drive_id, part);
 1240         err = ntfs_device_win32_open_partition(drive_id, part, &fd,
 1241                 flags);
 1242         break;
 1243     case 3:
 1244         ntfs_log_debug("win32_open(%s) -> drive %c:\n",
 1245                 dev->d_name, drive_char);
 1246         err = ntfs_device_win32_open_lowlevel(drive_id, &fd,
 1247                 flags);
 1248         break;
 1249     default:
 1250         ntfs_log_debug("win32_open(%s) -> unknwon file format.\n",
 1251                 dev->d_name);
 1252         err = -1;
 1253     }
 1254     if (err)
 1255         return err;
 1256     ntfs_log_debug("win32_open(%s) -> %p, offset 0x%llx.\n", dev->d_name,
 1257             dev, fd.part_start);
 1258     /* Setup our read-only flag. */
 1259     if ((flags & O_RDWR) != O_RDWR)
 1260         NDevSetReadOnly(dev);
 1261     dev->d_private = (win32_fd*)ntfs_malloc(sizeof(win32_fd));
 1262     memcpy(dev->d_private, &fd, sizeof(win32_fd));
 1263     NDevSetOpen(dev);
 1264     NDevClearDirty(dev);
 1265     return 0;
 1266 }
 1267 
 1268 /**
 1269  * ntfs_device_win32_seek - change current logical file position
 1270  * @dev:    ntfs device obtained via ->open
 1271  * @offset: required offset from the whence anchor
 1272  * @whence: whence anchor specifying what @offset is relative to
 1273  *
 1274  * Return the new position on the volume on success and -1 on error with errno
 1275  * set to the error code.
 1276  *
 1277  * @whence may be one of the following:
 1278  *  SEEK_SET - Offset is relative to file start.
 1279  *  SEEK_CUR - Offset is relative to current position.
 1280  *  SEEK_END - Offset is relative to end of file.
 1281  */
 1282 static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset,
 1283         int whence)
 1284 {
 1285     s64 abs_ofs;
 1286     win32_fd *fd = (win32_fd *)dev->d_private;
 1287 
 1288     ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence);
 1289     switch (whence) {
 1290     case SEEK_SET:
 1291         abs_ofs = offset;
 1292         break;
 1293     case SEEK_CUR:
 1294         abs_ofs = fd->pos + offset;
 1295         break;
 1296     case SEEK_END:
 1297         /* End of partition != end of disk. */
 1298         if (fd->part_length == -1) {
 1299             ntfs_log_trace("Position relative to end of disk not "
 1300                     "implemented.\n");
 1301             errno = EOPNOTSUPP;
 1302             return -1;
 1303         }
 1304         abs_ofs = fd->part_length + offset;
 1305         break;
 1306     default:
 1307         ntfs_log_trace("Wrong mode %d.\n", whence);
 1308         errno = EINVAL;
 1309         return -1;
 1310     }
 1311     if ((abs_ofs < 0)
 1312         || (fd->ntdll && (abs_ofs > fd->part_length))) {
 1313         ntfs_log_trace("Seeking outsize seekable area.\n");
 1314         errno = EINVAL;
 1315         return -1;
 1316     }
 1317     fd->pos = abs_ofs;
 1318     return abs_ofs;
 1319 }
 1320 
 1321 /**
 1322  * ntfs_device_win32_pio - positioned low level i/o
 1323  * @fd:     win32 device descriptor obtained via ->open
 1324  * @pos:    at which position to do i/o from/to
 1325  * @count:  how many bytes should be transfered
 1326  * @b:      source/destination buffer
 1327  * @write:  TRUE if write transfer and FALSE if read transfer
 1328  *
 1329  * On success returns the number of bytes transfered (can be < @count) and on
 1330  * error returns -1 and errno set.  Transfer starts from position @pos on @fd.
 1331  *
 1332  * Notes:
 1333  *  - @pos, @buf, and @count must be aligned to geo_sector_size
 1334  *  - When dealing with volumes, a single call must not span both volume
 1335  *    and disk extents.
 1336  *  - Does not use/set @fd->pos.
 1337  */
 1338 static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos,
 1339         const s64 count, void *rbuf, const void *wbuf)
 1340 {
 1341     LARGE_INTEGER li;
 1342     HANDLE handle;
 1343     DWORD bt;
 1344     BOOL res;
 1345     s64 bytes;
 1346 
 1347     ntfs_log_trace("pos = 0x%llx, count = 0x%llx, direction = %s.\n",
 1348             (long long)pos, (long long)count, write ? "write" :
 1349             "read");
 1350     li.QuadPart = pos;
 1351     if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) {
 1352         ntfs_log_debug("Transfering via vol_handle.\n");
 1353         handle = fd->vol_handle;
 1354     } else {
 1355         ntfs_log_debug("Transfering via handle.\n");
 1356         handle = fd->handle;
 1357         li.QuadPart += fd->part_start;
 1358     }
 1359 
 1360     if (fd->ntdll) {
 1361         IO_STATUS_BLOCK io_status;
 1362         NTSTATUS res;
 1363         LARGE_INTEGER offset;
 1364 
 1365         io_status.Status = STATUS_SUCCESS;
 1366         io_status.Information = 0;
 1367         offset.QuadPart = pos;
 1368         if (wbuf) {
 1369             res = NtWriteFile(fd->handle,(HANDLE)NULL,
 1370                     (PIO_APC_ROUTINE)NULL,(void*)NULL,
 1371                     &io_status, wbuf, count,
 1372                     &offset, (PULONG)NULL);
 1373         } else {
 1374             res = NtReadFile(fd->handle,(HANDLE)NULL,
 1375                     (PIO_APC_ROUTINE)NULL,(void*)NULL,
 1376                     &io_status, rbuf, count,
 1377                     &offset, (PULONG)NULL);
 1378         }
 1379         if (res == STATUS_SUCCESS) {
 1380             bytes = io_status.Information;
 1381         } else {
 1382             bytes = -1;
 1383             errno = ntfs_ntstatus_to_errno(res);
 1384         }
 1385     } else {
 1386         if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) {
 1387             errno = ntfs_w32error_to_errno(GetLastError());
 1388             ntfs_log_trace("SetFilePointer failed.\n");
 1389             return -1;
 1390         }
 1391         if (wbuf)
 1392             res = WriteFile(handle, wbuf, count, &bt, NULL);
 1393         else
 1394             res = ReadFile(handle, rbuf, count, &bt, NULL);
 1395         bytes = bt;
 1396         if (!res) {
 1397             errno = ntfs_w32error_to_errno(GetLastError());
 1398             ntfs_log_trace("%sFile() failed.\n", write ?
 1399                             "Write" : "Read");
 1400             return -1;
 1401         }
 1402         if (rbuf && !pos) {
 1403             /* get the sector size from the boot sector */
 1404             char *boot = (char*)rbuf;
 1405             fd->geo_sector_size = (boot[11] & 255)
 1406                         + ((boot[12] & 255) << 8);
 1407         }
 1408     }
 1409     return bytes;
 1410 }
 1411 
 1412 /**
 1413  * ntfs_device_win32_pread_simple - positioned simple read
 1414  * @fd:     win32 device descriptor obtained via ->open
 1415  * @pos:    at which position to read from
 1416  * @count:  how many bytes should be read
 1417  * @b:      a pointer to where to put the contents
 1418  *
 1419  * On success returns the number of bytes read (can be < @count) and on error
 1420  * returns -1 and errno set.  Read starts from position @pos.
 1421  *
 1422  * Notes:
 1423  *  - @pos, @buf, and @count must be aligned to geo_sector_size.
 1424  *  - When dealing with volumes, a single call must not span both volume
 1425  *    and disk extents.
 1426  *  - Does not use/set @fd->pos.
 1427  */
 1428 static inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos,
 1429         const s64 count, void *b)
 1430 {
 1431     return ntfs_device_win32_pio(fd, pos, count, b, (void*)NULL);
 1432 }
 1433 
 1434 /**
 1435  * ntfs_device_win32_read - read bytes from an ntfs device
 1436  * @dev:    ntfs device obtained via ->open
 1437  * @b:      pointer to where to put the contents
 1438  * @count:  how many bytes should be read
 1439  *
 1440  * On success returns the number of bytes actually read (can be < @count).
 1441  * On error returns -1 with errno set.
 1442  */
 1443 static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count)
 1444 {
 1445     s64 old_pos, to_read, i, br = 0;
 1446     win32_fd *fd = (win32_fd *)dev->d_private;
 1447     BYTE *alignedbuffer;
 1448     int old_ofs, ofs;
 1449 
 1450     old_pos = fd->pos;
 1451     old_ofs = ofs = old_pos & (fd->geo_sector_size - 1);
 1452     to_read = (ofs + count + fd->geo_sector_size - 1) &
 1453             ~(s64)(fd->geo_sector_size - 1);
 1454     /* Impose maximum of 2GB to be on the safe side. */
 1455     if (to_read > 0x80000000) {
 1456         int delta = to_read - count;
 1457         to_read = 0x80000000;
 1458         count = to_read - delta;
 1459     }
 1460     ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, "
 1461             "ofs = %i, to_read = 0x%llx.\n", fd, b,
 1462             (long long)count, (long long)old_pos, ofs,
 1463             (long long)to_read);
 1464     if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs &&
 1465             !(count & (fd->geo_sector_size - 1)))
 1466         alignedbuffer = b;
 1467     else {
 1468         alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT,
 1469                 PAGE_READWRITE);
 1470         if (!alignedbuffer) {
 1471             errno = ntfs_w32error_to_errno(GetLastError());
 1472             ntfs_log_trace("VirtualAlloc failed for read.\n");
 1473             return -1;
 1474         }
 1475     }
 1476     if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) {
 1477         s64 vol_to_read = fd->geo_size - old_pos;
 1478         if (count > vol_to_read) {
 1479             br = ntfs_device_win32_pread_simple(fd,
 1480                     old_pos & ~(s64)(fd->geo_sector_size - 1),
 1481                     ofs + vol_to_read, alignedbuffer);
 1482             if (br == -1)
 1483                 goto read_error;
 1484             to_read -= br;
 1485             if (br < ofs) {
 1486                 br = 0;
 1487                 goto read_partial;
 1488             }
 1489             br -= ofs;
 1490             fd->pos += br;
 1491             ofs = fd->pos & (fd->geo_sector_size - 1);
 1492             if (br != vol_to_read)
 1493                 goto read_partial;
 1494         }
 1495     }
 1496     i = ntfs_device_win32_pread_simple(fd,
 1497             fd->pos & ~(s64)(fd->geo_sector_size - 1), to_read,
 1498             alignedbuffer + br);
 1499     if (i == -1) {
 1500         if (br)
 1501             goto read_partial;
 1502         goto read_error;
 1503     }
 1504     if (i < ofs)
 1505         goto read_partial;
 1506     i -= ofs;
 1507     br += i;
 1508     if (br > count)
 1509         br = count;
 1510     fd->pos = old_pos + br;
 1511 read_partial:
 1512     if (alignedbuffer != b) {
 1513         memcpy((void*)b, alignedbuffer + old_ofs, br);
 1514         VirtualFree(alignedbuffer, 0, MEM_RELEASE);
 1515     }
 1516     return br;
 1517 read_error:
 1518     if (alignedbuffer != b)
 1519         VirtualFree(alignedbuffer, 0, MEM_RELEASE);
 1520     return -1;
 1521 }
 1522 
 1523 /**
 1524  * ntfs_device_win32_close - close an open ntfs deivce
 1525  * @dev:    ntfs device obtained via ->open
 1526  *
 1527  * Return 0 if o.k.
 1528  *   -1 if not, and errno set.  Note if error fd->vol_handle is trashed.
 1529  */
 1530 static int ntfs_device_win32_close(struct ntfs_device *dev)
 1531 {
 1532     win32_fd *fd = (win32_fd *)dev->d_private;
 1533     BOOL rvl;
 1534 
 1535     ntfs_log_trace("Closing device %p.\n", dev);
 1536     if (!NDevOpen(dev)) {
 1537         errno = EBADF;
 1538         return -1;
 1539     }
 1540     if (fd->vol_handle != INVALID_HANDLE_VALUE) {
 1541         if (!NDevReadOnly(dev)) {
 1542             ntfs_device_win32_dismount(fd->vol_handle);
 1543             ntfs_device_win32_unlock(fd->vol_handle);
 1544         }
 1545         if (!CloseHandle(fd->vol_handle))
 1546             ntfs_log_trace("CloseHandle() failed for volume.\n");
 1547     }
 1548     if (fd->ntdll) {
 1549         ntfs_device_win32_setlock(fd->handle,FSCTL_UNLOCK_VOLUME);
 1550         rvl = NtClose(fd->handle) == STATUS_SUCCESS;
 1551     } else
 1552         rvl = CloseHandle(fd->handle);
 1553     NDevClearOpen(dev);
 1554     free(fd);
 1555     if (!rvl) {
 1556         errno = ntfs_w32error_to_errno(GetLastError());
 1557         if (fd->ntdll)
 1558             ntfs_log_trace("NtClose() failed.\n");
 1559         else
 1560             ntfs_log_trace("CloseHandle() failed.\n");
 1561         return -1;
 1562     }
 1563     return 0;
 1564 }
 1565 
 1566 /**
 1567  * ntfs_device_win32_sync - flush write buffers to disk
 1568  * @dev:    ntfs device obtained via ->open
 1569  *
 1570  * Return 0 if o.k.
 1571  *   -1 if not, and errno set.
 1572  *
 1573  * Note: Volume syncing works differently in windows.
 1574  *   Disk cannot be synced in windows.
 1575  */
 1576 static int ntfs_device_win32_sync(struct ntfs_device *dev)
 1577 {
 1578     int err = 0;
 1579     BOOL to_clear = TRUE;
 1580 
 1581     if (!NDevReadOnly(dev) && NDevDirty(dev)) {
 1582         win32_fd *fd = (win32_fd *)dev->d_private;
 1583 
 1584         if ((fd->vol_handle != INVALID_HANDLE_VALUE) &&
 1585                 !FlushFileBuffers(fd->vol_handle)) {
 1586             to_clear = FALSE;
 1587             err = ntfs_w32error_to_errno(GetLastError());
 1588         }
 1589         if (!FlushFileBuffers(fd->handle)) {
 1590             to_clear = FALSE;
 1591             if (!err)
 1592                 err = ntfs_w32error_to_errno(GetLastError());
 1593         }
 1594         if (!to_clear) {
 1595             ntfs_log_trace("Could not sync.\n");
 1596             errno = err;
 1597             return -1;
 1598         }
 1599         NDevClearDirty(dev);
 1600     }
 1601     return 0;
 1602 }
 1603 
 1604 /**
 1605  * ntfs_device_win32_pwrite_simple - positioned simple write
 1606  * @fd:     win32 device descriptor obtained via ->open
 1607  * @pos:    at which position to write to
 1608  * @count:  how many bytes should be written
 1609  * @b:      a pointer to the data to write
 1610  *
 1611  * On success returns the number of bytes written and on error returns -1 and
 1612  * errno set.  Write starts from position @pos.
 1613  *
 1614  * Notes:
 1615  *  - @pos, @buf, and @count must be aligned to geo_sector_size.
 1616  *  - When dealing with volumes, a single call must not span both volume
 1617  *    and disk extents.
 1618  *  - Does not use/set @fd->pos.
 1619  */
 1620 static inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos,
 1621         const s64 count, const void *b)
 1622 {
 1623     return ntfs_device_win32_pio(fd, pos, count, (void*)NULL, b);
 1624 }
 1625 
 1626 /**
 1627  * ntfs_device_win32_write - write bytes to an ntfs device
 1628  * @dev:    ntfs device obtained via ->open
 1629  * @b:      pointer to the data to write
 1630  * @count:  how many bytes should be written
 1631  *
 1632  * On success returns the number of bytes actually written.
 1633  * On error returns -1 with errno set.
 1634  */
 1635 static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
 1636         s64 count)
 1637 {
 1638     s64 old_pos, to_write, i, bw = 0;
 1639     win32_fd *fd = (win32_fd *)dev->d_private;
 1640     const BYTE *alignedbuffer;
 1641     BYTE *readbuffer;
 1642     int old_ofs, ofs;
 1643 
 1644     old_pos = fd->pos;
 1645     old_ofs = ofs = old_pos & (fd->geo_sector_size - 1);
 1646     to_write = (ofs + count + fd->geo_sector_size - 1) &
 1647             ~(s64)(fd->geo_sector_size - 1);
 1648     /* Impose maximum of 2GB to be on the safe side. */
 1649     if (to_write > 0x80000000) {
 1650         int delta = to_write - count;
 1651         to_write = 0x80000000;
 1652         count = to_write - delta;
 1653     }
 1654     ntfs_log_trace("fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, "
 1655             "ofs = %i, to_write = 0x%llx.\n", fd, b,
 1656             (long long)count, (long long)old_pos, ofs,
 1657             (long long)to_write);
 1658     if (NDevReadOnly(dev)) {
 1659         ntfs_log_trace("Can't write on a R/O device.\n");
 1660         errno = EROFS;
 1661         return -1;
 1662     }
 1663     if (!count)
 1664         return 0;
 1665     NDevSetDirty(dev);
 1666     readbuffer = (BYTE*)NULL;
 1667     if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs &&
 1668             !(count & (fd->geo_sector_size - 1)))
 1669         alignedbuffer = (const BYTE *)b;
 1670     else {
 1671         s64 end;
 1672 
 1673         readbuffer = (BYTE *)VirtualAlloc(NULL, to_write,
 1674                 MEM_COMMIT, PAGE_READWRITE);
 1675         if (!readbuffer) {
 1676             errno = ntfs_w32error_to_errno(GetLastError());
 1677             ntfs_log_trace("VirtualAlloc failed for write.\n");
 1678             return -1;
 1679         }
 1680         /* Read first sector if start of write not sector aligned. */
 1681         if (ofs) {
 1682             i = ntfs_device_win32_pread_simple(fd,
 1683                     old_pos & ~(s64)(fd->geo_sector_size - 1),
 1684                     fd->geo_sector_size, readbuffer);
 1685             if (i != fd->geo_sector_size) {
 1686                 if (i >= 0)
 1687                     errno = EIO;
 1688                 goto write_error;
 1689             }
 1690         }
 1691         /*
 1692          * Read last sector if end of write not sector aligned and last
 1693          * sector is either not the same as the first sector or it is
 1694          * the same as the first sector but this has not been read in
 1695          * yet, i.e. the start of the write is sector aligned.
 1696          */
 1697         end = old_pos + count;
 1698         if ((end & (fd->geo_sector_size - 1)) &&
 1699                 ((to_write > fd->geo_sector_size) || !ofs)) {
 1700             i = ntfs_device_win32_pread_simple(fd,
 1701                     end & ~(s64)(fd->geo_sector_size - 1),
 1702                     fd->geo_sector_size, readbuffer +
 1703                     to_write - fd->geo_sector_size);
 1704             if (i != fd->geo_sector_size) {
 1705                 if (i >= 0)
 1706                     errno = EIO;
 1707                 goto write_error;
 1708             }
 1709         }
 1710         /* Copy the data to be written into @readbuffer. */
 1711         memcpy(readbuffer + ofs, b, count);
 1712         alignedbuffer = readbuffer;
 1713     }
 1714     if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) {
 1715         s64 vol_to_write = fd->geo_size - old_pos;
 1716         if (count > vol_to_write) {
 1717             bw = ntfs_device_win32_pwrite_simple(fd,
 1718                     old_pos & ~(s64)(fd->geo_sector_size - 1),
 1719                     ofs + vol_to_write, alignedbuffer);
 1720             if (bw == -1)
 1721                 goto write_error;
 1722             to_write -= bw;
 1723             if (bw < ofs) {
 1724                 bw = 0;
 1725                 goto write_partial;
 1726             }
 1727             bw -= ofs;
 1728             fd->pos += bw;
 1729             ofs = fd->pos & (fd->geo_sector_size - 1);
 1730             if (bw != vol_to_write)
 1731                 goto write_partial;
 1732         }
 1733     }
 1734     i = ntfs_device_win32_pwrite_simple(fd,
 1735             fd->pos & ~(s64)(fd->geo_sector_size - 1), to_write,
 1736             alignedbuffer + bw);
 1737     if (i == -1) {
 1738         if (bw)
 1739             goto write_partial;
 1740         goto write_error;
 1741     }
 1742     if (i < ofs)
 1743         goto write_partial;
 1744     i -= ofs;
 1745     bw += i;
 1746     if (bw > count)
 1747         bw = count;
 1748     fd->pos = old_pos + bw;
 1749 write_partial:
 1750     if (readbuffer)
 1751         VirtualFree(readbuffer, 0, MEM_RELEASE);
 1752     return bw;
 1753 write_error:
 1754     bw = -1;
 1755     goto write_partial;
 1756 }
 1757 
 1758 /**
 1759  * ntfs_device_win32_stat - get a unix-like stat structure for an ntfs device
 1760  * @dev:    ntfs device obtained via ->open
 1761  * @buf:    pointer to the stat structure to fill
 1762  *
 1763  * Note: Only st_mode, st_size, and st_blocks are filled.
 1764  *
 1765  * Return 0 if o.k.
 1766  *   -1 if not and errno set. in this case handle is trashed.
 1767  */
 1768 static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf)
 1769 {
 1770     win32_fd *fd = (win32_fd *)dev->d_private;
 1771     mode_t st_mode;
 1772 
 1773     if ((dev->d_name[1] == ':') && (dev->d_name[2] == '\0'))
 1774         st_mode = S_IFBLK;
 1775     else
 1776         switch (GetFileType(fd->handle)) {
 1777         case FILE_TYPE_CHAR:
 1778             st_mode = S_IFCHR;
 1779             break;
 1780         case FILE_TYPE_DISK:
 1781             st_mode = S_IFREG;
 1782             break;
 1783         case FILE_TYPE_PIPE:
 1784             st_mode = S_IFIFO;
 1785             break;
 1786         default:
 1787             st_mode = 0;
 1788         }
 1789     memset(buf, 0, sizeof(struct stat));
 1790     buf->st_mode = st_mode;
 1791     buf->st_size = fd->part_length;
 1792     if (buf->st_size != -1)
 1793         buf->st_blocks = buf->st_size >> 9;
 1794     else
 1795         buf->st_size = 0;
 1796     return 0;
 1797 }
 1798 
 1799 #ifdef HDIO_GETGEO
 1800 /**
 1801  * ntfs_win32_hdio_getgeo - get drive geometry
 1802  * @dev:    ntfs device obtained via ->open
 1803  * @argp:   pointer to where to put the output
 1804  *
 1805  * Note: Works on windows NT/2k/XP only.
 1806  *
 1807  * Return 0 if o.k.
 1808  *   -1 if not, and errno set.  Note if error fd->handle is trashed.
 1809  */
 1810 static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev,
 1811         struct hd_geometry *argp)
 1812 {
 1813     win32_fd *fd = (win32_fd *)dev->d_private;
 1814 
 1815     argp->heads = fd->geo_heads;
 1816     argp->sectors = fd->geo_sectors;
 1817     argp->cylinders = fd->geo_cylinders;
 1818     argp->start = fd->part_hidden_sectors;
 1819     return 0;
 1820 }
 1821 #endif
 1822 
 1823 /**
 1824  * ntfs_win32_blksszget - get block device sector size
 1825  * @dev:    ntfs device obtained via ->open
 1826  * @argp:   pointer to where to put the output
 1827  *
 1828  * Note: Works on windows NT/2k/XP only.
 1829  *
 1830  * Return 0 if o.k.
 1831  *   -1 if not, and errno set.  Note if error fd->handle is trashed.
 1832  */
 1833 static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp)
 1834 {
 1835     win32_fd *fd = (win32_fd *)dev->d_private;
 1836     DWORD bytesReturned;
 1837     DISK_GEOMETRY dg;
 1838 
 1839     if (DeviceIoControl(fd->handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
 1840             &dg, sizeof(DISK_GEOMETRY), &bytesReturned, NULL)) {
 1841         /* success */
 1842         *argp = dg.BytesPerSector;
 1843         return 0;
 1844     }
 1845     errno = ntfs_w32error_to_errno(GetLastError());
 1846     ntfs_log_trace("GET_DRIVE_GEOMETRY failed.\n");
 1847     return -1;
 1848 }
 1849 
 1850 static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
 1851         void *argp)
 1852 {
 1853 #if defined(BLKGETSIZE) | defined(BLKGETSIZE64)
 1854     win32_fd *fd = (win32_fd *)dev->d_private;
 1855 #endif
 1856 
 1857     ntfs_log_trace("win32_ioctl(%d) called.\n", request);
 1858     switch (request) {
 1859 #if defined(BLKGETSIZE)
 1860     case BLKGETSIZE:
 1861         ntfs_log_debug("BLKGETSIZE detected.\n");
 1862         if (fd->part_length >= 0) {
 1863             *(int *)argp = (int)(fd->part_length / 512);
 1864             return 0;
 1865         }
 1866         errno = EOPNOTSUPP;
 1867         return -1;
 1868 #endif
 1869 #if defined(BLKGETSIZE64)
 1870     case BLKGETSIZE64:
 1871         ntfs_log_debug("BLKGETSIZE64 detected.\n");
 1872         if (fd->part_length >= 0) {
 1873             *(s64 *)argp = fd->part_length;
 1874             return 0;
 1875         }
 1876         errno = EOPNOTSUPP;
 1877         return -1;
 1878 #endif
 1879 #ifdef HDIO_GETGEO
 1880     case HDIO_GETGEO:
 1881         ntfs_log_debug("HDIO_GETGEO detected.\n");
 1882         return ntfs_win32_hdio_getgeo(dev, (struct hd_geometry *)argp);
 1883 #endif
 1884 #ifdef BLKSSZGET
 1885     case BLKSSZGET:
 1886         ntfs_log_debug("BLKSSZGET detected.\n");
 1887         if (fd && !fd->ntdll) {
 1888             *(int*)argp = fd->geo_sector_size;
 1889             return (0);
 1890         } else
 1891             return ntfs_win32_blksszget(dev, (int *)argp);
 1892 #endif
 1893 #ifdef BLKBSZSET
 1894     case BLKBSZSET:
 1895         ntfs_log_debug("BLKBSZSET detected.\n");
 1896         /* Nothing to do on Windows. */
 1897         return 0;
 1898 #endif
 1899     default:
 1900         ntfs_log_debug("unimplemented ioctl %d.\n", request);
 1901         errno = EOPNOTSUPP;
 1902         return -1;
 1903     }
 1904 }
 1905 
 1906 static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b,
 1907         s64 count, s64 offset)
 1908 {
 1909     s64 got;
 1910     win32_fd *fd;
 1911 
 1912         /* read the fast way if sector aligned */
 1913     fd = (win32_fd*)dev->d_private;
 1914     if (!((count | offset) & (fd->geo_sector_size - 1))) {
 1915         got = ntfs_device_win32_pio(fd, offset, count, b, (void*)NULL);
 1916     } else {
 1917         if (ntfs_device_win32_seek(dev, offset, 0) == -1)
 1918             got = 0;
 1919         else
 1920             got = ntfs_device_win32_read(dev, b, count);
 1921     }
 1922 
 1923     return (got);
 1924 }
 1925 
 1926 static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b,
 1927         s64 count, s64 offset)
 1928 {
 1929     s64 put;
 1930     win32_fd *fd;
 1931 
 1932         /* write the fast way if sector aligned */
 1933     fd = (win32_fd*)dev->d_private;
 1934     if (!((count | offset) & (fd->geo_sector_size - 1))) {
 1935         put = ntfs_device_win32_pio(fd, offset, count, (void*)NULL, b);
 1936     } else {
 1937         if (ntfs_device_win32_seek(dev, offset, 0) == -1)
 1938             put = 0;
 1939         else
 1940             put = ntfs_device_win32_write(dev, b, count);
 1941     }
 1942     return (put);
 1943 }
 1944 
 1945 struct ntfs_device_operations ntfs_device_win32_io_ops = {
 1946     .open       = ntfs_device_win32_open,
 1947     .close      = ntfs_device_win32_close,
 1948     .seek       = ntfs_device_win32_seek,
 1949     .read       = ntfs_device_win32_read,
 1950     .write      = ntfs_device_win32_write,
 1951     .pread      = ntfs_device_win32_pread,
 1952     .pwrite     = ntfs_device_win32_pwrite,
 1953     .sync       = ntfs_device_win32_sync,
 1954     .stat       = ntfs_device_win32_stat,
 1955     .ioctl      = ntfs_device_win32_ioctl
 1956 };
 1957 
 1958 /*
 1959  *          Mark an open file as sparse
 1960  *
 1961  *  This is only called by ntfsclone when cloning a volume to a file.
 1962  *  The argument is the target file, not a volume.
 1963  *
 1964  *  Returns 0 if successful.
 1965  */
 1966 
 1967 int ntfs_win32_set_sparse(int fd)
 1968 {
 1969     BOOL ok;
 1970     HANDLE handle;
 1971     DWORD bytes;   
 1972 
 1973     handle = get_osfhandle(fd);
 1974     if (handle == INVALID_HANDLE_VALUE)
 1975         ok = FALSE;
 1976     else
 1977         ok = DeviceIoControl(handle, FSCTL_SET_SPARSE,
 1978                 (void*)NULL, 0, (void*)NULL, 0,
 1979                 &bytes, (LPOVERLAPPED)NULL);
 1980     return (!ok);
 1981 }
 1982 
 1983 /*
 1984  *          Resize an open file
 1985  *
 1986  *  This is only called by ntfsclone when cloning a volume to a file.
 1987  *  The argument must designate a file, not a volume.
 1988  *
 1989  *  Returns 0 if successful.
 1990  */
 1991 
 1992 static int win32_ftruncate(HANDLE handle, s64 size)
 1993 {
 1994     BOOL ok;
 1995     LONG hsize, lsize;
 1996     LONG ohsize, olsize;
 1997 
 1998     if (handle == INVALID_HANDLE_VALUE)
 1999         ok = FALSE;
 2000     else {
 2001         SetLastError(NO_ERROR);
 2002             /* save original position */
 2003         ohsize = 0;
 2004         olsize = SetFilePointer(handle, 0, &ohsize, 1);
 2005         hsize = size >> 32;
 2006         lsize = size & 0xffffffff;
 2007         ok = (SetFilePointer(handle, lsize, &hsize, 0) == (DWORD)lsize)
 2008             && (GetLastError() == NO_ERROR)
 2009             && SetEndOfFile(handle);
 2010             /* restore original position, even if above failed */
 2011         SetFilePointer(handle, olsize, &ohsize, 0);
 2012         if (GetLastError() != NO_ERROR)
 2013             ok = FALSE;
 2014     }
 2015     if (!ok)
 2016         errno = EINVAL;
 2017     return (ok ? 0 : -1);
 2018 }
 2019 
 2020 int ntfs_device_win32_ftruncate(struct ntfs_device *dev, s64 size)
 2021 {
 2022     win32_fd *fd;
 2023     int ret;
 2024 
 2025     ret = -1;
 2026     fd = (win32_fd*)dev->d_private;
 2027     if (fd && !fd->ntdll)
 2028         ret = win32_ftruncate(fd->handle, size);
 2029     return (ret);
 2030 }
 2031 
 2032 int ntfs_win32_ftruncate(int fd, s64 size)
 2033 {
 2034     int ret;
 2035     HANDLE handle;
 2036 
 2037     handle = get_osfhandle(fd);
 2038     ret = win32_ftruncate(handle, size);
 2039     return (ret);
 2040 }