From 62a4484a94e95b29aa3b65b957ddce49c3f6f990 Mon Sep 17 00:00:00 2001 From: antona Date: Mon, 6 Jun 2005 14:30:38 +0000 Subject: [PATCH] Finally fix the win32 write support problems. --- libntfs/win32_io.c | 956 ++++++++++++++++++++++----------------------- 1 file changed, 459 insertions(+), 497 deletions(-) diff --git a/libntfs/win32_io.c b/libntfs/win32_io.c index 6efb19e5..26e77ac6 100644 --- a/libntfs/win32_io.c +++ b/libntfs/win32_io.c @@ -42,7 +42,11 @@ struct stat; struct ntfs_volume; typedef struct ntfs_volume ntfs_volume; -#include "config.h" +#ifndef NTFS_BLOCK_SIZE +#define NTFS_BLOCK_SIZE 512 +#define NTFS_BLOCK_SIZE_BITS 9 +#endif + #include "debug.h" /* Need device, but prevent ../include/types.h to be loaded. */ @@ -72,21 +76,20 @@ static LPFN_SETFILEPOINTEREX fnSetFilePointerEx = NULL; #define FNPOSTFIX "A" #endif -typedef struct win32_fd { +typedef struct { HANDLE handle; - int part_hidden_sectors; + s64 pos; /* Logical current position on the volume. */ s64 part_start; s64 part_length; - s64 real_pos; - int real_ofs; + int part_hidden_sectors; s64 geo_size, geo_cylinders; DWORD geo_sectors, geo_heads; HANDLE vol_handle; } win32_fd; /** - * ntfs_w32error_to_errno - Convert a win32 error code to the unix one - * @w32error The win32 error code. + * ntfs_w32error_to_errno - convert a win32 error code to the unix one + * @w32error: the win32 error code * * Limited to a relatively small but useful number of codes. */ @@ -158,7 +161,7 @@ static BOOL WINAPI libntfs_SetFilePointerEx(HANDLE hFile, } /** - * ntfs_device_win32_init_imports - initialize the function pointers. + * ntfs_device_win32_init_imports - initialize the function pointers * * The Find*Volume and SetFilePointerEx functions exist only on win2k+, as such * we cannot just staticly import them. @@ -209,41 +212,44 @@ static void ntfs_device_win32_init_imports(void) /** * ntfs_device_unix_status_flags_to_win32 - convert unix->win32 open flags - * @flags: Unix open status flags. + * @flags: unix open status flags * * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. */ static __inline__ int ntfs_device_unix_status_flags_to_win32(int flags) { + int win_mode; + switch (flags & O_ACCMODE) { - case O_RDONLY: - return FILE_READ_DATA; - break; - case O_WRONLY: - return FILE_WRITE_DATA; - break; - case O_RDWR: - return FILE_READ_DATA | FILE_WRITE_DATA; - break; - default: - /* error */ - Dputs("win32_unix_status_flags_to_win32: flags unknown"); - return 0; + case O_RDONLY: + win_mode = FILE_READ_DATA; + break; + case O_WRONLY: + win_mode = FILE_WRITE_DATA; + break; + case O_RDWR: + win_mode = FILE_READ_DATA | FILE_WRITE_DATA; + break; + default: + /* error */ + Dputs("win32_unix_status_flags_to_win32: unknown flags"); + win_mode = 0; } + return win_mode; } /** - * ntfs_device_win32_simple_open_file - Just open a file via win32 API - * @filename: Name of the file to open. - * @handle: Pointer the a HANDLE in which to put the result. - * @flags: Unix open status flags. + * ntfs_device_win32_simple_open_file - just open a file via win32 API + * @filename: name of the file to open + * @handle: pointer the a HANDLE in which to put the result + * @flags: unix open status flags * @locking: will the function gain an exclusive lock on the file? * * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. * * Return 0 if o.k. - * -1 if not, and errno set. in this case handle is trashed. + * -1 if not, and errno set. In this case handle is trashed. */ static int ntfs_device_win32_simple_open_file(const char *filename, HANDLE *handle, int flags, BOOL locking) @@ -252,7 +258,6 @@ static int ntfs_device_win32_simple_open_file(const char *filename, ntfs_device_unix_status_flags_to_win32(flags), locking ? 0 : (FILE_SHARE_WRITE | FILE_SHARE_READ), NULL, OPEN_EXISTING, 0, NULL); - if (*handle == INVALID_HANDLE_VALUE) { errno = ntfs_w32error_to_errno(GetLastError()); Dprintf("CreateFile(%s) failed.\n", filename); @@ -262,8 +267,8 @@ static int ntfs_device_win32_simple_open_file(const char *filename, } /** - * ntfs_device_win32_lock - Lock the volume - * @handle: A win32 HANDLE for a volume to lock. + * ntfs_device_win32_lock - lock the volume + * @handle: a win32 HANDLE for a volume to lock * * Locking a volume means no one can access its contents. * Exiting the process automatically unlocks the volume, except in old NT4s. @@ -274,6 +279,7 @@ static int ntfs_device_win32_simple_open_file(const char *filename, static int ntfs_device_win32_lock(HANDLE handle) { DWORD i; + if (!DeviceIoControl(handle, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); @@ -285,8 +291,8 @@ static int ntfs_device_win32_lock(HANDLE handle) } /** - * ntfs_device_win32_unlock - Unlock the volume - * @handle: The win32 HANDLE which the volume was locked with. + * ntfs_device_win32_unlock - unlock the volume + * @handle: the win32 HANDLE which the volume was locked with * * Return 0 if o.k. * -1 if not, and errno set. @@ -294,6 +300,7 @@ static int ntfs_device_win32_lock(HANDLE handle) static int ntfs_device_win32_unlock(HANDLE handle) { DWORD i; + if (!DeviceIoControl(handle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); @@ -305,14 +312,14 @@ static int ntfs_device_win32_unlock(HANDLE handle) } /** - * ntfs_device_win32_dismount - Dismount a volume - * @handle: A win32 HANDLE for a volume to dismount. + * ntfs_device_win32_dismount - dismount a volume + * @handle: a win32 HANDLE for a volume to dismount * - * Dismounting means the system will refresh the volume in the first change - * it gets. Usefull after altering the file structures. + * Dismounting means the system will refresh the volume in the first change it + * gets. Usefull after altering the file structures. * The volume must be locked by the current process while dismounting. - * A side effect is that the volume is also unlocked, but you mustn't rely - * On this. + * A side effect is that the volume is also unlocked, but you must not rely om + * this. * * Return 0 if o.k. * -1 if not, and errno set. @@ -320,6 +327,7 @@ static int ntfs_device_win32_unlock(HANDLE handle) static int ntfs_device_win32_dismount(HANDLE handle) { DWORD i; + if (!DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); @@ -332,8 +340,8 @@ static int ntfs_device_win32_dismount(HANDLE handle) } /** - * ntfs_device_win32_getsize - Get file size via win32 API - * @handle: Pointer the file HANDLE obtained via open. + * ntfs_device_win32_getsize - get file size via win32 API + * @handle: pointer the file HANDLE obtained via open * * Only works on ordinary files. * @@ -350,13 +358,13 @@ static s64 ntfs_device_win32_getsize(HANDLE handle) Dputs("Error: Couldn't get file size."); return -1; } - return ((s64)hiword << 32) + (s64)loword; + return ((s64)hiword << 32) + loword; } /** - * ntfs_device_win32_getdisklength - Get disk size via win32 API - * @handle: Pointer the file HANDLE obtained via open. - * @argp: Pointer to result buffer. + * ntfs_device_win32_getdisklength - get disk size via win32 API + * @handle: pointer the file HANDLE obtained via open + * @argp: pointer to result buffer * * Only works on PhysicalDriveX type handles. * @@ -380,16 +388,16 @@ static s64 ntfs_device_win32_getdisklength(HANDLE handle) } /** - * ntfs_device_win32_getntfssize - Get NTFS volume size via win32 API - * @handle: Pointer the file HANDLE obtained via open. - * @argp: Pointer to result buffer. + * ntfs_device_win32_getntfssize - get NTFS volume size via win32 API + * @handle: pointer the file HANDLE obtained via open + * @argp: pointer to result buffer * * Only works on NTFS volume handles. - * An annoying bug in windows is that a NTFS volume does not occupy the - * Entire partition, namely not the last sector (Which holds the backup - * Boot sector, and normally not interesting). - * Use this function to get the length of the accessible space through a - * given volume handle. + * An annoying bug in windows is that a NTFS volume does not occupy the entire + * partition, namely not the last sector (which holds the backup boot sector, + * and normally not interesting). + * Use this function to get the length of the accessible space through a given + * volume handle. * * Return The volume size if o.k. * -1 if not, and errno set. @@ -397,106 +405,101 @@ static s64 ntfs_device_win32_getdisklength(HANDLE handle) static s64 ntfs_device_win32_getntfssize(HANDLE handle) { #ifdef FSCTL_GET_NTFS_VOLUME_DATA - NTFS_VOLUME_DATA_BUFFER buf; + s64 rvl; DWORD i; + NTFS_VOLUME_DATA_BUFFER buf; if (!DeviceIoControl(handle, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &buf, sizeof(buf), &i, NULL)) { errno = ntfs_w32error_to_errno(GetLastError()); Dputs("Warnning: Couldn't get NTFS volume length."); return -1; - } else { - s64 rvl = buf.NumberSectors.QuadPart * buf.BytesPerSector; - Dprintf("NTFS volume length: 0x%llx\n", (long long)rvl); - return rvl; } + rvl = buf.NumberSectors.QuadPart * buf.BytesPerSector; + Dprintf("NTFS volume length: 0x%llx\n", (long long)rvl); #else - return -1; + errno = EINVAL; + rvl = -1; #endif + return rvl; } /** - * ntfs_device_win32_getgeo - Get CHS information of a drive. - * @handle: An open handle to the PhysicalDevice - * @fd: a win_fd structure that will be filled. + * ntfs_device_win32_getgeo - get CHS information of a drive + * @handle: an open handle to the PhysicalDevice + * @fd: a win_fd structure that will be filled * * Return 0 if o.k. - * -1 if not + * -1 if not, and errno set. * - * In Windows NT+: fills the members: size, sectors, cylinders - * and set heads to -1. - * In Windows XP+: fills the members: size, sectors, cylinders and heads. + * In Windows NT+: fills size, sectors, and cylinders and sets heads to -1. + * In Windows XP+: fills size, sectors, cylinders, and heads. * - * Note: in pre XP, this requires write permission, even though nothing is - * actually written. + * Note: In pre XP, this requires write permission, even though nothing is + * actually written. * - * if fails, set sectors, cylinders and heads to -1. + * If fails, sets sectors, cylinders, heads, and size to -1. */ static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd *fd) { - BYTE buf[sizeof(DISK_GEOMETRY) + sizeof(DISK_PARTITION_INFO) + - sizeof(DISK_DETECTION_INFO) + 512]; DWORD i; BOOL rvl; + BYTE b[sizeof(DISK_GEOMETRY) + sizeof(DISK_PARTITION_INFO) + + sizeof(DISK_DETECTION_INFO) + 512]; - rvl = DeviceIoControl(handle,IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, - &buf, sizeof(buf), &i, NULL); + rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, + 0, &b, sizeof(b), &i, NULL); if (rvl) { Dputs("GET_DRIVE_GEOMETRY_EX detected."); DISK_DETECTION_INFO *ddi = (PDISK_DETECTION_INFO) - (((PBYTE)(&((PDISK_GEOMETRY_EX)buf)->Data)) + - (((PDISK_PARTITION_INFO)(&((PDISK_GEOMETRY_EX)buf) - ->Data))->SizeOfPartitionInfo)); - - fd->geo_cylinders = ((DISK_GEOMETRY*)&buf)->Cylinders.QuadPart; - fd->geo_sectors = ((DISK_GEOMETRY*)&buf)->SectorsPerTrack; - fd->geo_size = ((DISK_GEOMETRY_EX*)&buf)->DiskSize.QuadPart; + (((PBYTE)(&((PDISK_GEOMETRY_EX)b)->Data)) + + (((PDISK_PARTITION_INFO) + (&((PDISK_GEOMETRY_EX)b)->Data))-> + SizeOfPartitionInfo)); + fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart; + fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack; + fd->geo_size = ((DISK_GEOMETRY_EX*)&b)->DiskSize.QuadPart; switch (ddi->DetectionType) { - case DetectInt13: - fd->geo_cylinders = ddi->Int13.MaxCylinders; - fd->geo_sectors = ddi->Int13.SectorsPerTrack; - fd->geo_heads = ddi->Int13.MaxHeads; - return 0; - case DetectExInt13: - fd->geo_cylinders = ddi->ExInt13.ExCylinders; - fd->geo_sectors = - ddi->ExInt13.ExSectorsPerTrack; - fd->geo_heads = ddi->ExInt13.ExHeads; - return 0; - case DetectNone: - default: - break; + case DetectInt13: + fd->geo_cylinders = ddi->Int13.MaxCylinders; + fd->geo_sectors = ddi->Int13.SectorsPerTrack; + fd->geo_heads = ddi->Int13.MaxHeads; + return 0; + case DetectExInt13: + fd->geo_cylinders = ddi->ExInt13.ExCylinders; + fd->geo_sectors = ddi->ExInt13.ExSectorsPerTrack; + fd->geo_heads = ddi->ExInt13.ExHeads; + return 0; + case DetectNone: + default: + break; } } else fd->geo_heads = -1; - - rvl = DeviceIoControl(handle,IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, - &buf, sizeof(buf), &i, NULL); + rvl = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, + &b, sizeof(b), &i, NULL); if (rvl) { Dputs("GET_DRIVE_GEOMETRY detected."); - fd->geo_cylinders = ((DISK_GEOMETRY*)&buf)->Cylinders.QuadPart; - fd->geo_sectors = ((DISK_GEOMETRY*)&buf)->SectorsPerTrack; + fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart; + fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack; fd->geo_size = fd->geo_cylinders * fd->geo_sectors * - ((DISK_GEOMETRY*)&buf)->TracksPerCylinder * - ((DISK_GEOMETRY*)&buf)->BytesPerSector; + ((DISK_GEOMETRY*)&b)->TracksPerCylinder * + ((DISK_GEOMETRY*)&b)->BytesPerSector; return 0; } - errno = ntfs_w32error_to_errno(GetLastError()); Dputs("Error: Couldn't retrieve disk geometry."); - fd->geo_cylinders = -1; fd->geo_sectors = -1; fd->geo_size = -1; - return -1; } /** - * ntfs_device_win32_open_file - Open a file via win32 API - * @filename: Name of the file to open. - * @fd: Pointer to win32 file device in which to put the result. - * @flags: Unix open status flags. + * ntfs_device_win32_open_file - open a file via win32 API + * @filename: name of the file 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. @@ -511,13 +514,11 @@ static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd, /* open error */ return -1; } - /* fill fd */ fd->handle = handle; fd->part_start = 0; fd->part_length = ntfs_device_win32_getsize(handle); - fd->real_pos = 0; - fd->real_ofs = 0; + fd->pos = 0; fd->part_hidden_sectors = -1; fd->geo_size = -1; /* used as a marker that this is a file */ fd->vol_handle = INVALID_HANDLE_VALUE; @@ -525,50 +526,44 @@ static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd, } /** - * ntfs_device_win32_open_drive - Open a drive via win32 API - * @dev: NTFS_DEVICE to open - * @handle: Win32 file handle to return - * @flags: Unix open status flags. + * ntfs_device_win32_open_drive - open a drive via 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. - * -errno if not + * -1 if not, and errno set. */ static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd, int flags) { - char filename[256]; HANDLE handle; int err; + char filename[MAX_PATH]; sprintf(filename, "\\\\.\\PhysicalDrive%d", drive_id); - if ((err = ntfs_device_win32_simple_open_file(filename, &handle, flags, TRUE))) { /* open error */ return err; } - /* store the drive geometry */ ntfs_device_win32_getgeo(handle, fd); - /* Just to be sure */ if (fd->geo_size == -1) fd->geo_size = ntfs_device_win32_getdisklength(handle); - /* fill fd */ fd->handle = handle; fd->part_start = 0; fd->part_length = fd->geo_size; - fd->real_pos = 0; - fd->real_ofs = 0; + fd->pos = 0; fd->part_hidden_sectors = -1; fd->vol_handle = INVALID_HANDLE_VALUE; - return 0; } /** - * ntfs_device_win32_open_volume_for_partition - find and open a volume. + * ntfs_device_win32_open_volume_for_partition - find and open a volume * * Windows NT/2k/XP handles volumes instead of partitions. * This function gets the partition details and return an open volume handle. @@ -615,28 +610,38 @@ static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id, Dprintf("win32_open_volume_for_partition: Processing %s\n", vol_name); - /* open the file */ handle = CreateFile(vol_name, - ntfs_device_unix_status_flags_to_win32(flags), FILE_SHARE_READ | - FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (handle!=INVALID_HANDLE_VALUE) { -#define EXTENTS_SIZE sizeof(VOLUME_DISK_EXTENTS)+9*sizeof(DISK_EXTENT) - char extents[EXTENTS_SIZE]; + ntfs_device_unix_status_flags_to_win32(flags), + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, 0, NULL); + if (handle != INVALID_HANDLE_VALUE) { DWORD bytesReturned; +#define EXTENTS_SIZE sizeof(VOLUME_DISK_EXTENTS) + 9 * sizeof(DISK_EXTENT) + char extents[EXTENTS_SIZE]; - /* check physical locations */ + /* Check physical locations. */ if (DeviceIoControl(handle, - IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, extents, - EXTENTS_SIZE, &bytesReturned, NULL)) { - if (((VOLUME_DISK_EXTENTS *)extents)->NumberOfDiskExtents==1) { - DISK_EXTENT *extent = &((VOLUME_DISK_EXTENTS *)extents)-> - Extents[0]; + IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, + NULL, 0, extents, EXTENTS_SIZE, + &bytesReturned, NULL)) { + if (((VOLUME_DISK_EXTENTS *)extents)-> + NumberOfDiskExtents == 1) { + DISK_EXTENT *extent = &(( + VOLUME_DISK_EXTENTS *) + extents)->Extents[0]; if ((extent->DiskNumber==drive_id) && - (extent->StartingOffset.QuadPart==part_offset) && - (extent->ExtentLength.QuadPart==part_length)) { - /* Eureka! (Archimedes, 287 BC, "I have found it!") */ - fnFindVolumeClose(vol_find_handle); + (extent->StartingOffset. + QuadPart==part_offset) + && (extent-> + ExtentLength.QuadPart + == part_length)) { + /* + * Eureka! (Archimedes, 287 BC, + * "I have found it!") + */ + fnFindVolumeClose( + vol_find_handle); return handle; } } @@ -645,20 +650,19 @@ static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id, Dputs("win32_open_volume_for_partition: getExtents " "Failed!" ); } while (fnFindNextVolume(vol_find_handle, vol_name, MAX_PATH)); - - /* end of iteration through volumes */ + /* End of iteration through volumes. */ Dprintf("win32_open_volume_for_partition: Closing.\n"); fnFindVolumeClose(vol_find_handle); - return INVALID_HANDLE_VALUE; } /** - * ntfs_device_win32_find_partition - locates partition details by id. - * @handle HANDLE to the PhysicalDrive - * @partition_id The partition number to locate. - * @part_offset Pointer to where to put the offset to the partition. - * @part_length Pointer to where to put the length of the partition. + * ntfs_device_win32_find_partition - locates partition details by id + * @handle HANDLE to the PhysicalDrive + * @partition_id the partition number to locate + * @part_offset pointer to where to put the offset to the partition + * @part_length pointer to where to put the length of the partition + * @hidden_sectors pointer to where to put the hidden sectors * * This function requires an open PhysicalDrive handle and a partition_id. * If a partition with the required id is found on the supplied device, @@ -667,12 +671,13 @@ static HANDLE ntfs_device_win32_open_volume_for_partition(unsigned int drive_id, * Return TRUE if found, and sets the output parameters. * FALSE if not. */ -static BOOL ntfs_device_win32_find_partition(HANDLE handle,DWORD partition_id, +static BOOL ntfs_device_win32_find_partition(HANDLE handle, DWORD partition_id, s64 *part_offset, s64 *part_length, int *hidden_sectors) { - char buf[sizeof(DRIVE_LAYOUT_INFORMATION)+9*sizeof(PARTITION_INFORMATION)]; DRIVE_LAYOUT_INFORMATION *drive_layout; DWORD i; + char buf[sizeof(DRIVE_LAYOUT_INFORMATION) + + 9 * sizeof(PARTITION_INFORMATION)]; if (!DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0, &buf, sizeof(buf), &i, NULL)) { @@ -680,73 +685,66 @@ static BOOL ntfs_device_win32_find_partition(HANDLE handle,DWORD partition_id, Dputs("Error: GetDriveLayout failed."); return FALSE; } - drive_layout = (DRIVE_LAYOUT_INFORMATION *)buf; for (i = 0; i < drive_layout->PartitionCount; i++) { - if (drive_layout->PartitionEntry[i].PartitionNumber == partition_id) { - *part_offset = - drive_layout->PartitionEntry[i].StartingOffset.QuadPart; - *part_length = - drive_layout->PartitionEntry[i].PartitionLength.QuadPart; - *hidden_sectors = drive_layout->PartitionEntry[i].HiddenSectors; + if (drive_layout->PartitionEntry[i].PartitionNumber == + partition_id) { + *part_offset = drive_layout->PartitionEntry[i]. + StartingOffset.QuadPart; + *part_length = drive_layout->PartitionEntry[i]. + PartitionLength.QuadPart; + *hidden_sectors = drive_layout->PartitionEntry[i]. + HiddenSectors; return TRUE; } } - return FALSE; } /** - * ntfs_device_win32_open_partition - Open a partition via win32 API - * @dev: NTFS_DEVICE to open - * @fd: Win32 file device to return - * @flags: Unix open status flags. + * ntfs_device_win32_open_partition - open a partition via win32 API + * @drive_id: drive to open + * @partition_id: partition to open + * @fd: win32 file device to return + * @flags: unix open status flags * * Return 0 if o.k. - * -1 if not + * -1 if not, and errno set. * * When fails, fd contents may have not been preserved. */ static int ntfs_device_win32_open_partition(int drive_id, unsigned int partition_id, win32_fd *fd, int flags) { - char drive_name[MAX_PATH]; - HANDLE handle; - int err; s64 part_start, part_length; - int hidden_sectors; + HANDLE handle; + int err, hidden_sectors; + char drive_name[MAX_PATH]; sprintf(drive_name, "\\\\.\\PhysicalDrive%d", drive_id); - /* Open the entire device without locking, ask questions later */ - if ((err = ntfs_device_win32_simple_open_file(drive_name, &handle, flags, - FALSE))) { - /* error */ + if ((err = ntfs_device_win32_simple_open_file(drive_name, &handle, + flags, FALSE))) { + /* error */ return err; } - if (ntfs_device_win32_find_partition(handle, partition_id, &part_start, &part_length, &hidden_sectors)) { s64 tmp; HANDLE vol_handle = ntfs_device_win32_open_volume_for_partition( drive_id, part_start, part_length, flags); - - /* store the drive geometry */ + /* Store the drive geometry. */ ntfs_device_win32_getgeo(handle, fd); - fd->handle = handle; - fd->real_pos = 0; - fd->real_ofs = 0; + fd->pos = 0; fd->part_start = part_start; fd->part_length = part_length; fd->part_hidden_sectors = hidden_sectors; - tmp = ntfs_device_win32_getntfssize(vol_handle); if (tmp > 0) fd->geo_size = tmp; else fd->geo_size = fd->part_length; - if (vol_handle != INVALID_HANDLE_VALUE) { if (((flags & O_RDWR) == O_RDWR) && ntfs_device_win32_lock(vol_handle)) { @@ -757,9 +755,10 @@ static int ntfs_device_win32_open_partition(int drive_id, fd->vol_handle = vol_handle; } else { if ((flags & O_RDWR) == O_RDWR) { - /* access if read-write, no volume found */ - Dputs("Partitions containing Spanned/Mirrored volumes are " - "not supported in R/W status yet"); + /* Access if read-write, no volume found. */ + Dputs("Partitions containing Spanned/Mirrored " + "volumes are not supported in " + "R/W status yet"); CloseHandle(handle); errno = ENOTSUP; return -1; @@ -768,7 +767,8 @@ static int ntfs_device_win32_open_partition(int drive_id, } return 0; } else { - Dprintf("partition %u not found on drive %d\n", partition_id, drive_id); + Dprintf("Partition %u not found on drive %d.\n", partition_id, + drive_id); CloseHandle(handle); errno = ENODEV; return -1; @@ -776,11 +776,11 @@ static int ntfs_device_win32_open_partition(int drive_id, } /** - * ntfs_device_win32_open - Open a device - * @dev: A pointer to the NTFS_DEVICE to open - * dev->d_name must hold the device name, the rest is ignored. - * @flags: Unix open status flags. + * ntfs_device_win32_open - open a device + * @dev: a pointer to the NTFS_DEVICE to open + * @flags: unix open status flags * + * @dev->d_name must hold the device name, the rest is ignored. * Supported flags are O_RDONLY, O_WRONLY and O_RDWR. * * If name is in format "(hd[0-9],[0-9])" then open a partition. @@ -836,77 +836,37 @@ static int ntfs_device_win32_open(struct ntfs_device *dev, int flags) } /** - * ntfs_device_win32_seek - Change current file position. - * @handle: Pointer the file HANDLE obtained via open. - * @pos: Offset in the file relative to file start. + * ntfs_device_win32_seek - change current logical file position + * @dev: ntfs device obtained via ->open + * @offset: required offset from the whence anchor + * @whence: whence anchor specifying what @offset is relative to * - * Return Succeed: The new position in the file - * Fail: -1 and errno set. - */ -static s64 ntfs_device_win32_abs_seek(struct win32_fd *fd, s64 pos) -{ - LARGE_INTEGER li; - HANDLE handle; - - if (pos < 0 || pos > fd->part_length) { - Dputs("Error: Seeking outsize seekable area."); - errno = EINVAL; - return -1; - } - li.QuadPart = pos; - if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) { - Dputs("Seeking via vol_handle"); - handle = fd->vol_handle; - } else { - Dputs("Seeking via handle"); - handle = fd->handle; - li.QuadPart += fd->part_start; - } - /* If the address is not alligned, we round down to nearest sector. */ - li.QuadPart &= ~(s64)(NTFS_BLOCK_SIZE - 1); - /* Only seek if we are not there already. */ - if (li.QuadPart != fd->real_pos) { - if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) { - errno = ntfs_w32error_to_errno(GetLastError()); - Dputs("Error: SetFilePointer failed."); - return -1; - } - fd->real_pos = li.QuadPart; - } - fd->real_ofs = pos & (NTFS_BLOCK_SIZE - 1); - return pos; -} - -/** - * ntfs_device_win32_seek - Change current file position. - * @handle: Pointer the file HANDLE obtained via open. - * @offset: Required offset from the whence anchor. - * @whence: May be one of the following: - * SEEK_SET Offset is relative to file start. - * SEEK_CUR Offset is relative to current position. - * SEEK_END Offset is relative to end of file. + * Return the new position on the volume on success and -1 on error with errno + * set to the error code. * - * Return 0 if o.k. - * -1 if not and errno set. + * @whence may be one of the following: + * SEEK_SET - Offset is relative to file start. + * SEEK_CUR - Offset is relative to current position. + * SEEK_END - Offset is relative to end of file. */ static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset, int whence) { s64 abs_ofs; - struct win32_fd *fd = (win32_fd *)dev->d_private; + win32_fd *fd = (win32_fd *)dev->d_private; - Dprintf("win32_seek(%lld=0x%llx,%d)\n", offset, offset, whence); + Dprintf("win32_seek(): offset = 0x%llx, whence = %d\n", offset, whence); switch (whence) { case SEEK_SET: abs_ofs = offset; break; case SEEK_CUR: - abs_ofs = fd->real_pos + fd->real_ofs + offset; + abs_ofs = fd->pos + offset; break; case SEEK_END: - /* end of partition != end of disk */ + /* End of partition != end of disk. */ if (fd->part_length == -1) { - Dputs("win32_seek: position relative to end " + Dputs("win32_seek(): Error: Position relative to end " "of disk not implemented."); errno = ENOTSUP; return -1; @@ -914,75 +874,114 @@ static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset, abs_ofs = fd->part_length + offset; break; default: - Dprintf("win32_seek() wrong mode %d.\n", whence); + Dprintf("win32_seek(): Error: Wrong mode %d.\n", whence); errno = EINVAL; return -1; } - return ntfs_device_win32_abs_seek(fd, abs_ofs); + if (abs_ofs < 0 || abs_ofs > fd->part_length) { + Dputs("Error: Seeking outsize seekable area."); + errno = EINVAL; + return -1; + } + fd->pos = abs_ofs; + return abs_ofs; } /** - * ntfs_device_win32_read_simple - Positioned simple read. - * @fd: The private data of the NTFS_DEVICE. - * @buf: A pointer to where to put the contents. - * @count: How many bytes should be read. + * ntfs_device_win32_pio - positioned low level i/o + * @fd: win32 device descriptor obtained via ->open + * @pos: at which position to do i/o from/to + * @count: how many bytes should be transfered + * @b: source/destination buffer + * @write: TRUE if write transfer and FALSE if read transfer * - * On success returns the number of bytes read (can be < @count) and on error - * returns (DWORD)-1 and errno set. + * On success returns the number of bytes transfered (can be < @count) and on + * error returns -1 and errno set. Transfer starts from position @pos on @fd. * * Notes: - * - Reads from fd->real_pos NOT considering fd->real_ofs. - * - Does NOT advance fd->real_pos and fd->real_ofs. - * - @buf must be aligned to page boundary. - * - @count must be a multiple of the sector size. + * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE. * - When dealing with volumes, a single call must not span both volume * and disk extents. + * - Does not use/set @fd->pos. */ -static DWORD ntfs_device_win32_read_simple(win32_fd *fd, void *buf, DWORD count) +static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos, + const s64 count, void *b, const BOOL write) { + LARGE_INTEGER li; HANDLE handle; - DWORD br; + DWORD bt; + BOOL res; - if (fd->real_pos + fd->real_ofs < fd->geo_size && - fd->vol_handle != INVALID_HANDLE_VALUE) { - Dputs("Reading via vol_handle."); + Dprintf("win32_pio(): pos = 0x%llx, count = 0x%llx, direction = %s", + (long long)pos, (long long)count, write ? "write" : + "read"); + li.QuadPart = pos; + if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) { + Dputs("Transfering via vol_handle."); handle = fd->vol_handle; } else { - Dputs("Reading via handle."); + Dputs("Transfering via handle."); handle = fd->handle; + li.QuadPart += fd->part_start; } - if (!ReadFile(handle, buf, count, &br, NULL)) { + if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) { errno = ntfs_w32error_to_errno(GetLastError()); - Dputs("Error: ReadFile() failed."); - return (DWORD)-1; + Dputs("Error: SetFilePointer failed."); + return -1; } - /* - * NOTE: The caller *MUST* update fd->real_pos and fd->real_ofs!!! - * Alternatively, caller can call ntfs_device_win32_{,abs_}seek(). - */ - return br; + 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()); + Dprintf("Error: %sFile() failed.\n", write ? "Write" : "Read"); + return -1; + } + return bt; } /** - * ntfs_device_win32_read - Read 'count' bytes from 'dev' into 'buf'. - * @dev: An NTFS_DEVICE obtained via the open command. - * @buf: A pointer to where to put the contents. - * @count: How many bytes should be read. + * ntfs_device_win32_pread_simple - positioned simple read + * @fd: win32 device descriptor obtained via ->open + * @pos: at which position to read from + * @count: how many bytes should be read + * @b: a pointer to where to put the contents * - * On success returns the amount of bytes actually read. - * On fail returns -1 and sets errno. + * On success returns the number of bytes read (can be < @count) and on error + * returns -1 and errno set. Read starts from position @pos. + * + * Notes: + * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_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_read(struct ntfs_device *dev, void *buf, s64 count) +static inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos, + const s64 count, void *b) { - s64 pos, to_read; - struct win32_fd *fd = (win32_fd *)dev->d_private; - BYTE *alignedbuffer; - int old_ofs; - DWORD i, br = 0; + return ntfs_device_win32_pio(fd, pos, count, b, FALSE); +} - old_ofs = fd->real_ofs; - pos = fd->real_pos + old_ofs; - to_read = (old_ofs + count + NTFS_BLOCK_SIZE - 1) & +/** + * ntfs_device_win32_read - read bytes from an ntfs device + * @dev: ntfs device obtained via ->open + * @b: pointer to where to put the contents + * @count: how many bytes should be read + * + * On success returns the number of bytes actually read (can be < @count). + * On error returns -1 with errno set. + */ +static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *b, s64 count) +{ + s64 old_pos, to_read, i, br = 0; + win32_fd *fd = (win32_fd *)dev->d_private; + BYTE *alignedbuffer; + 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); /* Impose maximum of 2GB to be on the safe side. */ if (to_read > 0x80000000) { @@ -990,12 +989,13 @@ static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *buf, s64 count) to_read = 0x80000000; count = to_read - delta; } - Dprintf("win32_read(fd=%p,b=%p,count=0x%llx)->(%llx+%x:%llx)\n", fd, - buf, count, (long long)fd->real_pos, old_ofs, + Dprintf("win32_read(): fd = %p, b = %p, count = 0x%llx, pos = 0x%llx, " + "ofs = %i, to_read = 0x%llx\n", fd, b, + (long long)count, (long long)old_pos, ofs, (long long)to_read); - if (!((unsigned long)buf & (NTFS_BLOCK_SIZE - 1)) && !old_ofs && + if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs && !(count & (NTFS_BLOCK_SIZE - 1))) - alignedbuffer = buf; + alignedbuffer = b; else { alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT, PAGE_READWRITE); @@ -1005,70 +1005,69 @@ static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *buf, s64 count) return -1; } } - if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) { - s64 vol_to_read = fd->geo_size - pos; + if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) { + s64 vol_to_read = fd->geo_size - old_pos; if (count > vol_to_read) { - br = ntfs_device_win32_read_simple(fd, - alignedbuffer, old_ofs + vol_to_read); - if (br == (DWORD)-1) + br = ntfs_device_win32_pread_simple(fd, + old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1), + ofs + vol_to_read, alignedbuffer); + if (br == -1) goto read_error; to_read -= br; - if (br < old_ofs) { + if (br < ofs) { br = 0; goto read_partial; } - br -= old_ofs; - pos += br; - fd->real_pos = pos & ~(s64)(NTFS_BLOCK_SIZE - 1); - fd->real_ofs = pos & (NTFS_BLOCK_SIZE - 1); + br -= ofs; + fd->pos += br; + ofs = fd->pos & (NTFS_BLOCK_SIZE - 1); if (br != vol_to_read) goto read_partial; } } - if ((i = ntfs_device_win32_read_simple(fd, alignedbuffer + br, - to_read)) == (DWORD)-1) { + i = ntfs_device_win32_pread_simple(fd, + fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_read, + alignedbuffer + br); + if (i == -1) { if (br) goto read_partial; goto read_error; } - if (i < fd->real_ofs) + if (i < ofs) goto read_partial; - i -= fd->real_ofs; + i -= ofs; br += i; if (br > count) br = count; - pos += br; - fd->real_pos = pos & ~(s64)(NTFS_BLOCK_SIZE - 1); - fd->real_ofs = pos & (NTFS_BLOCK_SIZE - 1); + fd->pos = old_pos + br; read_partial: - if (alignedbuffer != buf) { - memcpy((void*)buf, alignedbuffer + old_ofs, br); + if (alignedbuffer != b) { + memcpy((void*)b, alignedbuffer + old_ofs, br); VirtualFree(alignedbuffer, 0, MEM_RELEASE); } return br; read_error: - if (alignedbuffer != buf) + if (alignedbuffer != b) VirtualFree(alignedbuffer, 0, MEM_RELEASE); return -1; } /** - * ntfs_device_win32_close - Close an open NTFS_DEVICE and - * free internal buffers. - * @dev: An NTFS_DEVICE obtained via the open command. + * ntfs_device_win32_close - close an open ntfs deivce + * @dev: ntfs device obtained via ->open * * Return 0 if o.k. - * -errno if not, in this case handle is trashed. + * -1 if not, and errno set. Note if error fd->vol_handle is trashed. */ static int ntfs_device_win32_close(struct ntfs_device *dev) { - struct win32_fd *fd = (win32_fd *)dev->d_private; + win32_fd *fd = (win32_fd *)dev->d_private; BOOL rvl; Dprintf("win32_close(%p)\n", dev); if (!NDevOpen(dev)) { errno = EBADF; - return -errno; + return -1; } if (fd->vol_handle != INVALID_HANDLE_VALUE) { if (!NDevReadOnly(dev)) { @@ -1076,7 +1075,7 @@ static int ntfs_device_win32_close(struct ntfs_device *dev) ntfs_device_win32_unlock(fd->vol_handle); } if (!CloseHandle(fd->vol_handle)) - Dputs("Error: CloseHandle failed for volume."); + Dputs("Error: CloseHandle() failed for volume."); } rvl = CloseHandle(fd->handle); free(fd); @@ -1089,14 +1088,14 @@ static int ntfs_device_win32_close(struct ntfs_device *dev) } /** - * ntfs_device_win32_sync - Flush write buffers to disk. - * @dev: An NTFS_DEVICE obtained via the open command. + * ntfs_device_win32_sync - flush write buffers to disk + * @dev: ntfs device obtained via ->open * * Return 0 if o.k. - * -1 if not and errno set. + * -1 if not, and errno set. * * Note: Volume syncing works differently in windows. - * Disk can't be synced in windows. + * Disk cannot be synced in windows. */ static int ntfs_device_win32_sync(struct ntfs_device *dev) { @@ -1104,7 +1103,7 @@ static int ntfs_device_win32_sync(struct ntfs_device *dev) BOOL to_clear = TRUE; if (!NDevReadOnly(dev) && NDevDirty(dev)) { - struct win32_fd *fd = (win32_fd *)dev->d_private; + win32_fd *fd = (win32_fd *)dev->d_private; if ((fd->vol_handle != INVALID_HANDLE_VALUE) && !FlushFileBuffers(fd->vol_handle)) { @@ -1127,68 +1126,58 @@ static int ntfs_device_win32_sync(struct ntfs_device *dev) } /** - * ntfs_device_win32_write_simple - Write 'count' bytes from 'buf' into 'dev'. - * @dev: An NTFS_DEVICE obtained via the open command. - * @buf: A pointer to the contents. - * @count: How many bytes should be written. + * ntfs_device_win32_pwrite_simple - positioned simple write + * @fd: win32 device descriptor obtained via ->open + * @pos: at which position to write to + * @count: how many bytes should be written + * @b: a pointer to the data to write * - * On success returns the amount of bytes actually written. - * On success returns the number of bytes written and on error returns - * (DWORD)-1 and errno set. + * On success returns the number of bytes written and on error returns -1 and + * errno set. Write starts from position @pos. * * Notes: - * - Writes to fd->real_pos NOT considering fd->real_ofs. - * - Does NOT advance fd->real_pos and fd->real_ofs. - * - @buf must be aligned to page boundary. - * - @count must be a multiple of the sector size. + * - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE. * - When dealing with volumes, a single call must not span both volume * and disk extents. + * - Does not use/set @fd->pos. */ -static DWORD ntfs_device_win32_write_simple(win32_fd *fd, const void *buf, - DWORD count) +static inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos, + const s64 count, const void *b) { - HANDLE handle; - DWORD bw; - - if (fd->real_pos + fd->real_ofs < fd->geo_size && - fd->vol_handle != INVALID_HANDLE_VALUE) { - Dputs("Writing via vol_handle"); - handle = fd->vol_handle; - } else { - Dputs("Writing via handle"); - handle = fd->handle; - } - if (!WriteFile(handle, buf, count, &bw, NULL)) { - errno = ntfs_w32error_to_errno(GetLastError()); - Dputs("Error: WriteFile failed."); - return (DWORD)-1; - } - /* - * NOTE: The caller *MUST* update fd->real_pos and fd->real_ofs!!! - * Alternatively, caller can call ntfs_device_win32_{,abs_}seek(). - */ - return bw; + return ntfs_device_win32_pio(fd, pos, count, (void *)b, TRUE); } /** - * ntfs_device_win32_write - Write 'count' bytes from 'buf' into 'dev'. - * @dev: An NTFS_DEVICE obtained via the open command. - * @buf: A pointer to the contents. - * @count: How many bytes should be written. + * ntfs_device_win32_write - write bytes to an ntfs device + * @dev: ntfs device obtained via ->open + * @b: pointer to the data to write + * @count: how many bytes should be written * - * On success returns the amount of bytes actually written. - * On fail returns -1 and errno set. + * On success returns the number of bytes actually written. + * On error returns -1 with errno set. */ -static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *buf, +static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *b, s64 count) { - s64 pos, to_write; + s64 old_pos, to_write, i, bw = 0; win32_fd *fd = (win32_fd *)dev->d_private; BYTE *alignedbuffer; - int old_ofs; - DWORD i, bw = 0; + int old_ofs, ofs; - Dprintf("win32_write: Writing %lld bytes\n", (long long)count); + 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); + /* Impose maximum of 2GB to be on the safe side. */ + if (to_write > 0x80000000) { + int delta = to_write - count; + to_write = 0x80000000; + count = to_write - delta; + } + Dprintf("win32_write(): fd = %p, b = %p, count = 0x%llx, " + "pos = 0x%llx, ofs = %i, to_write = 0x%llx\n", fd, b, + (long long)count, (long long)old_pos, ofs, + (long long)to_write); if (NDevReadOnly(dev)) { Dputs("win32_write: Device R/O, exiting."); errno = EROFS; @@ -1197,20 +1186,12 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *buf, if (!count) return 0; NDevSetDirty(dev); - old_ofs = fd->real_ofs; - pos = fd->real_pos + old_ofs; - to_write = (old_ofs + count + NTFS_BLOCK_SIZE - 1) & - ~(s64)(NTFS_BLOCK_SIZE - 1); - /* Impose maximum of 2GB to be on the safe side. */ - if (to_write > 0x80000000) { - int delta = to_write - count; - to_write = 0x80000000; - count = to_write - delta; - } - if (!((unsigned long)buf & (NTFS_BLOCK_SIZE - 1)) && !old_ofs && + if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs && !(count & (NTFS_BLOCK_SIZE - 1))) - alignedbuffer = buf; + alignedbuffer = (BYTE *)b; else { + s64 end; + alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_write, MEM_COMMIT, PAGE_READWRITE); if (!alignedbuffer) { @@ -1219,80 +1200,75 @@ static s64 ntfs_device_win32_write(struct ntfs_device *dev, const void *buf, return -1; } /* Read first sector if start of write not sector aligned. */ - if (old_ofs) { - i = ntfs_device_win32_read_simple(fd, alignedbuffer, - NTFS_BLOCK_SIZE); + 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) { if (i >= 0) errno = EIO; goto write_error; } } - /* Read last sector if end of write not sector aligned. */ - if ((pos + count) & (NTFS_BLOCK_SIZE - 1)) { - if (ntfs_device_win32_abs_seek(fd, (pos + count) & - ~(NTFS_BLOCK_SIZE - 1)) == -1) - goto write_error; - i = ntfs_device_win32_read_simple(fd, alignedbuffer + - to_write - NTFS_BLOCK_SIZE, - NTFS_BLOCK_SIZE); + /* + * Read last sector if end of write not sector aligned and last + * sector is either not the same as the first sector or it is + * the same as the first sector but this has not been read in + * 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)) { + 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) { - if (ntfs_device_win32_abs_seek(fd, pos) == -1) { - fd->real_pos = pos & ~(s64) - (NTFS_BLOCK_SIZE - 1); - fd->real_ofs = old_ofs; - } if (i >= 0) errno = EIO; goto write_error; } } - /* Move the file position back so we can start writing. */ - if (ntfs_device_win32_abs_seek(fd, pos) == -1) { - fd->real_pos = pos & ~(s64)(NTFS_BLOCK_SIZE - 1); - fd->real_ofs = old_ofs; - goto write_error; - } /* Copy the data to be written into @alignedbuffer. */ - memcpy(alignedbuffer + old_ofs, buf, count); + memcpy(alignedbuffer + ofs, b, count); } - if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) { - s64 vol_to_write = fd->geo_size - pos; - if (count > vol_to_read) { - bw = ntfs_device_win32_write_simple(fd, alignedbuffer, - old_ofs + vol_to_write); - if (bw == (DWORD)-1) + if (fd->vol_handle != INVALID_HANDLE_VALUE && old_pos < fd->geo_size) { + 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), + ofs + vol_to_write, alignedbuffer); + if (bw == -1) goto write_error; to_write -= bw; - if (bw < old_ofs) { + if (bw < ofs) { bw = 0; goto write_partial; } - bw -= old_ofs; - pos += bw; - fd->real_pos = pos & ~(s64)(NTFS_BLOCK_SIZE - 1); - fd->real_ofs = pos & (NTFS_BLOCK_SIZE - 1); + bw -= ofs; + fd->pos += bw; + ofs = fd->pos & (NTFS_BLOCK_SIZE - 1); if (bw != vol_to_write) goto write_partial; } } - if ((i = ntfs_device_win32_write_simple(fd, alignedbuffer + bw, - to_write)) == (DWORD)-1) { + i = ntfs_device_win32_pwrite_simple(fd, + fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_write, + alignedbuffer + bw); + if (i == -1) { if (bw) goto write_partial; goto write_error; } - if (i < fd->real_ofs) + if (i < ofs) goto write_partial; - i -= fd->real_ofs; + i -= ofs; bw += i; if (bw > count) bw = count; - pos += bw; - fd->real_pos = pos & ~(s64)(NTFS_BLOCK_SIZE - 1); - fd->real_ofs = pos & (NTFS_BLOCK_SIZE - 1); + fd->pos = old_pos + bw; write_partial: - if (alignedbuffer != buf) + if (alignedbuffer != b) VirtualFree(alignedbuffer, 0, MEM_RELEASE); return bw; write_error: @@ -1301,63 +1277,57 @@ write_error: } /** - * ntfs_device_win32_stat - Get a Unix-like stat structure for the file. - * @dev: An NTFS_DEVICE obtained via the open command. - * @argp: A pointer to where to put the output. + * ntfs_device_win32_stat - get a unix-like stat structure for an ntfs device + * @dev: ntfs device obtained via ->open + * @buf: pointer to the stat structure to fill * - * Only st_mode & st_size are filled. + * Note: Only st_mode, st_size, and st_blocks are filled. * * Return 0 if o.k. * -1 if not and errno set. in this case handle is trashed. */ static int ntfs_device_win32_stat(struct ntfs_device *dev, struct stat *buf) { - mode_t st_mode; win32_fd *fd = (win32_fd *)dev->d_private; + mode_t st_mode; switch (GetFileType(fd->handle)) { - case FILE_TYPE_CHAR: - st_mode = S_IFCHR; - break; - case FILE_TYPE_DISK: - st_mode = S_IFBLK; - break; - case FILE_TYPE_PIPE: - st_mode = S_IFIFO; - break; - default: - st_mode = 0; + case FILE_TYPE_CHAR: + st_mode = S_IFCHR; + break; + case FILE_TYPE_DISK: + st_mode = S_IFBLK; + break; + case FILE_TYPE_PIPE: + st_mode = S_IFIFO; + break; + default: + st_mode = 0; } - - memset(buf,0,sizeof (struct stat)); + memset(buf, 0, sizeof(struct stat)); buf->st_mode = st_mode; buf->st_size = fd->part_length; if (buf->st_size != -1) buf->st_blocks = buf->st_size >> 9; else buf->st_size = 0; - return 0; } /** - * ntfs_win32_hdio_getgeo - Get drive geometry. - * @dev: An NTFS_DEVICE obtained via the open command. - * @argp: A pointer to where to put the output. + * ntfs_win32_hdio_getgeo - get drive geometry + * @dev: ntfs device obtained via ->open + * @argp: pointer to where to put the output * - * Requires windows NT/2k/XP only - * - * Currently only the 'start' field is filled + * Note: Works on windows NT/2k/XP only. * * Return 0 if o.k. - * -errno if not, in this case handle is trashed. + * -1 if not, and errno set. Note if error fd->handle is trashed. */ static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev, struct hd_geometry *argp) { - win32_fd *fd; - - fd = (win32_fd *)dev->d_private; + win32_fd *fd = (win32_fd *)dev->d_private; argp->heads = fd->geo_heads; argp->sectors = fd->geo_sectors; @@ -1367,33 +1337,30 @@ static __inline__ int ntfs_win32_hdio_getgeo(struct ntfs_device *dev, } /** - * ntfs_win32_blksszget - Get block device sector size. - * @dev: An NTFS_DEVICE obtained via the open command. - * @argp: A pointer to where to put the output. + * ntfs_win32_blksszget - get block device sector size + * @dev: ntfs device obtained via ->open + * @argp: pointer to where to put the output * - * Works on windows NT/2k/XP only + * Note: Works on windows NT/2k/XP only. * * Return 0 if o.k. - * -errno if not, in this case handle is trashed. + * -1 if not, and errno set. Note if error fd->handle is trashed. */ static __inline__ int ntfs_win32_blksszget(struct ntfs_device *dev,int *argp) { - win32_fd *fd; - DISK_GEOMETRY dg; + win32_fd *fd = (win32_fd *)dev->d_private; DWORD bytesReturned; - - fd = (win32_fd *)dev->d_private; + DISK_GEOMETRY dg; if (DeviceIoControl(fd->handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof(DISK_GEOMETRY), &bytesReturned, NULL)) { /* success */ - *argp=dg.BytesPerSector; + *argp = dg.BytesPerSector; return 0; - } else { - errno = ntfs_w32error_to_errno(GetLastError()); - Dputs("Error: GET_DRIVE_GEOMETRY failed."); - return -errno; } + errno = ntfs_w32error_to_errno(GetLastError()); + Dputs("Error: GET_DRIVE_GEOMETRY failed."); + return -1; } static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, @@ -1401,60 +1368,55 @@ static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request, { win32_fd *fd = (win32_fd *)dev->d_private; - Dprintf("win32_ioctl(%d) called.\n",request); - + Dprintf("win32_ioctl(%d) called.\n", request); switch (request) { #if defined(BLKGETSIZE) - case BLKGETSIZE: - Dputs("win32_ioctl: BLKGETSIZE detected."); - if (fd->part_length>=0) { - *(int *)argp = (int)(fd->part_length / 512); - return 0; - } else { - errno = ENOTSUP; - return -ENOTSUP; - } + case BLKGETSIZE: + Dputs("win32_ioctl(): BLKGETSIZE detected."); + if (fd->part_length >= 0) { + *(int *)argp = (int)(fd->part_length / 512); + return 0; + } + errno = ENOTSUP; + return -1; #endif #if defined(BLKGETSIZE64) - case BLKGETSIZE64: - Dputs("win32_ioctl: BLKGETSIZE64 detected."); - if (fd->part_length>=0) { - *(s64 *)argp = fd->part_length; - return 0; - } else { - errno = ENOTSUP; - return -ENOTSUP; - } + case BLKGETSIZE64: + Dputs("win32_ioctl(): BLKGETSIZE64 detected."); + if (fd->part_length >= 0) { + *(s64 *)argp = fd->part_length; + return 0; + } + errno = ENOTSUP; + return -1; #endif #ifdef HDIO_GETGEO - case HDIO_GETGEO: - Dputs("win32_ioctl: HDIO_GETGEO detected."); - return ntfs_win32_hdio_getgeo(dev,(struct hd_geometry *)argp); + case HDIO_GETGEO: + Dputs("win32_ioctl(): HDIO_GETGEO detected."); + return ntfs_win32_hdio_getgeo(dev, (struct hd_geometry *)argp); #endif #ifdef BLKSSZGET - case BLKSSZGET: - Dputs("win32_ioctl: BLKSSZGET detected."); - return ntfs_win32_blksszget(dev,(int *)argp); - break; + case BLKSSZGET: + Dputs("win32_ioctl(): BLKSSZGET detected."); + return ntfs_win32_blksszget(dev, (int *)argp); #endif - default: - Dprintf("win32_ioctl(): unimplemented ioctl %d.\n", - request); - errno = ENOTSUP; - return -1; + default: + Dprintf("win32_ioctl(): unimplemented ioctl %d.\n", request); + errno = ENOTSUP; + return -1; } } -static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *buf, +static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b, s64 count, s64 offset) { - return ntfs_pread(dev, offset, count, buf); + return ntfs_pread(dev, offset, count, b); } -static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *buf, +static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b, s64 count, s64 offset) { - return ntfs_pwrite(dev, offset, count, buf); + return ntfs_pwrite(dev, offset, count, b); } struct ntfs_device_operations ntfs_device_win32_io_ops = {