Major rewrite, in particular seek, read, and write related code.
(Logical change 1.698)edge.strict_endians
parent
032d26b4d4
commit
307659837c
|
@ -4,7 +4,7 @@
|
||||||
* Part of the Linux-NTFS project.
|
* Part of the Linux-NTFS project.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2004 Lode Leroy
|
* Copyright (c) 2003-2004 Lode Leroy
|
||||||
* Copyright (c) 2003-2004 Anton Altaparmakov
|
* Copyright (c) 2003-2005 Anton Altaparmakov
|
||||||
*
|
*
|
||||||
* This program/include file is free software; you can redistribute it and/or
|
* 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
|
* modify it under the terms of the GNU General Public License as published
|
||||||
|
@ -36,8 +36,8 @@
|
||||||
* Cannot use "../include/types.h" since it conflicts with "wintypes.h".
|
* Cannot use "../include/types.h" since it conflicts with "wintypes.h".
|
||||||
* define our own...
|
* define our own...
|
||||||
*/
|
*/
|
||||||
typedef long long int s64;
|
typedef long long s64;
|
||||||
typedef unsigned long int u32;
|
typedef unsigned long u32;
|
||||||
struct stat;
|
struct stat;
|
||||||
struct ntfs_volume;
|
struct ntfs_volume;
|
||||||
typedef struct ntfs_volume ntfs_volume;
|
typedef struct ntfs_volume ntfs_volume;
|
||||||
|
@ -72,7 +72,8 @@ typedef struct win32_fd {
|
||||||
int part_hidden_sectors;
|
int part_hidden_sectors;
|
||||||
s64 part_start;
|
s64 part_start;
|
||||||
s64 part_length;
|
s64 part_length;
|
||||||
LARGE_INTEGER current_pos;
|
s64 real_pos;
|
||||||
|
int real_ofs;
|
||||||
s64 geo_size, geo_cylinders;
|
s64 geo_size, geo_cylinders;
|
||||||
DWORD geo_sectors, geo_heads;
|
DWORD geo_sectors, geo_heads;
|
||||||
HANDLE vol_handle;
|
HANDLE vol_handle;
|
||||||
|
@ -366,7 +367,7 @@ static s64 ntfs_device_win32_getntfssize(HANDLE handle)
|
||||||
* In Windows XP+: fills the members: size, sectors, cylinders and heads.
|
* In Windows XP+: fills the members: size, sectors, cylinders and heads.
|
||||||
*
|
*
|
||||||
* Note: in pre XP, this requires write permission, even though nothing is
|
* Note: in pre XP, this requires write permission, even though nothing is
|
||||||
* actuallt written.
|
* actually written.
|
||||||
*
|
*
|
||||||
* if fails, set sectors, cylinders and heads to -1.
|
* if fails, set sectors, cylinders and heads to -1.
|
||||||
*/
|
*/
|
||||||
|
@ -478,7 +479,8 @@ static __inline__ int ntfs_device_win32_open_file(char *filename, win32_fd *fd,
|
||||||
fd->handle = handle;
|
fd->handle = handle;
|
||||||
fd->part_start = 0;
|
fd->part_start = 0;
|
||||||
fd->part_length = ntfs_device_win32_getsize(handle);
|
fd->part_length = ntfs_device_win32_getsize(handle);
|
||||||
fd->current_pos.QuadPart = 0;
|
fd->real_pos = 0;
|
||||||
|
fd->real_ofs = 0;
|
||||||
fd->part_hidden_sectors = -1;
|
fd->part_hidden_sectors = -1;
|
||||||
fd->geo_size = -1; /* used as a marker that this is a file */
|
fd->geo_size = -1; /* used as a marker that this is a file */
|
||||||
fd->vol_handle = INVALID_HANDLE_VALUE;
|
fd->vol_handle = INVALID_HANDLE_VALUE;
|
||||||
|
@ -520,7 +522,8 @@ static __inline__ int ntfs_device_win32_open_drive(int drive_id, win32_fd *fd,
|
||||||
fd->handle = handle;
|
fd->handle = handle;
|
||||||
fd->part_start = 0;
|
fd->part_start = 0;
|
||||||
fd->part_length = fd->geo_size;
|
fd->part_length = fd->geo_size;
|
||||||
fd->current_pos.QuadPart = 0;
|
fd->real_pos = 0;
|
||||||
|
fd->real_ofs = 0;
|
||||||
fd->part_hidden_sectors = -1;
|
fd->part_hidden_sectors = -1;
|
||||||
fd->vol_handle = INVALID_HANDLE_VALUE;
|
fd->vol_handle = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
@ -699,7 +702,8 @@ static int ntfs_device_win32_open_partition(int drive_id,
|
||||||
ntfs_device_win32_getgeo(handle, fd);
|
ntfs_device_win32_getgeo(handle, fd);
|
||||||
|
|
||||||
fd->handle = handle;
|
fd->handle = handle;
|
||||||
fd->current_pos.QuadPart = 0;
|
fd->real_pos = 0;
|
||||||
|
fd->real_ofs = 0;
|
||||||
fd->part_start = part_start;
|
fd->part_start = part_start;
|
||||||
fd->part_length = part_length;
|
fd->part_length = part_length;
|
||||||
fd->part_hidden_sectors = hidden_sectors;
|
fd->part_hidden_sectors = hidden_sectors;
|
||||||
|
@ -814,40 +818,38 @@ static int ntfs_device_win32_open(struct ntfs_device *dev, int flags)
|
||||||
* Return Succeed: The new position in the file
|
* Return Succeed: The new position in the file
|
||||||
* Fail: -1 and errno set.
|
* Fail: -1 and errno set.
|
||||||
*/
|
*/
|
||||||
static s64 ntfs_device_win32_abs_seek(struct win32_fd *fd, LARGE_INTEGER pos)
|
static s64 ntfs_device_win32_abs_seek(struct win32_fd *fd, s64 pos)
|
||||||
{
|
{
|
||||||
if ((pos.QuadPart < 0) || (pos.QuadPart > fd->part_length)) {
|
LARGE_INTEGER li;
|
||||||
|
HANDLE handle;
|
||||||
|
|
||||||
|
if (pos < 0 || pos > fd->part_length) {
|
||||||
Dputs("Error: Seeking outsize seekable area.");
|
Dputs("Error: Seeking outsize seekable area.");
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
li.QuadPart = pos;
|
||||||
if (!(pos.QuadPart & 0x1FF)) {
|
if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) {
|
||||||
LARGE_INTEGER pos2;
|
|
||||||
HANDLE handle;
|
|
||||||
|
|
||||||
if ((fd->vol_handle != INVALID_HANDLE_VALUE) &&
|
|
||||||
(pos.QuadPart < fd->geo_size)) {
|
|
||||||
Dputs("Seeking via vol_handle");
|
Dputs("Seeking via vol_handle");
|
||||||
handle = fd->vol_handle;
|
handle = fd->vol_handle;
|
||||||
pos2.QuadPart = pos.QuadPart;
|
|
||||||
} else {
|
} else {
|
||||||
Dputs("Seeking via handle");
|
Dputs("Seeking via handle");
|
||||||
handle = fd->handle;
|
handle = fd->handle;
|
||||||
pos2.QuadPart = pos.QuadPart + fd->part_start;
|
li.QuadPart += fd->part_start;
|
||||||
}
|
}
|
||||||
if (!SetFilePointerEx(handle, pos2, NULL, FILE_BEGIN)) {
|
/* 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 (!SetFilePointerEx(handle, li, NULL, FILE_BEGIN)) {
|
||||||
errno = ntfs_w32error_to_errno(GetLastError());
|
errno = ntfs_w32error_to_errno(GetLastError());
|
||||||
Dputs("Error: SetFilePointer failed.");
|
Dputs("Error: SetFilePointer failed.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
fd->real_pos = li.QuadPart;
|
||||||
}
|
}
|
||||||
|
fd->real_ofs = pos & (NTFS_BLOCK_SIZE - 1);
|
||||||
/* Notice: If the address is not alligned, we leave it for the
|
return pos;
|
||||||
read/write operation. */
|
|
||||||
fd->current_pos.QuadPart = pos.QuadPart;
|
|
||||||
|
|
||||||
return pos.QuadPart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -865,17 +867,16 @@ static s64 ntfs_device_win32_abs_seek(struct win32_fd *fd, LARGE_INTEGER pos)
|
||||||
static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset,
|
static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset,
|
||||||
int whence)
|
int whence)
|
||||||
{
|
{
|
||||||
LARGE_INTEGER abs_offset;
|
s64 abs_ofs;
|
||||||
struct win32_fd *fd = (win32_fd *)dev->d_private;
|
struct win32_fd *fd = (win32_fd *)dev->d_private;
|
||||||
|
|
||||||
Dprintf("win32_seek(%lld=0x%llx,%d)\n", offset, offset, whence);
|
Dprintf("win32_seek(%lld=0x%llx,%d)\n", offset, offset, whence);
|
||||||
|
|
||||||
switch (whence) {
|
switch (whence) {
|
||||||
case SEEK_SET:
|
case SEEK_SET:
|
||||||
abs_offset.QuadPart = offset;
|
abs_ofs = offset;
|
||||||
break;
|
break;
|
||||||
case SEEK_CUR:
|
case SEEK_CUR:
|
||||||
abs_offset.QuadPart = fd->current_pos.QuadPart + offset;
|
abs_ofs = fd->real_pos + fd->real_ofs + offset;
|
||||||
break;
|
break;
|
||||||
case SEEK_END:
|
case SEEK_END:
|
||||||
/* end of partition != end of disk */
|
/* end of partition != end of disk */
|
||||||
|
@ -885,64 +886,56 @@ static s64 ntfs_device_win32_seek(struct ntfs_device *dev, s64 offset,
|
||||||
errno = ENOTSUP;
|
errno = ENOTSUP;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
abs_offset.QuadPart = fd->part_length + offset;
|
abs_ofs = fd->part_length + offset;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Dprintf("win32_seek() wrong mode %d.\n", whence);
|
Dprintf("win32_seek() wrong mode %d.\n", whence);
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
return ntfs_device_win32_abs_seek(fd, abs_ofs);
|
||||||
return ntfs_device_win32_abs_seek(fd, abs_offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_device_win32_read_simple - Positioned simple read.
|
* ntfs_device_win32_read_simple - Positioned simple read.
|
||||||
* @fd: The private data of the NTFS_DEVICE.
|
* @fd: The private data of the NTFS_DEVICE.
|
||||||
* @pos: Absolute offset in the file.
|
|
||||||
* @buf: A pointer to where to put the contents.
|
* @buf: A pointer to where to put the contents.
|
||||||
* @count: How many bytes should be read.
|
* @count: How many bytes should be read.
|
||||||
*
|
*
|
||||||
* On success returns the number of bytes read (could be <count)
|
* On success returns the number of bytes read (can be < @count) and on error
|
||||||
* otherwise ((DWORD)-1) with errno.
|
* returns (DWORD)-1 and errno set.
|
||||||
*
|
*
|
||||||
* Note:
|
* Notes:
|
||||||
* As count must be a multiple of the sector size, ((DWORD)-1) never
|
* - Reads from fd->real_pos NOT considering fd->real_ofs.
|
||||||
* successfully occur.
|
* - Does NOT advance fd->real_pos and fd->real_ofs.
|
||||||
*
|
* - @buf must be aligned to page boundary.
|
||||||
* Limitations:
|
* - @count must be a multiple of the sector size.
|
||||||
* buf must be aligned to page boundery
|
* - When dealing with volumes, a single call must not span both volume
|
||||||
* pos & count must be aligned to sector bounderies.
|
|
||||||
* When dealing with volumes, a single call must not span both volume
|
|
||||||
* and disk extents.
|
* and disk extents.
|
||||||
*/
|
*/
|
||||||
static DWORD ntfs_device_win32_read_simple(win32_fd *fd, void *buf,
|
static DWORD ntfs_device_win32_read_simple(win32_fd *fd, void *buf, DWORD count)
|
||||||
DWORD count)
|
|
||||||
{
|
{
|
||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
DWORD rvl, i;
|
DWORD br;
|
||||||
|
|
||||||
if ((fd->geo_size > fd->current_pos.QuadPart) &&
|
if (fd->real_pos + fd->real_ofs < fd->geo_size &&
|
||||||
(fd->vol_handle != INVALID_HANDLE_VALUE)) {
|
fd->vol_handle != INVALID_HANDLE_VALUE) {
|
||||||
Dputs("Reading via vol_handle");
|
Dputs("Reading via vol_handle.");
|
||||||
handle = fd->vol_handle;
|
handle = fd->vol_handle;
|
||||||
} else {
|
} else {
|
||||||
Dputs("Reading via handle");
|
Dputs("Reading via handle.");
|
||||||
handle = fd->handle;
|
handle = fd->handle;
|
||||||
}
|
}
|
||||||
|
if (!ReadFile(handle, buf, count, &br, NULL)) {
|
||||||
rvl = ReadFile(handle, buf, count, &i, (LPOVERLAPPED)NULL);
|
|
||||||
if (!rvl) {
|
|
||||||
errno = ntfs_w32error_to_errno(GetLastError());
|
errno = ntfs_w32error_to_errno(GetLastError());
|
||||||
Dputs("Error: ReadFile failed.");
|
Dputs("Error: ReadFile() failed.");
|
||||||
return -1;
|
return (DWORD)-1;
|
||||||
} else if (!i) {
|
|
||||||
errno = ENXIO;
|
|
||||||
Dputs("Error: ReadFile failed: EOF.");
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
return i;
|
* NOTE: The caller *MUST* update fd->real_pos and fd->real_ofs!!!
|
||||||
|
* Alternatively, caller can call ntfs_device_win32_{,abs_}seek().
|
||||||
|
*/
|
||||||
|
return br;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -956,77 +949,80 @@ static DWORD ntfs_device_win32_read_simple(win32_fd *fd, void *buf,
|
||||||
*/
|
*/
|
||||||
static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *buf, s64 count)
|
static s64 ntfs_device_win32_read(struct ntfs_device *dev, void *buf, s64 count)
|
||||||
{
|
{
|
||||||
|
s64 pos, to_read;
|
||||||
struct win32_fd *fd = (win32_fd *)dev->d_private;
|
struct win32_fd *fd = (win32_fd *)dev->d_private;
|
||||||
LARGE_INTEGER base, offset, numtoread;
|
|
||||||
BYTE *alignedbuffer;
|
BYTE *alignedbuffer;
|
||||||
DWORD i, numread = 0;
|
int old_ofs;
|
||||||
|
DWORD i, br = 0;
|
||||||
|
|
||||||
offset.QuadPart = fd->current_pos.QuadPart & 0x1FF;
|
old_ofs = fd->real_ofs;
|
||||||
base.QuadPart = fd->current_pos.QuadPart - offset.QuadPart;
|
pos = fd->real_pos + old_ofs;
|
||||||
numtoread.QuadPart = ((count + offset.QuadPart - 1) | 0x1FF) + 1;
|
to_read = (old_ofs + count + NTFS_BLOCK_SIZE - 1) &
|
||||||
|
~(s64)(NTFS_BLOCK_SIZE - 1);
|
||||||
Dprintf("win32_read(fd=%p,b=%p,count=0x%llx)->(%llx+%llx:%llx)\n", fd,
|
/* Impose maximum of 2GB to be on the safe side. */
|
||||||
buf, count, base.QuadPart, offset.QuadPart,
|
if (to_read > 0x80000000) {
|
||||||
numtoread.QuadPart);
|
int delta = to_read - count;
|
||||||
|
to_read = 0x80000000;
|
||||||
if (((((long)buf) & ((s64)0x1FF)) == 0) && ((count & ((s64)0x1FF)) == 0)
|
count = to_read - delta;
|
||||||
&& ((fd->current_pos.QuadPart & 0x1FF) == 0)) {
|
}
|
||||||
|
Dprintf("win32_read(fd=%p,b=%p,count=0x%llx)->(%llx+%x:%llx)\n", fd,
|
||||||
|
buf, count, (long long)fd->real_pos, old_ofs,
|
||||||
|
(long long)to_read);
|
||||||
|
if (!((unsigned long)buf & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
|
||||||
|
!(count & (NTFS_BLOCK_SIZE - 1)))
|
||||||
alignedbuffer = buf;
|
alignedbuffer = buf;
|
||||||
} else {
|
else {
|
||||||
alignedbuffer = (BYTE *)VirtualAlloc(NULL, numtoread.LowPart,
|
alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT,
|
||||||
MEM_COMMIT, PAGE_READWRITE);
|
PAGE_READWRITE);
|
||||||
if (alignedbuffer == NULL) {
|
if (!alignedbuffer) {
|
||||||
errno = ntfs_w32error_to_errno(GetLastError());
|
errno = ntfs_w32error_to_errno(GetLastError());
|
||||||
Dputs("Error: VirtualAlloc failed for read.");
|
Dputs("Error: VirtualAlloc failed for read.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (fd->vol_handle != INVALID_HANDLE_VALUE && pos < fd->geo_size) {
|
||||||
/* seek to base, if we are not in place */
|
s64 vol_to_read = fd->geo_size - pos;
|
||||||
if ((fd->current_pos.QuadPart & 0x1FF) &&
|
if (count > vol_to_read) {
|
||||||
(ntfs_device_win32_abs_seek(fd, base) == -1))
|
br = ntfs_device_win32_read_simple(fd,
|
||||||
|
alignedbuffer, old_ofs + vol_to_read);
|
||||||
|
if (br == (DWORD)-1)
|
||||||
goto read_error;
|
goto read_error;
|
||||||
|
to_read -= br;
|
||||||
if ((fd->vol_handle != INVALID_HANDLE_VALUE) &&
|
if (br < old_ofs) {
|
||||||
(fd->current_pos.QuadPart < fd->geo_size)) {
|
br = 0;
|
||||||
s64 vol_numtoread = fd->geo_size - fd->current_pos.QuadPart;
|
|
||||||
if (count > vol_numtoread) {
|
|
||||||
numread = ntfs_device_win32_read_simple(fd,
|
|
||||||
(LPVOID)alignedbuffer, vol_numtoread);
|
|
||||||
if (numread==(DWORD)-1)
|
|
||||||
goto read_error;
|
|
||||||
if (numread!=vol_numtoread)
|
|
||||||
goto read_partial;
|
goto read_partial;
|
||||||
|
}
|
||||||
base.QuadPart = fd->geo_size;
|
br -= old_ofs;
|
||||||
numtoread.QuadPart -= numread;
|
pos += br;
|
||||||
if (ntfs_device_win32_abs_seek(fd, base) == -1)
|
fd->real_pos = pos & ~(s64)(NTFS_BLOCK_SIZE - 1);
|
||||||
|
fd->real_ofs = pos & (NTFS_BLOCK_SIZE - 1);
|
||||||
|
if (br != vol_to_read)
|
||||||
goto read_partial;
|
goto read_partial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ((i = ntfs_device_win32_read_simple(fd, alignedbuffer + br,
|
||||||
if ((i = ntfs_device_win32_read_simple(fd, (LPVOID)(alignedbuffer +
|
to_read)) == (DWORD)-1) {
|
||||||
numread), numtoread.QuadPart)) == (DWORD)-1) {
|
if (br)
|
||||||
if (numread>0)
|
|
||||||
goto read_partial;
|
goto read_partial;
|
||||||
goto read_error;
|
goto read_error;
|
||||||
}
|
}
|
||||||
numread += i;
|
if (i < fd->real_ofs)
|
||||||
|
goto read_partial;
|
||||||
|
i -= fd->real_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);
|
||||||
read_partial:
|
read_partial:
|
||||||
numread = (numread < offset.LowPart) ? 0 : ((numread - offset.LowPart >
|
if (alignedbuffer != buf) {
|
||||||
count) ? count : (numread - offset.LowPart));
|
memcpy((void*)buf, alignedbuffer + old_ofs, br);
|
||||||
fd->current_pos.QuadPart += numread;
|
|
||||||
|
|
||||||
if (buf != alignedbuffer) {
|
|
||||||
memcpy((void *)buf, alignedbuffer + offset.QuadPart, numread);
|
|
||||||
VirtualFree(alignedbuffer, 0, MEM_RELEASE);
|
VirtualFree(alignedbuffer, 0, MEM_RELEASE);
|
||||||
}
|
}
|
||||||
|
return br;
|
||||||
return numread;
|
|
||||||
|
|
||||||
read_error:
|
read_error:
|
||||||
if (buf != alignedbuffer)
|
if (alignedbuffer != buf)
|
||||||
VirtualFree(alignedbuffer, 0, MEM_RELEASE);
|
VirtualFree(alignedbuffer, 0, MEM_RELEASE);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1045,12 +1041,10 @@ static int ntfs_device_win32_close(struct ntfs_device *dev)
|
||||||
BOOL rvl;
|
BOOL rvl;
|
||||||
|
|
||||||
Dprintf("win32_close(%p)\n", dev);
|
Dprintf("win32_close(%p)\n", dev);
|
||||||
|
|
||||||
if (!NDevOpen(dev)) {
|
if (!NDevOpen(dev)) {
|
||||||
errno = EBADF;
|
errno = EBADF;
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd->vol_handle != INVALID_HANDLE_VALUE) {
|
if (fd->vol_handle != INVALID_HANDLE_VALUE) {
|
||||||
if (!NDevReadOnly(dev)) {
|
if (!NDevReadOnly(dev)) {
|
||||||
ntfs_device_win32_dismount(fd->vol_handle);
|
ntfs_device_win32_dismount(fd->vol_handle);
|
||||||
|
@ -1059,17 +1053,13 @@ static int ntfs_device_win32_close(struct ntfs_device *dev)
|
||||||
if (!CloseHandle(fd->vol_handle))
|
if (!CloseHandle(fd->vol_handle))
|
||||||
Dputs("Error: CloseHandle failed for volume.");
|
Dputs("Error: CloseHandle failed for volume.");
|
||||||
}
|
}
|
||||||
|
|
||||||
rvl = CloseHandle(fd->handle);
|
rvl = CloseHandle(fd->handle);
|
||||||
|
|
||||||
free(fd);
|
free(fd);
|
||||||
|
|
||||||
if (!rvl) {
|
if (!rvl) {
|
||||||
errno = ntfs_w32error_to_errno(GetLastError());
|
errno = ntfs_w32error_to_errno(GetLastError());
|
||||||
Dputs("Error: CloseHandle failed.");
|
Dputs("Error: CloseHandle failed.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1085,32 +1075,30 @@ static int ntfs_device_win32_close(struct ntfs_device *dev)
|
||||||
*/
|
*/
|
||||||
static int ntfs_device_win32_sync(struct ntfs_device *dev)
|
static int ntfs_device_win32_sync(struct ntfs_device *dev)
|
||||||
{
|
{
|
||||||
|
int err = 0;
|
||||||
|
BOOL to_clear = TRUE;
|
||||||
|
|
||||||
if (!NDevReadOnly(dev) && NDevDirty(dev)) {
|
if (!NDevReadOnly(dev) && NDevDirty(dev)) {
|
||||||
struct win32_fd *fd = (win32_fd *)dev->d_private;
|
struct win32_fd *fd = (win32_fd *)dev->d_private;
|
||||||
|
|
||||||
if ((fd->vol_handle != INVALID_HANDLE_VALUE) &&
|
if ((fd->vol_handle != INVALID_HANDLE_VALUE) &&
|
||||||
FlushFileBuffers(fd->handle))
|
!FlushFileBuffers(fd->vol_handle)) {
|
||||||
NDevClearDirty(dev);
|
to_clear = FALSE;
|
||||||
|
err = ntfs_w32error_to_errno(GetLastError());
|
||||||
if (FlushFileBuffers(fd->handle)) {
|
}
|
||||||
NDevClearDirty(dev);
|
if (!FlushFileBuffers(fd->handle)) {
|
||||||
return 0;
|
to_clear = FALSE;
|
||||||
} else {
|
if (!err)
|
||||||
/* We want to set errno even if we return 0 to
|
err = ntfs_w32error_to_errno(GetLastError());
|
||||||
let the user to know about failure even in
|
}
|
||||||
the disk/volume case. */
|
if (!to_clear) {
|
||||||
errno = ntfs_w32error_to_errno(GetLastError());
|
errno = err;
|
||||||
/* Don't fail in case of volume/disk */
|
Dputs("Error: Could not sync.");
|
||||||
if (fd->geo_size != -1)
|
|
||||||
return 0;
|
|
||||||
/* fail on the other cases */
|
|
||||||
Dputs("Error: Couldn't sync.");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
NDevClearDirty(dev);
|
||||||
/* no need/ability for a sync(), just exit gracefully */
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1120,31 +1108,41 @@ static int ntfs_device_win32_sync(struct ntfs_device *dev)
|
||||||
* @count: How many bytes should be written.
|
* @count: How many bytes should be written.
|
||||||
*
|
*
|
||||||
* On success returns the amount of bytes actually written.
|
* On success returns the amount of bytes actually written.
|
||||||
* On fail returns -1 and errno set.
|
* On success returns the number of bytes written and on error returns
|
||||||
|
* (DWORD)-1 and errno set.
|
||||||
*
|
*
|
||||||
* Limitations:
|
* Notes:
|
||||||
* buf must be aligned to page boundery
|
* - Writes to fd->real_pos NOT considering fd->real_ofs.
|
||||||
* pos & count must be aligned to sector bounderies.
|
* - Does NOT advance fd->real_pos and fd->real_ofs.
|
||||||
* When dealing with volumes, a single call must not span both volume and disk
|
* - @buf must be aligned to page boundary.
|
||||||
* extents.
|
* - @count must be a multiple of the sector size.
|
||||||
|
* - When dealing with volumes, a single call must not span both volume
|
||||||
|
* and disk extents.
|
||||||
*/
|
*/
|
||||||
static DWORD ntfs_device_win32_write_simple(win32_fd *fd,
|
static DWORD ntfs_device_win32_write_simple(win32_fd *fd, const void *buf,
|
||||||
const void *buf, DWORD count)
|
DWORD count)
|
||||||
{
|
{
|
||||||
DWORD rvl, i;
|
HANDLE handle;
|
||||||
|
DWORD bw;
|
||||||
|
|
||||||
if ((fd->geo_size > fd->current_pos.QuadPart) &&
|
if (fd->real_pos + fd->real_ofs < fd->geo_size &&
|
||||||
(fd->vol_handle != INVALID_HANDLE_VALUE))
|
fd->vol_handle != INVALID_HANDLE_VALUE) {
|
||||||
rvl = WriteFile(fd->vol_handle, buf, count, &i, NULL);
|
Dputs("Writing via vol_handle");
|
||||||
else
|
handle = fd->vol_handle;
|
||||||
rvl = WriteFile(fd->handle, buf, count, &i, NULL);
|
} else {
|
||||||
|
Dputs("Writing via handle");
|
||||||
if (!rvl) {
|
handle = fd->handle;
|
||||||
|
}
|
||||||
|
if (!WriteFile(handle, buf, count, &bw, NULL)) {
|
||||||
errno = ntfs_w32error_to_errno(GetLastError());
|
errno = ntfs_w32error_to_errno(GetLastError());
|
||||||
Dputs("Error: WriteFile failed.");
|
Dputs("Error: WriteFile failed.");
|
||||||
return (DWORD)-1;
|
return (DWORD)-1;
|
||||||
}
|
}
|
||||||
return i;
|
/*
|
||||||
|
* NOTE: The caller *MUST* update fd->real_pos and fd->real_ofs!!!
|
||||||
|
* Alternatively, caller can call ntfs_device_win32_{,abs_}seek().
|
||||||
|
*/
|
||||||
|
return bw;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1159,111 +1157,122 @@ static DWORD ntfs_device_win32_write_simple(win32_fd *fd,
|
||||||
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 *buf,
|
||||||
s64 count)
|
s64 count)
|
||||||
{
|
{
|
||||||
|
s64 pos, to_write;
|
||||||
win32_fd *fd = (win32_fd *)dev->d_private;
|
win32_fd *fd = (win32_fd *)dev->d_private;
|
||||||
LARGE_INTEGER base, offset, actual_count;
|
BYTE *alignedbuffer;
|
||||||
BYTE *alignedbuffer = NULL;
|
int old_ofs;
|
||||||
DWORD i;
|
DWORD i, bw = 0;
|
||||||
|
|
||||||
Dprintf("win32_write: Writing %lld bytes\n",count);
|
|
||||||
|
|
||||||
|
Dprintf("win32_write: Writing %lld bytes\n", (long long)count);
|
||||||
if (NDevReadOnly(dev)) {
|
if (NDevReadOnly(dev)) {
|
||||||
Dputs("win32_write: Device R/O, exiting.");
|
Dputs("win32_write: Device R/O, exiting.");
|
||||||
errno = EROFS;
|
errno = EROFS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!count)
|
if (!count)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
NDevSetDirty(dev);
|
NDevSetDirty(dev);
|
||||||
|
old_ofs = fd->real_ofs;
|
||||||
offset.QuadPart = fd->current_pos.QuadPart & 0x1FF;
|
pos = fd->real_pos + old_ofs;
|
||||||
base.QuadPart = fd->current_pos.QuadPart - offset.QuadPart;
|
to_write = (old_ofs + count + NTFS_BLOCK_SIZE - 1) &
|
||||||
actual_count.QuadPart = ((count + offset.QuadPart - 1) | 0x1FF) + 1;
|
~(s64)(NTFS_BLOCK_SIZE - 1);
|
||||||
|
/* Impose maximum of 2GB to be on the safe side. */
|
||||||
if ((actual_count.QuadPart != count) || (((long)buf) & 0x1FF) ||
|
if (to_write > 0x80000000) {
|
||||||
(fd->current_pos.QuadPart & 0x1FF)) {
|
int delta = to_write - count;
|
||||||
alignedbuffer = (BYTE *)VirtualAlloc(NULL,
|
to_write = 0x80000000;
|
||||||
actual_count.QuadPart, MEM_COMMIT, PAGE_READWRITE);
|
count = to_write - delta;
|
||||||
if (alignedbuffer == NULL) {
|
}
|
||||||
|
if (!((unsigned long)buf & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
|
||||||
|
!(count & (NTFS_BLOCK_SIZE - 1)))
|
||||||
|
alignedbuffer = buf;
|
||||||
|
else {
|
||||||
|
alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_write,
|
||||||
|
MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
if (!alignedbuffer) {
|
||||||
errno = ntfs_w32error_to_errno(GetLastError());
|
errno = ntfs_w32error_to_errno(GetLastError());
|
||||||
Dputs("Error: VirtualAlloc failed for write.");
|
Dputs("Error: VirtualAlloc failed for write.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
/* Read first sector if start of write not sector aligned. */
|
||||||
/* read last sector */
|
if (old_ofs) {
|
||||||
if ((offset.QuadPart + count) & 0x1FF) {
|
i = ntfs_device_win32_read_simple(fd, alignedbuffer,
|
||||||
LARGE_INTEGER pos;
|
NTFS_BLOCK_SIZE);
|
||||||
pos.QuadPart = base.QuadPart + actual_count.QuadPart -
|
if (i != NTFS_BLOCK_SIZE) {
|
||||||
512;
|
if (i >= 0)
|
||||||
if (ntfs_device_win32_abs_seek(fd, pos) == -1)
|
errno = EIO;
|
||||||
goto write_error;
|
|
||||||
if (!ntfs_device_win32_read_simple(fd,
|
|
||||||
(LPVOID)(alignedbuffer +
|
|
||||||
actual_count.QuadPart - 512), 512))
|
|
||||||
goto write_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read first sector */
|
|
||||||
if (offset.LowPart) {
|
|
||||||
if (ntfs_device_win32_abs_seek(fd, base) == -1)
|
|
||||||
goto write_error;
|
|
||||||
if (!ntfs_device_win32_read_simple(fd,
|
|
||||||
(LPVOID)(alignedbuffer), 512)) {
|
|
||||||
goto write_error;
|
goto write_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Read last sector if end of write not sector aligned. */
|
||||||
/* copy the rest of the contents */
|
if ((pos + count) & (NTFS_BLOCK_SIZE - 1)) {
|
||||||
memcpy((void *)(alignedbuffer + offset.LowPart), buf,
|
if (ntfs_device_win32_abs_seek(fd, (pos + count) &
|
||||||
(size_t)count);
|
~(NTFS_BLOCK_SIZE - 1)) == -1)
|
||||||
|
|
||||||
/* ReAligning */
|
|
||||||
if (ntfs_device_win32_abs_seek(fd, base) == -1)
|
|
||||||
goto write_error;
|
goto write_error;
|
||||||
|
i = ntfs_device_win32_read_simple(fd, alignedbuffer +
|
||||||
/* hack to share code */
|
to_write - NTFS_BLOCK_SIZE,
|
||||||
buf = (const void *)alignedbuffer;
|
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)
|
||||||
if ((fd->geo_size > base.QuadPart) &&
|
errno = EIO;
|
||||||
(fd->vol_handle != INVALID_HANDLE_VALUE)) {
|
|
||||||
s64 tmp = min((fd->geo_size - base.QuadPart),
|
|
||||||
actual_count.QuadPart);
|
|
||||||
i = ntfs_device_win32_write_simple(fd, buf, tmp);
|
|
||||||
if (i == (DWORD)-1)
|
|
||||||
goto write_error;
|
|
||||||
if (i != tmp)
|
|
||||||
goto partial_write;
|
|
||||||
base.QuadPart -= i;
|
|
||||||
} else
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
if (fd->geo_size <= base.QuadPart) {
|
|
||||||
const void *newp = (const void *)(((const BYTE *)buf) + i);
|
|
||||||
i += ntfs_device_win32_write_simple(fd, newp,
|
|
||||||
actual_count.LowPart - i);
|
|
||||||
if (!i || (i == (DWORD)-1))
|
|
||||||
goto write_error;
|
goto write_error;
|
||||||
}
|
}
|
||||||
partial_write:
|
}
|
||||||
if (alignedbuffer)
|
/* 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);
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
goto write_error;
|
||||||
|
to_write -= bw;
|
||||||
|
if (bw < old_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);
|
||||||
|
if (bw != vol_to_write)
|
||||||
|
goto write_partial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((i = ntfs_device_win32_write_simple(fd, alignedbuffer + bw,
|
||||||
|
to_write)) == (DWORD)-1) {
|
||||||
|
if (bw)
|
||||||
|
goto write_partial;
|
||||||
|
goto write_error;
|
||||||
|
}
|
||||||
|
if (i < fd->real_ofs)
|
||||||
|
goto write_partial;
|
||||||
|
i -= fd->real_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);
|
||||||
|
write_partial:
|
||||||
|
if (alignedbuffer != buf)
|
||||||
VirtualFree(alignedbuffer, 0, MEM_RELEASE);
|
VirtualFree(alignedbuffer, 0, MEM_RELEASE);
|
||||||
|
return bw;
|
||||||
actual_count.QuadPart = (s64)i - actual_count.QuadPart + count;
|
|
||||||
if (actual_count.QuadPart < 0)
|
|
||||||
return 0;
|
|
||||||
return actual_count.QuadPart;
|
|
||||||
|
|
||||||
write_error:
|
write_error:
|
||||||
if (alignedbuffer)
|
bw = -1;
|
||||||
VirtualFree(alignedbuffer, 0, MEM_RELEASE);
|
goto write_partial;
|
||||||
|
|
||||||
fd->current_pos.QuadPart = base.QuadPart + offset.QuadPart;
|
|
||||||
if (!(fd->current_pos.QuadPart & 512))
|
|
||||||
ntfs_device_win32_abs_seek(fd, base);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue