Upgraded the Win32 interface for use with ntfsprogs
Upgrade the Win32 interface (win32_io.c) which was designed for Cygwin so that it can be used for using the ntfsprogs utilities on native Windows. Two new entries are added for truncating a file and creating a sparse file, both of which not being supported through msvcrt.dll.edge.strict_endians
parent
7cb4b99627
commit
44fbf02a97
|
@ -28,12 +28,18 @@
|
|||
|
||||
#ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
|
||||
|
||||
#ifndef __CYGWIN32__
|
||||
#if defined(linux) || defined(__uClinux__) || defined(__sun) \
|
||||
|| defined(__APPLE__) || defined(__DARWIN__)
|
||||
/* Make sure the presence of <windows.h> means compiling for Windows */
|
||||
#undef HAVE_WINDOWS_H
|
||||
#endif
|
||||
|
||||
/* Not on Cygwin; use standard Unix style low level device operations. */
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
|
||||
/* Not for Windows use standard Unix style low level device operations. */
|
||||
#define ntfs_device_default_io_ops ntfs_device_unix_io_ops
|
||||
|
||||
#else /* __CYGWIN32__ */
|
||||
#else /* HAVE_WINDOWS_H */
|
||||
|
||||
#ifndef HDIO_GETGEO
|
||||
# define HDIO_GETGEO 0x301
|
||||
|
@ -60,10 +66,15 @@ struct hd_geometry {
|
|||
# define BLKBSZSET 0x40041271
|
||||
#endif
|
||||
|
||||
/* On Cygwin; use Win32 low level device operations. */
|
||||
/* On Windows (and Cygwin) : use Win32 low level device operations. */
|
||||
#define ntfs_device_default_io_ops ntfs_device_win32_io_ops
|
||||
|
||||
#endif /* __CYGWIN32__ */
|
||||
/* A few useful functions */
|
||||
int ntfs_win32_set_sparse(int);
|
||||
int ntfs_win32_ftruncate(int fd, s64 size);
|
||||
int ntfs_win32_device_ftruncate(struct ntfs_device*, s64);
|
||||
|
||||
#endif /* HAVE_WINDOWS_H */
|
||||
|
||||
|
||||
/* Forward declaration. */
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Copyright (c) 2003-2004 Lode Leroy
|
||||
* Copyright (c) 2003-2006 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Yuval Fledel
|
||||
* Copyright (c) 2012 Jean-Pierre Andre
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
|
@ -26,8 +27,33 @@
|
|||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#define BOOL WINBOOL /* avoid conflicting definitions of BOOL */
|
||||
#include <windows.h>
|
||||
#undef BOOL
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Definitions needed for <winioctl.h>
|
||||
*/
|
||||
#ifndef _ANONYMOUS_UNION
|
||||
#define _ANONYMOUS_UNION
|
||||
#define _ANONYMOUS_STRUCT
|
||||
typedef unsigned long long DWORD64;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
DWORD data1; /* The first eight hexadecimal digits of the GUID. */
|
||||
WORD data2; /* The first group of four hexadecimal digits. */
|
||||
WORD data3; /* The second group of four hexadecimal digits. */
|
||||
char data4[8]; /* The first two bytes are the third group of four
|
||||
hexadecimal digits. The remaining six bytes are the
|
||||
final 12 hexadecimal digits. */
|
||||
} GUID;
|
||||
|
||||
#include <winioctl.h>
|
||||
|
||||
#ifdef HAVE_STDIO_H
|
||||
|
@ -42,6 +68,10 @@
|
|||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#define st_blocks st_rdev /* emulate st_blocks, missing in Windows */
|
||||
#endif
|
||||
|
||||
/* Prevent volume.h from being be loaded, as it conflicts with winnt.h. */
|
||||
#define _NTFS_VOLUME_H
|
||||
|
@ -51,6 +81,10 @@ typedef struct ntfs_volume ntfs_volume;
|
|||
#include "debug.h"
|
||||
#include "types.h"
|
||||
#include "device.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define cpu_to_le16(x) (x)
|
||||
#define const_cpu_to_le16(x) (x)
|
||||
|
||||
#ifndef MAX_PATH
|
||||
#define MAX_PATH 1024
|
||||
|
@ -61,10 +95,26 @@ typedef struct ntfs_volume ntfs_volume;
|
|||
#define NTFS_BLOCK_SIZE_BITS 9
|
||||
#endif
|
||||
|
||||
#ifndef INVALID_SET_FILE_POINTER
|
||||
#define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
||||
#endif
|
||||
|
||||
#ifndef IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
|
||||
#define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096
|
||||
#endif
|
||||
|
||||
#ifndef IOCTL_DISK_GET_DRIVE_GEOMETRY
|
||||
#define IOCTL_DISK_GET_DRIVE_GEOMETRY 0x70000
|
||||
#endif
|
||||
|
||||
#ifndef IOCTL_GET_DISK_LENGTH_INFO
|
||||
#define IOCTL_GET_DISK_LENGTH_INFO 0x7405c
|
||||
#endif
|
||||
|
||||
#ifndef FSCTL_ALLOW_EXTENDED_DASD_IO
|
||||
#define FSCTL_ALLOW_EXTENDED_DASD_IO 0x90083
|
||||
#endif
|
||||
|
||||
/* Windows 2k+ imports. */
|
||||
typedef HANDLE (WINAPI *LPFN_FINDFIRSTVOLUME)(LPTSTR, DWORD);
|
||||
typedef BOOL (WINAPI *LPFN_FINDNEXTVOLUME)(HANDLE, LPTSTR, DWORD);
|
||||
|
@ -83,6 +133,131 @@ static LPFN_SETFILEPOINTEREX fnSetFilePointerEx = NULL;
|
|||
#define FNPOSTFIX "A"
|
||||
#endif
|
||||
|
||||
enum { /* see http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx */
|
||||
STATUS_UNKNOWN = -1,
|
||||
STATUS_SUCCESS = 0x00000000,
|
||||
STATUS_BUFFER_OVERFLOW = 0x80000005,
|
||||
STATUS_INVALID_HANDLE = 0xC0000008,
|
||||
STATUS_INVALID_PARAMETER = 0xC000000D,
|
||||
STATUS_INVALID_DEVICE_REQUEST = 0xC0000010,
|
||||
STATUS_END_OF_FILE = 0xC0000011,
|
||||
STATUS_CONFLICTING_ADDRESSES = 0xC0000018,
|
||||
STATUS_NO_MATCH = 0xC000001E,
|
||||
STATUS_ACCESS_DENIED = 0xC0000022,
|
||||
STATUS_BUFFER_TOO_SMALL = 0xC0000023,
|
||||
STATUS_OBJECT_TYPE_MISMATCH = 0xC0000024,
|
||||
STATUS_FILE_NOT_FOUND = 0xC0000028,
|
||||
STATUS_OBJECT_NAME_INVALID = 0xC0000033,
|
||||
STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
|
||||
STATUS_INVALID_PARAMETER_1 = 0xC00000EF,
|
||||
STATUS_IO_DEVICE_ERROR = 0xC0000185,
|
||||
STATUS_GUARD_PAGE_VIOLATION = 0x80000001
|
||||
} ;
|
||||
|
||||
typedef u32 NTSTATUS; /* do not let the compiler choose the size */
|
||||
typedef unsigned long ULONG_PTR;
|
||||
|
||||
HANDLE get_osfhandle(int); /* from msvcrt.dll */
|
||||
|
||||
/*
|
||||
* A few needed definitions not included in <windows.h>
|
||||
*/
|
||||
|
||||
typedef struct _IO_STATUS_BLOCK {
|
||||
union {
|
||||
NTSTATUS Status;
|
||||
PVOID Pointer;
|
||||
};
|
||||
ULONG_PTR Information;
|
||||
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING, *PUNICODE_STRING;
|
||||
|
||||
typedef struct _OBJECT_ATTRIBUTES {
|
||||
ULONG Length;
|
||||
HANDLE RootDirectory;
|
||||
PUNICODE_STRING ObjectName;
|
||||
ULONG Attributes;
|
||||
PVOID SecurityDescriptor;
|
||||
PVOID SecurityQualityOfService;
|
||||
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
|
||||
|
||||
#define FILE_OPEN 1
|
||||
#define FILE_CREATE 2
|
||||
#define FILE_OVERWRITE 4
|
||||
#define FILE_SYNCHRONOUS_IO_ALERT 0x10
|
||||
#define FILE_SYNCHRONOUS_IO_NONALERT 0x20
|
||||
#define OBJ_CASE_INSENSITIVE 0x40
|
||||
|
||||
typedef void (WINAPI *PIO_APC_ROUTINE)(void*, PIO_STATUS_BLOCK, ULONG);
|
||||
|
||||
extern WINAPI NTSTATUS NtOpenFile(
|
||||
PHANDLE FileHandle,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG ShareAccess,
|
||||
ULONG OpenOptions
|
||||
);
|
||||
|
||||
extern WINAPI NTSTATUS NtReadFile(
|
||||
HANDLE FileHandle,
|
||||
HANDLE Event,
|
||||
PIO_APC_ROUTINE ApcRoutine,
|
||||
PVOID ApcContext,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
PLARGE_INTEGER ByteOffset,
|
||||
PULONG Key
|
||||
);
|
||||
|
||||
extern WINAPI NTSTATUS NtWriteFile(
|
||||
HANDLE FileHandle,
|
||||
HANDLE Event,
|
||||
PIO_APC_ROUTINE ApcRoutine,
|
||||
PVOID ApcContext,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
LPCVOID Buffer,
|
||||
ULONG Length,
|
||||
PLARGE_INTEGER ByteOffset,
|
||||
PULONG Key
|
||||
);
|
||||
|
||||
extern NTSTATUS WINAPI NtClose(
|
||||
HANDLE Handle
|
||||
);
|
||||
|
||||
extern NTSTATUS WINAPI NtDeviceIoControlFile(
|
||||
HANDLE FileHandle,
|
||||
HANDLE Event,
|
||||
PIO_APC_ROUTINE ApcRoutine,
|
||||
PVOID ApcContext,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG IoControlCode,
|
||||
PVOID InputBuffer,
|
||||
ULONG InputBufferLength,
|
||||
PVOID OutputBuffer,
|
||||
ULONG OutputBufferLength
|
||||
);
|
||||
|
||||
extern NTSTATUS WINAPI NtFsControlFile(
|
||||
HANDLE FileHandle,
|
||||
HANDLE Event,
|
||||
PIO_APC_ROUTINE ApcRoutine,
|
||||
PVOID ApcContext,
|
||||
PIO_STATUS_BLOCK IoStatusBlock,
|
||||
ULONG FsControlCode,
|
||||
PVOID InputBuffer,
|
||||
ULONG InputBufferLength,
|
||||
PVOID OutputBuffer,
|
||||
ULONG OutputBufferLength
|
||||
);
|
||||
|
||||
/**
|
||||
* struct win32_fd -
|
||||
*/
|
||||
|
@ -93,8 +268,11 @@ typedef struct {
|
|||
s64 part_length;
|
||||
int part_hidden_sectors;
|
||||
s64 geo_size, geo_cylinders;
|
||||
s32 geo_sector_size;
|
||||
s64 volume_size;
|
||||
DWORD geo_sectors, geo_heads;
|
||||
HANDLE vol_handle;
|
||||
BOOL ntdll;
|
||||
} win32_fd;
|
||||
|
||||
/**
|
||||
|
@ -146,6 +324,26 @@ static int ntfs_w32error_to_errno(unsigned int w32error)
|
|||
}
|
||||
}
|
||||
|
||||
static int ntfs_ntstatus_to_errno(NTSTATUS status)
|
||||
{
|
||||
ntfs_log_trace("Converting w32error 0x%x.\n",w32error);
|
||||
switch (status) {
|
||||
case STATUS_INVALID_HANDLE :
|
||||
case STATUS_INVALID_PARAMETER :
|
||||
case STATUS_OBJECT_NAME_INVALID :
|
||||
case STATUS_INVALID_DEVICE_REQUEST :
|
||||
return (EINVAL);
|
||||
case STATUS_ACCESS_DENIED :
|
||||
return (EACCES);
|
||||
case STATUS_IO_DEVICE_ERROR :
|
||||
case STATUS_END_OF_FILE :
|
||||
return (EIO);
|
||||
default:
|
||||
/* generic message */
|
||||
return ENOMSG;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* libntfs_SetFilePointerEx - emulation for SetFilePointerEx()
|
||||
*
|
||||
|
@ -156,10 +354,11 @@ static BOOL WINAPI libntfs_SetFilePointerEx(HANDLE hFile,
|
|||
LARGE_INTEGER liDistanceToMove,
|
||||
PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
|
||||
{
|
||||
liDistanceToMove.LowPart = SetFilePointer(hFile,
|
||||
liDistanceToMove.LowPart, &liDistanceToMove.HighPart,
|
||||
dwMoveMethod);
|
||||
if (liDistanceToMove.LowPart == INVALID_SET_FILE_POINTER &&
|
||||
liDistanceToMove.u.LowPart = SetFilePointer(hFile,
|
||||
liDistanceToMove.u.LowPart,
|
||||
&liDistanceToMove.u.HighPart, dwMoveMethod);
|
||||
SetLastError(NO_ERROR);
|
||||
if (liDistanceToMove.u.LowPart == INVALID_SET_FILE_POINTER &&
|
||||
GetLastError() != NO_ERROR) {
|
||||
if (lpNewFilePointer)
|
||||
lpNewFilePointer->QuadPart = -1;
|
||||
|
@ -199,7 +398,7 @@ static void ntfs_device_win32_init_imports(void)
|
|||
* SetFilePointerEx().
|
||||
*/
|
||||
if (!fnSetFilePointerEx) {
|
||||
ntfs_log_debug("SetFilePonterEx() not found in "
|
||||
ntfs_log_debug("SetFilePointerEx() not found in "
|
||||
"kernel32.dll: Enabling emulation.\n");
|
||||
fnSetFilePointerEx = libntfs_SetFilePointerEx;
|
||||
}
|
||||
|
@ -232,13 +431,13 @@ static __inline__ int ntfs_device_unix_status_flags_to_win32(int flags)
|
|||
|
||||
switch (flags & O_ACCMODE) {
|
||||
case O_RDONLY:
|
||||
win_mode = FILE_READ_DATA;
|
||||
win_mode = GENERIC_READ;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
win_mode = FILE_WRITE_DATA;
|
||||
win_mode = GENERIC_WRITE;
|
||||
break;
|
||||
case O_RDWR:
|
||||
win_mode = FILE_READ_DATA | FILE_WRITE_DATA;
|
||||
win_mode = GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
default:
|
||||
/* error */
|
||||
|
@ -321,6 +520,22 @@ static int ntfs_device_win32_unlock(HANDLE handle)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ntfs_device_win32_setlock(HANDLE handle, ULONG code)
|
||||
{
|
||||
IO_STATUS_BLOCK io_status;
|
||||
NTSTATUS res;
|
||||
|
||||
io_status.Status = STATUS_SUCCESS;
|
||||
io_status.Information = 0;
|
||||
res = NtFsControlFile(handle,(HANDLE)NULL,
|
||||
(PIO_APC_ROUTINE)NULL,(void*)NULL,
|
||||
&io_status, code,
|
||||
(char*)NULL,0,(char*)NULL,0);
|
||||
if (res != STATUS_SUCCESS)
|
||||
errno = ntfs_ntstatus_to_errno(res);
|
||||
return (res == STATUS_SUCCESS ? 0 : -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_win32_dismount - dismount a volume
|
||||
* @handle: a win32 HANDLE for a volume to dismount
|
||||
|
@ -359,9 +574,10 @@ static int ntfs_device_win32_dismount(HANDLE handle)
|
|||
*/
|
||||
static s64 ntfs_device_win32_getsize(HANDLE handle)
|
||||
{
|
||||
DWORD loword, hiword;
|
||||
LONG loword, hiword;
|
||||
|
||||
loword = GetFileSize(handle, &hiword);
|
||||
hiword = 0;
|
||||
loword = SetFilePointer(handle, 0, &hiword, 2);
|
||||
if (loword == INVALID_FILE_SIZE) {
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
ntfs_log_trace("Couldn't get file size.\n");
|
||||
|
@ -467,6 +683,7 @@ static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd)
|
|||
fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart;
|
||||
fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack;
|
||||
fd->geo_size = ((DISK_GEOMETRY_EX*)&b)->DiskSize.QuadPart;
|
||||
fd->geo_sector_size = NTFS_BLOCK_SIZE;
|
||||
switch (ddi->DetectionType) {
|
||||
case DetectInt13:
|
||||
fd->geo_cylinders = ddi->Int13.MaxCylinders;
|
||||
|
@ -493,6 +710,7 @@ static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd)
|
|||
fd->geo_size = fd->geo_cylinders * fd->geo_sectors *
|
||||
((DISK_GEOMETRY*)&b)->TracksPerCylinder *
|
||||
((DISK_GEOMETRY*)&b)->BytesPerSector;
|
||||
fd->geo_sector_size = ((DISK_GEOMETRY*)&b)->BytesPerSector;
|
||||
return 0;
|
||||
}
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
|
@ -500,9 +718,51 @@ static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd)
|
|||
fd->geo_cylinders = -1;
|
||||
fd->geo_sectors = -1;
|
||||
fd->geo_size = -1;
|
||||
fd->geo_sector_size = NTFS_BLOCK_SIZE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ntfs_device_win32_getntgeo(HANDLE handle, win32_fd *fd)
|
||||
{
|
||||
DISK_GEOMETRY geo;
|
||||
NTSTATUS st;
|
||||
IO_STATUS_BLOCK status;
|
||||
u64 bytes;
|
||||
int res;
|
||||
|
||||
res = -1;
|
||||
fd->geo_cylinders = 0;
|
||||
fd->geo_sectors = 0;
|
||||
fd->geo_size = 1073741824;
|
||||
fd->geo_sectors = fd->geo_size >> 9;
|
||||
fd->geo_sector_size = NTFS_BLOCK_SIZE;
|
||||
|
||||
st = NtDeviceIoControlFile(handle, (HANDLE)NULL,
|
||||
(PIO_APC_ROUTINE)NULL, (void*)NULL,
|
||||
&status, IOCTL_DISK_GET_DRIVE_GEOMETRY, (void*)NULL, 0,
|
||||
(void*)&geo, sizeof(geo));
|
||||
if (st == STATUS_SUCCESS) {
|
||||
/* over-estimate the (rounded) number of cylinders */
|
||||
fd->geo_cylinders = geo.Cylinders.QuadPart + 1;
|
||||
fd->geo_sectors = fd->geo_cylinders
|
||||
*geo.TracksPerCylinder*geo.SectorsPerTrack;
|
||||
fd->geo_size = fd->geo_sectors*geo.BytesPerSector;
|
||||
fd->geo_sector_size = geo.BytesPerSector;
|
||||
res = 0;
|
||||
/* try to get the exact sector count */
|
||||
st = NtDeviceIoControlFile(handle, (HANDLE)NULL,
|
||||
(PIO_APC_ROUTINE)NULL, (void*)NULL,
|
||||
&status, IOCTL_GET_DISK_LENGTH_INFO,
|
||||
(void*)NULL, 0,
|
||||
(void*)&bytes, sizeof(bytes));
|
||||
if (st == STATUS_SUCCESS) {
|
||||
fd->geo_size = bytes;
|
||||
fd->geo_sectors = bytes/geo.BytesPerSector;
|
||||
}
|
||||
}
|
||||
return (res);
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_win32_open_file - open a file via win32 API
|
||||
* @filename: name of the file to open
|
||||
|
@ -516,12 +776,22 @@ static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd,
|
|||
int flags)
|
||||
{
|
||||
HANDLE handle;
|
||||
int mode;
|
||||
|
||||
if (ntfs_device_win32_simple_open_file(filename, &handle, flags,
|
||||
FALSE)) {
|
||||
/* open error */
|
||||
return -1;
|
||||
}
|
||||
mode = flags & O_ACCMODE;
|
||||
if ((mode == O_RDWR) || (mode == O_WRONLY)) {
|
||||
DWORD bytes;
|
||||
|
||||
/* try making sparse (but ignore errors) */
|
||||
DeviceIoControl(handle, FSCTL_SET_SPARSE,
|
||||
(void*)NULL, 0, (void*)NULL, 0,
|
||||
&bytes, (LPOVERLAPPED)NULL);
|
||||
}
|
||||
/* fill fd */
|
||||
fd->handle = handle;
|
||||
fd->part_start = 0;
|
||||
|
@ -530,6 +800,8 @@ static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd,
|
|||
fd->part_hidden_sectors = -1;
|
||||
fd->geo_size = -1; /* used as a marker that this is a file */
|
||||
fd->vol_handle = INVALID_HANDLE_VALUE;
|
||||
fd->geo_sector_size = 512; /* will be adjusted from the boot sector */
|
||||
fd->ntdll = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -561,6 +833,90 @@ static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd,
|
|||
if (fd->geo_size == -1)
|
||||
fd->geo_size = ntfs_device_win32_getdisklength(handle);
|
||||
/* fill fd */
|
||||
fd->ntdll = FALSE;
|
||||
fd->handle = handle;
|
||||
fd->part_start = 0;
|
||||
fd->part_length = fd->geo_size;
|
||||
fd->pos = 0;
|
||||
fd->part_hidden_sectors = -1;
|
||||
fd->vol_handle = INVALID_HANDLE_VALUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_device_win32_open_lowlevel - open a drive via low level win32 API
|
||||
* @drive_id: drive to open
|
||||
* @fd: pointer to win32 file device in which to put the result
|
||||
* @flags: unix open status flags
|
||||
*
|
||||
* return 0 if o.k.
|
||||
* -1 if not, and errno set.
|
||||
*/
|
||||
static __inline__ int ntfs_device_win32_open_lowlevel(int drive_id,
|
||||
win32_fd *fd, int flags)
|
||||
{
|
||||
HANDLE handle;
|
||||
NTSTATUS st;
|
||||
ACCESS_MASK access;
|
||||
ULONG share;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
IO_STATUS_BLOCK io_status;
|
||||
UNICODE_STRING unicode_name;
|
||||
ntfschar unicode_buffer[7];
|
||||
int mode;
|
||||
static const ntfschar unicode_init[] = {
|
||||
const_cpu_to_le16('\\'), const_cpu_to_le16('?'),
|
||||
const_cpu_to_le16('?'), const_cpu_to_le16('\\'),
|
||||
const_cpu_to_le16(' '), const_cpu_to_le16(':'),
|
||||
const_cpu_to_le16(0)
|
||||
};
|
||||
|
||||
memcpy(unicode_buffer, unicode_init, sizeof(unicode_buffer));
|
||||
unicode_buffer[4] = cpu_to_le16(drive_id + 'A');
|
||||
unicode_name.Buffer = unicode_buffer;
|
||||
unicode_name.Length = 6*sizeof(ntfschar);
|
||||
unicode_name.MaximumLength = 6*sizeof(ntfschar);
|
||||
|
||||
attr.Length = sizeof(OBJECT_ATTRIBUTES);
|
||||
attr.RootDirectory = (HANDLE*)NULL;
|
||||
attr.ObjectName = &unicode_name;
|
||||
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
||||
attr.SecurityDescriptor = (void*)NULL;
|
||||
attr.SecurityQualityOfService = (void*)NULL;
|
||||
|
||||
io_status.Status = 0;
|
||||
io_status.Information = 0;
|
||||
mode = flags & O_ACCMODE;
|
||||
share = (mode == O_RDWR ?
|
||||
0 : FILE_SHARE_READ | FILE_SHARE_WRITE);
|
||||
access = (mode == O_RDWR ?
|
||||
FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE
|
||||
: FILE_READ_DATA | SYNCHRONIZE);
|
||||
|
||||
st = NtOpenFile(&handle, access,
|
||||
&attr, &io_status,
|
||||
share,
|
||||
FILE_SYNCHRONOUS_IO_ALERT);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
errno = ntfs_ntstatus_to_errno(st);
|
||||
return (-1);
|
||||
}
|
||||
ntfs_device_win32_setlock(handle,FSCTL_LOCK_VOLUME);
|
||||
/* store the drive geometry */
|
||||
ntfs_device_win32_getntgeo(handle, fd);
|
||||
fd->ntdll = TRUE;
|
||||
/* allow accessing the full partition */
|
||||
st = NtFsControlFile(handle, (HANDLE)NULL,
|
||||
(PIO_APC_ROUTINE)NULL,
|
||||
(PVOID)NULL, &io_status,
|
||||
FSCTL_ALLOW_EXTENDED_DASD_IO,
|
||||
NULL, 0, NULL, 0);
|
||||
if (st != STATUS_SUCCESS) {
|
||||
errno = ntfs_ntstatus_to_errno(st);
|
||||
NtClose(handle);
|
||||
return (-1);
|
||||
}
|
||||
/* fill fd */
|
||||
fd->handle = handle;
|
||||
fd->part_start = 0;
|
||||
fd->part_length = fd->geo_size;
|
||||
|
@ -694,7 +1050,7 @@ static BOOL ntfs_device_win32_find_partition(HANDLE handle, DWORD partition_id,
|
|||
do {
|
||||
buf_size = sizeof(DRIVE_LAYOUT_INFORMATION) +
|
||||
part_count * sizeof(PARTITION_INFORMATION);
|
||||
drive_layout = malloc(buf_size);
|
||||
drive_layout = (DRIVE_LAYOUT_INFORMATION*)ntfs_malloc(buf_size);
|
||||
if (!drive_layout) {
|
||||
errno = ENOMEM;
|
||||
return FALSE;
|
||||
|
@ -775,6 +1131,8 @@ static int ntfs_device_win32_open_partition(int drive_id,
|
|||
fd->part_start = part_start;
|
||||
fd->part_length = part_length;
|
||||
fd->part_hidden_sectors = hidden_sectors;
|
||||
fd->geo_sector_size = 512;
|
||||
fd->ntdll = FALSE;
|
||||
tmp = ntfs_device_win32_getntfssize(vol_handle);
|
||||
if (tmp > 0)
|
||||
fd->geo_size = tmp;
|
||||
|
@ -837,7 +1195,13 @@ static int ntfs_device_win32_open(struct ntfs_device *dev, int flags)
|
|||
}
|
||||
ntfs_device_win32_init_imports();
|
||||
numparams = sscanf(dev->d_name, "/dev/hd%c%u", &drive_char, &part);
|
||||
drive_id = toupper(drive_char) - 'A';
|
||||
if (!numparams
|
||||
&& (dev->d_name[1] == ':')
|
||||
&& (dev->d_name[2] == '\0')) {
|
||||
drive_char = dev->d_name[0];
|
||||
numparams = 3;
|
||||
drive_id = toupper(drive_char) - 'A';
|
||||
}
|
||||
switch (numparams) {
|
||||
case 0:
|
||||
ntfs_log_debug("win32_open(%s) -> file.\n", dev->d_name);
|
||||
|
@ -854,6 +1218,12 @@ static int ntfs_device_win32_open(struct ntfs_device *dev, int flags)
|
|||
err = ntfs_device_win32_open_partition(drive_id, part, &fd,
|
||||
flags);
|
||||
break;
|
||||
case 3:
|
||||
ntfs_log_debug("win32_open(%s) -> drive %c:\n",
|
||||
dev->d_name, drive_char);
|
||||
err = ntfs_device_win32_open_lowlevel(drive_id, &fd,
|
||||
flags);
|
||||
break;
|
||||
default:
|
||||
ntfs_log_debug("win32_open(%s) -> unknwon file format.\n",
|
||||
dev->d_name);
|
||||
|
@ -866,7 +1236,7 @@ static int ntfs_device_win32_open(struct ntfs_device *dev, int flags)
|
|||
/* Setup our read-only flag. */
|
||||
if ((flags & O_RDWR) != O_RDWR)
|
||||
NDevSetReadOnly(dev);
|
||||
dev->d_private = malloc(sizeof(win32_fd));
|
||||
dev->d_private = (win32_fd*)ntfs_malloc(sizeof(win32_fd));
|
||||
memcpy(dev->d_private, &fd, sizeof(win32_fd));
|
||||
NDevSetOpen(dev);
|
||||
NDevClearDirty(dev);
|
||||
|
@ -916,7 +1286,8 @@ static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset,
|
|||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (abs_ofs < 0 || abs_ofs > fd->part_length) {
|
||||
if ((abs_ofs < 0)
|
||||
|| (fd->ntdll && (abs_ofs > fd->part_length))) {
|
||||
ntfs_log_trace("Seeking outsize seekable area.\n");
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
|
@ -937,18 +1308,19 @@ static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset,
|
|||
* error returns -1 and errno set. Transfer starts from position @pos on @fd.
|
||||
*
|
||||
* Notes:
|
||||
* - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
|
||||
* - @pos, @buf, and @count must be aligned to geo_sector_size
|
||||
* - When dealing with volumes, a single call must not span both volume
|
||||
* and disk extents.
|
||||
* - Does not use/set @fd->pos.
|
||||
*/
|
||||
static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos,
|
||||
const s64 count, void *b, const BOOL write)
|
||||
const s64 count, void *rbuf, const void *wbuf)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
HANDLE handle;
|
||||
DWORD bt;
|
||||
BOOL res;
|
||||
s64 bytes;
|
||||
|
||||
ntfs_log_trace("pos = 0x%llx, count = 0x%llx, direction = %s.\n",
|
||||
(long long)pos, (long long)count, write ? "write" :
|
||||
|
@ -962,21 +1334,57 @@ static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos,
|
|||
handle = fd->handle;
|
||||
li.QuadPart += fd->part_start;
|
||||
}
|
||||
if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) {
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
ntfs_log_trace("SetFilePointer failed.\n");
|
||||
return -1;
|
||||
|
||||
if (fd->ntdll) {
|
||||
IO_STATUS_BLOCK io_status;
|
||||
NTSTATUS res;
|
||||
LARGE_INTEGER offset;
|
||||
|
||||
io_status.Status = STATUS_SUCCESS;
|
||||
io_status.Information = 0;
|
||||
offset.QuadPart = pos;
|
||||
if (wbuf) {
|
||||
res = NtWriteFile(fd->handle,(HANDLE)NULL,
|
||||
(PIO_APC_ROUTINE)NULL,(void*)NULL,
|
||||
&io_status, wbuf, count,
|
||||
&offset, (PULONG)NULL);
|
||||
} else {
|
||||
res = NtReadFile(fd->handle,(HANDLE)NULL,
|
||||
(PIO_APC_ROUTINE)NULL,(void*)NULL,
|
||||
&io_status, rbuf, count,
|
||||
&offset, (PULONG)NULL);
|
||||
}
|
||||
if (res == STATUS_SUCCESS) {
|
||||
bytes = io_status.Information;
|
||||
} else {
|
||||
bytes = -1;
|
||||
errno = ntfs_ntstatus_to_errno(res);
|
||||
}
|
||||
} else {
|
||||
if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) {
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
ntfs_log_trace("SetFilePointer failed.\n");
|
||||
return -1;
|
||||
}
|
||||
if (wbuf)
|
||||
res = WriteFile(handle, wbuf, count, &bt, NULL);
|
||||
else
|
||||
res = ReadFile(handle, rbuf, count, &bt, NULL);
|
||||
bytes = bt;
|
||||
if (!res) {
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
ntfs_log_trace("%sFile() failed.\n", write ?
|
||||
"Write" : "Read");
|
||||
return -1;
|
||||
}
|
||||
if (rbuf && !pos) {
|
||||
/* get the sector size from the boot sector */
|
||||
char *boot = (char*)rbuf;
|
||||
fd->geo_sector_size = (boot[11] & 255)
|
||||
+ ((boot[12] & 255) << 8);
|
||||
}
|
||||
}
|
||||
if (write)
|
||||
res = WriteFile(handle, b, count, &bt, NULL);
|
||||
else
|
||||
res = ReadFile(handle, b, count, &bt, NULL);
|
||||
if (!res) {
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
ntfs_log_trace("%sFile() failed.\n", write ? "Write" : "Read");
|
||||
return -1;
|
||||
}
|
||||
return bt;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -990,7 +1398,7 @@ static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos,
|
|||
* returns -1 and errno set. Read starts from position @pos.
|
||||
*
|
||||
* Notes:
|
||||
* - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
|
||||
* - @pos, @buf, and @count must be aligned to geo_sector_size.
|
||||
* - When dealing with volumes, a single call must not span both volume
|
||||
* and disk extents.
|
||||
* - Does not use/set @fd->pos.
|
||||
|
@ -998,7 +1406,7 @@ static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos,
|
|||
static inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos,
|
||||
const s64 count, void *b)
|
||||
{
|
||||
return ntfs_device_win32_pio(fd, pos, count, b, FALSE);
|
||||
return ntfs_device_win32_pio(fd, pos, count, b, (void*)NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1018,9 +1426,9 @@ static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count)
|
|||
int old_ofs, ofs;
|
||||
|
||||
old_pos = fd->pos;
|
||||
old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1);
|
||||
to_read = (ofs + count + NTFS_BLOCK_SIZE - 1) &
|
||||
~(s64)(NTFS_BLOCK_SIZE - 1);
|
||||
old_ofs = ofs = old_pos & (fd->geo_sector_size - 1);
|
||||
to_read = (ofs + count + fd->geo_sector_size - 1) &
|
||||
~(s64)(fd->geo_sector_size - 1);
|
||||
/* Impose maximum of 2GB to be on the safe side. */
|
||||
if (to_read > 0x80000000) {
|
||||
int delta = to_read - count;
|
||||
|
@ -1031,8 +1439,8 @@ static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count)
|
|||
"ofs = %i, to_read = 0x%llx.\n", fd, b,
|
||||
(long long)count, (long long)old_pos, ofs,
|
||||
(long long)to_read);
|
||||
if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
|
||||
!(count & (NTFS_BLOCK_SIZE - 1)))
|
||||
if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs &&
|
||||
!(count & (fd->geo_sector_size - 1)))
|
||||
alignedbuffer = b;
|
||||
else {
|
||||
alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT,
|
||||
|
@ -1047,7 +1455,7 @@ static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count)
|
|||
s64 vol_to_read = fd->geo_size - old_pos;
|
||||
if (count > vol_to_read) {
|
||||
br = ntfs_device_win32_pread_simple(fd,
|
||||
old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
|
||||
old_pos & ~(s64)(fd->geo_sector_size - 1),
|
||||
ofs + vol_to_read, alignedbuffer);
|
||||
if (br == -1)
|
||||
goto read_error;
|
||||
|
@ -1058,13 +1466,13 @@ static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count)
|
|||
}
|
||||
br -= ofs;
|
||||
fd->pos += br;
|
||||
ofs = fd->pos & (NTFS_BLOCK_SIZE - 1);
|
||||
ofs = fd->pos & (fd->geo_sector_size - 1);
|
||||
if (br != vol_to_read)
|
||||
goto read_partial;
|
||||
}
|
||||
}
|
||||
i = ntfs_device_win32_pread_simple(fd,
|
||||
fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_read,
|
||||
fd->pos & ~(s64)(fd->geo_sector_size - 1), to_read,
|
||||
alignedbuffer + br);
|
||||
if (i == -1) {
|
||||
if (br)
|
||||
|
@ -1115,11 +1523,18 @@ static int ntfs_device_win32_close(struct ntfs_device *dev)
|
|||
if (!CloseHandle(fd->vol_handle))
|
||||
ntfs_log_trace("CloseHandle() failed for volume.\n");
|
||||
}
|
||||
rvl = CloseHandle(fd->handle);
|
||||
if (fd->ntdll) {
|
||||
ntfs_device_win32_setlock(fd->handle,FSCTL_UNLOCK_VOLUME);
|
||||
rvl = NtClose(fd->handle) == STATUS_SUCCESS;
|
||||
} else
|
||||
rvl = CloseHandle(fd->handle);
|
||||
free(fd);
|
||||
if (!rvl) {
|
||||
errno = ntfs_w32error_to_errno(GetLastError());
|
||||
ntfs_log_trace("CloseHandle() failed.\n");
|
||||
if (fd->ntdll)
|
||||
ntfs_log_trace("NtClose() failed.\n");
|
||||
else
|
||||
ntfs_log_trace("CloseHandle() failed.\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -1174,7 +1589,7 @@ static int ntfs_device_win32_sync(struct ntfs_device *dev)
|
|||
* errno set. Write starts from position @pos.
|
||||
*
|
||||
* Notes:
|
||||
* - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
|
||||
* - @pos, @buf, and @count must be aligned to geo_sector_size.
|
||||
* - When dealing with volumes, a single call must not span both volume
|
||||
* and disk extents.
|
||||
* - Does not use/set @fd->pos.
|
||||
|
@ -1182,7 +1597,7 @@ static int ntfs_device_win32_sync(struct ntfs_device *dev)
|
|||
static inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos,
|
||||
const s64 count, const void *b)
|
||||
{
|
||||
return ntfs_device_win32_pio(fd, pos, count, (void *)b, TRUE);
|
||||
return ntfs_device_win32_pio(fd, pos, count, (void*)NULL, b);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1203,9 +1618,9 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
|||
int old_ofs, ofs;
|
||||
|
||||
old_pos = fd->pos;
|
||||
old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1);
|
||||
to_write = (ofs + count + NTFS_BLOCK_SIZE - 1) &
|
||||
~(s64)(NTFS_BLOCK_SIZE - 1);
|
||||
old_ofs = ofs = old_pos & (fd->geo_sector_size - 1);
|
||||
to_write = (ofs + count + fd->geo_sector_size - 1) &
|
||||
~(s64)(fd->geo_sector_size - 1);
|
||||
/* Impose maximum of 2GB to be on the safe side. */
|
||||
if (to_write > 0x80000000) {
|
||||
int delta = to_write - count;
|
||||
|
@ -1224,8 +1639,8 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
|||
if (!count)
|
||||
return 0;
|
||||
NDevSetDirty(dev);
|
||||
if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
|
||||
!(count & (NTFS_BLOCK_SIZE - 1)))
|
||||
if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs &&
|
||||
!(count & (fd->geo_sector_size - 1)))
|
||||
alignedbuffer = (BYTE *)b;
|
||||
else {
|
||||
s64 end;
|
||||
|
@ -1240,9 +1655,9 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
|||
/* Read first sector if start of write not sector aligned. */
|
||||
if (ofs) {
|
||||
i = ntfs_device_win32_pread_simple(fd,
|
||||
old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
|
||||
NTFS_BLOCK_SIZE, alignedbuffer);
|
||||
if (i != NTFS_BLOCK_SIZE) {
|
||||
old_pos & ~(s64)(fd->geo_sector_size - 1),
|
||||
fd->geo_sector_size, alignedbuffer);
|
||||
if (i != fd->geo_sector_size) {
|
||||
if (i >= 0)
|
||||
errno = EIO;
|
||||
goto write_error;
|
||||
|
@ -1255,13 +1670,13 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
|||
* yet, i.e. the start of the write is sector aligned.
|
||||
*/
|
||||
end = old_pos + count;
|
||||
if ((end & (NTFS_BLOCK_SIZE - 1)) &&
|
||||
((to_write > NTFS_BLOCK_SIZE) || !ofs)) {
|
||||
if ((end & (fd->geo_sector_size - 1)) &&
|
||||
((to_write > fd->geo_sector_size) || !ofs)) {
|
||||
i = ntfs_device_win32_pread_simple(fd,
|
||||
end & ~(s64)(NTFS_BLOCK_SIZE - 1),
|
||||
NTFS_BLOCK_SIZE, alignedbuffer +
|
||||
to_write - NTFS_BLOCK_SIZE);
|
||||
if (i != NTFS_BLOCK_SIZE) {
|
||||
end & ~(s64)(fd->geo_sector_size - 1),
|
||||
fd->geo_sector_size, alignedbuffer +
|
||||
to_write - fd->geo_sector_size);
|
||||
if (i != fd->geo_sector_size) {
|
||||
if (i >= 0)
|
||||
errno = EIO;
|
||||
goto write_error;
|
||||
|
@ -1274,7 +1689,7 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
|||
s64 vol_to_write = fd->geo_size - old_pos;
|
||||
if (count > vol_to_write) {
|
||||
bw = ntfs_device_win32_pwrite_simple(fd,
|
||||
old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
|
||||
old_pos & ~(s64)(fd->geo_sector_size - 1),
|
||||
ofs + vol_to_write, alignedbuffer);
|
||||
if (bw == -1)
|
||||
goto write_error;
|
||||
|
@ -1285,13 +1700,13 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b,
|
|||
}
|
||||
bw -= ofs;
|
||||
fd->pos += bw;
|
||||
ofs = fd->pos & (NTFS_BLOCK_SIZE - 1);
|
||||
ofs = fd->pos & (fd->geo_sector_size - 1);
|
||||
if (bw != vol_to_write)
|
||||
goto write_partial;
|
||||
}
|
||||
}
|
||||
i = ntfs_device_win32_pwrite_simple(fd,
|
||||
fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_write,
|
||||
fd->pos & ~(s64)(fd->geo_sector_size - 1), to_write,
|
||||
alignedbuffer + bw);
|
||||
if (i == -1) {
|
||||
if (bw)
|
||||
|
@ -1352,6 +1767,7 @@ static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HDIO_GETGEO
|
||||
/**
|
||||
* ntfs_win32_hdio_getgeo - get drive geometry
|
||||
* @dev: ntfs device obtained via ->open
|
||||
|
@ -1373,6 +1789,7 @@ static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev,
|
|||
argp->start = fd->part_hidden_sectors;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* ntfs_win32_blksszget - get block device sector size
|
||||
|
@ -1404,7 +1821,9 @@ static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp)
|
|||
static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
|
||||
void *argp)
|
||||
{
|
||||
#if defined(BLKGETSIZE) | defined(BLKGETSIZE64)
|
||||
win32_fd *fd = (win32_fd *)dev->d_private;
|
||||
#endif
|
||||
|
||||
ntfs_log_trace("win32_ioctl(%d) called.\n", request);
|
||||
switch (request) {
|
||||
|
@ -1454,13 +1873,40 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
|
|||
static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b,
|
||||
s64 count, s64 offset)
|
||||
{
|
||||
return ntfs_pread(dev, offset, count, b);
|
||||
s64 got;
|
||||
win32_fd *fd;
|
||||
|
||||
/* read the fast way if sector aligned */
|
||||
fd = (win32_fd*)dev->d_private;
|
||||
if (!((count | offset) & (fd->geo_sector_size - 1))) {
|
||||
got = ntfs_device_win32_pio(fd, offset, count, b, (void*)NULL);
|
||||
} else {
|
||||
if (ntfs_device_win32_seek(dev, offset, 0) == -1)
|
||||
got = 0;
|
||||
else
|
||||
got = ntfs_device_win32_read(dev, b, count);
|
||||
}
|
||||
|
||||
return (got);
|
||||
}
|
||||
|
||||
static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b,
|
||||
s64 count, s64 offset)
|
||||
{
|
||||
return ntfs_pwrite(dev, offset, count, b);
|
||||
s64 put;
|
||||
win32_fd *fd;
|
||||
|
||||
/* write the fast way if sector aligned */
|
||||
fd = (win32_fd*)dev->d_private;
|
||||
if (!((count | offset) & (fd->geo_sector_size - 1))) {
|
||||
put = ntfs_device_win32_pio(fd, offset, count, (void*)NULL, b);
|
||||
} else {
|
||||
if (ntfs_device_win32_seek(dev, offset, 0) == -1)
|
||||
put = 0;
|
||||
else
|
||||
put = ntfs_device_win32_write(dev, b, count);
|
||||
}
|
||||
return (put);
|
||||
}
|
||||
|
||||
struct ntfs_device_operations ntfs_device_win32_io_ops = {
|
||||
|
@ -1475,3 +1921,87 @@ struct ntfs_device_operations ntfs_device_win32_io_ops = {
|
|||
.stat = ntfs_device_win32_stat,
|
||||
.ioctl = ntfs_device_win32_ioctl
|
||||
};
|
||||
|
||||
/*
|
||||
* Mark an open file as sparse
|
||||
*
|
||||
* This is only called by ntfsclone when cloning a volume to a file.
|
||||
* The argument is the target file, not a volume.
|
||||
*
|
||||
* Returns 0 if successful.
|
||||
*/
|
||||
|
||||
int ntfs_win32_set_sparse(int fd)
|
||||
{
|
||||
BOOL ok;
|
||||
HANDLE handle;
|
||||
DWORD bytes;
|
||||
|
||||
handle = get_osfhandle(fd);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
ok = FALSE;
|
||||
else
|
||||
ok = DeviceIoControl(handle, FSCTL_SET_SPARSE,
|
||||
(void*)NULL, 0, (void*)NULL, 0,
|
||||
&bytes, (LPOVERLAPPED)NULL);
|
||||
return (!ok);
|
||||
}
|
||||
|
||||
/*
|
||||
* Resize an open file
|
||||
*
|
||||
* This is only called by ntfsclone when cloning a volume to a file.
|
||||
* The argument must designate a file, not a volume.
|
||||
*
|
||||
* Returns 0 if successful.
|
||||
*/
|
||||
|
||||
static int win32_ftruncate(HANDLE handle, s64 size)
|
||||
{
|
||||
BOOL ok;
|
||||
LONG hsize, lsize;
|
||||
LONG ohsize, olsize;
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
ok = FALSE;
|
||||
else {
|
||||
SetLastError(NO_ERROR);
|
||||
/* save original position */
|
||||
ohsize = 0;
|
||||
olsize = SetFilePointer(handle, 0, &ohsize, 1);
|
||||
hsize = size >> 32;
|
||||
lsize = size & 0xffffffff;
|
||||
ok = (SetFilePointer(handle, lsize, &hsize, 0) == (DWORD)lsize)
|
||||
&& (GetLastError() == NO_ERROR)
|
||||
&& SetEndOfFile(handle);
|
||||
/* restore original position, even if above failed */
|
||||
SetFilePointer(handle, olsize, &ohsize, 0);
|
||||
if (GetLastError() != NO_ERROR)
|
||||
ok = FALSE;
|
||||
}
|
||||
if (!ok)
|
||||
errno = EINVAL;
|
||||
return (ok ? 0 : -1);
|
||||
}
|
||||
|
||||
int ntfs_device_win32_ftruncate(struct ntfs_device *dev, s64 size)
|
||||
{
|
||||
win32_fd *fd;
|
||||
int ret;
|
||||
|
||||
ret = -1;
|
||||
fd = (win32_fd*)dev->d_private;
|
||||
if (fd && !fd->ntdll)
|
||||
ret = win32_ftruncate(fd->handle, size);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int ntfs_win32_ftruncate(int fd, s64 size)
|
||||
{
|
||||
int ret;
|
||||
HANDLE handle;
|
||||
|
||||
handle = get_osfhandle(fd);
|
||||
ret = win32_ftruncate(handle, size);
|
||||
return (ret);
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ int utils_valid_device(const char *name, int force)
|
|||
unsigned long mnt_flags = 0;
|
||||
struct stat st;
|
||||
|
||||
#ifdef __CYGWIN32__
|
||||
#if defined(HAVE_WINDOWS_H) | defined(__CYGWIN32__)
|
||||
/* FIXME: This doesn't work for Cygwin, so just return success. */
|
||||
return 1;
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue