* fhandler.h (class fhandler_dev_raw): Add members devbufalloc and
devbufalign. (class fhandler_dev_floppy): Remove member bytes_per_sector; * fhandler_floppy.cc (bytes_per_sector): Define as devbufalign. (fhandler_dev_floppy::open): Set devbufalign to a multiple of the sector size and handle devbuf allocation and alignment in !O_DIRECT case here. Change comment accordingly. Call FSCTL_ALLOW_EXTENDED_DASD_IO for partitions as well. (fhandler_dev_floppy::raw_write): Fix comment. Rewrite and fix writing behaviour when application uses read and lseek. (fhandler_dev_floppy::lseek): Use rounddown macro. Call SetFilePointerEx rather than the old SetFilePointer. (fhandler_dev_floppy::ioctl): Reformat switch. Call IOCTL_DISK_UPDATE_PROPERTIES rather than IOCTL_DISK_UPDATE_DRIVE_SIZE in BLKRRPART case. Support BLKIOMIN, BLKIOOPT, BLKPBSZGET and BLKALIGNOFF. * fhandler_raw.cc (fhandler_dev_raw::fhandler_dev_raw): Initialize all devbuf-related members. (fhandler_dev_raw::~fhandler_dev_raw): Delete devbufalloc rather than devbuf. (fhandler_dev_raw::open): Drop allocating devbuf. (fhandler_dev_raw::dup): Allocate devbufalloc and set devbuf to support new sector-aligned devbuf handling. (fhandler_dev_raw::fixup_after_exec): Ditto. * fhandler_tape.cc (fhandler_dev_tape::open): Ditto, set devbufalign to 1. * include/cygwin/fs.h (BLKIOMIN): Define. (BLKIOOPT): Define. (BLKALIGNOFF): Define. (BLKPBSZGET): Define.
This commit is contained in:
@ -28,6 +28,8 @@ details. */
|
||||
|| (err) == ERROR_SEEK \
|
||||
|| (err) == ERROR_SECTOR_NOT_FOUND)
|
||||
|
||||
#define bytes_per_sector devbufalign
|
||||
|
||||
/**********************************************************************/
|
||||
/* fhandler_dev_floppy */
|
||||
|
||||
@ -355,16 +357,6 @@ fhandler_dev_floppy::write_file (const void *buf, DWORD to_write,
|
||||
int
|
||||
fhandler_dev_floppy::open (int flags, mode_t)
|
||||
{
|
||||
/* The correct size of the buffer would be 512 bytes, which is the atomic
|
||||
size, supported by WinNT. Unfortunately, the performance is worse than
|
||||
access to file system on same device! Setting buffer size to a
|
||||
relatively big value increases performance by means. The new ioctl call
|
||||
with 'rdevio.h' header file supports changing this value.
|
||||
|
||||
As default buffer size, we're using some value which is a multiple of
|
||||
the typical tar and cpio buffer sizes, Except O_DIRECT is set, in which
|
||||
case we're not buffering at all. */
|
||||
devbufsiz = (flags & O_DIRECT) ? 0L : 61440L;
|
||||
int ret = fhandler_dev_raw::open (flags);
|
||||
|
||||
if (ret)
|
||||
@ -376,11 +368,22 @@ fhandler_dev_floppy::open (int flags, mode_t)
|
||||
close ();
|
||||
return 0;
|
||||
}
|
||||
if (!(flags & O_DIRECT))
|
||||
{
|
||||
/* Create sector-aligned buffer. As default buffer size, we're using
|
||||
some big, sector-aligned value. Since direct blockdev IO is
|
||||
usually non-buffered and non-cached, the performance without
|
||||
buffering is worse than access to a file system on same device.
|
||||
Whoever uses O_DIRECT has my condolences. */
|
||||
devbufsiz = MAX (16 * bytes_per_sector, 65536);
|
||||
devbufalloc = new char [devbufsiz + devbufalign];
|
||||
devbuf = (char *) roundup2 ((uintptr_t) devbufalloc, devbufalign);
|
||||
}
|
||||
|
||||
/* If we're trying to access a CD/DVD drive, or an entire disk,
|
||||
make sure we're actually allowed to read *all* of the device.
|
||||
This is actually documented in the MSDN CreateFile man page. */
|
||||
if (get_major () != DEV_FLOPPY_MAJOR
|
||||
&& (get_major () == DEV_CDROM_MAJOR || get_minor () % 16 == 0)
|
||||
&& !DeviceIoControl (get_handle (), FSCTL_ALLOW_EXTENDED_DASD_IO,
|
||||
NULL, 0, NULL, 0, &bytes_read, NULL))
|
||||
debug_printf ("DeviceIoControl (FSCTL_ALLOW_EXTENDED_DASD_IO) "
|
||||
@ -562,34 +565,103 @@ fhandler_dev_floppy::raw_write (const void *ptr, size_t len)
|
||||
char *p = (char *) ptr;
|
||||
int ret;
|
||||
|
||||
/* Checking a previous end of media on tape */
|
||||
/* Checking a previous end of media */
|
||||
if (eom_detected ())
|
||||
{
|
||||
set_errno (ENOSPC);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Invalidate buffer. */
|
||||
devbufstart = devbufend = 0;
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
if (len > 0)
|
||||
if (devbuf)
|
||||
{
|
||||
if (!write_file (p, len, &bytes_written, &ret))
|
||||
{
|
||||
if (!IS_EOM (ret))
|
||||
DWORD cplen, written;
|
||||
|
||||
/* First check if we have an active read buffer. If so, try to fit in
|
||||
the start of the input buffer and write out the entire result.
|
||||
This also covers the situation after lseek since lseek fills the read
|
||||
buffer in case we seek to an address which is not sector aligned. */
|
||||
if (devbufend && devbufstart < devbufend)
|
||||
{
|
||||
_off64_t current_pos = get_current_position ();
|
||||
cplen = MIN (len, devbufend - devbufstart);
|
||||
memcpy (devbuf + devbufstart, p, cplen);
|
||||
LARGE_INTEGER off = { QuadPart:current_pos - devbufend };
|
||||
if (!SetFilePointerEx (get_handle (), off, NULL, FILE_BEGIN))
|
||||
{
|
||||
devbufstart = devbufend = 0;
|
||||
__seterrno ();
|
||||
return -1;
|
||||
}
|
||||
eom_detected (true);
|
||||
if (!bytes_written)
|
||||
if (!write_file (devbuf, devbufend, &written, &ret))
|
||||
{
|
||||
set_errno (ENOSPC);
|
||||
return -1;
|
||||
devbufstart = devbufend = 0;
|
||||
goto err;
|
||||
}
|
||||
/* Align pointers, lengths, etc. */
|
||||
cplen = MIN (cplen, written);
|
||||
devbufstart += cplen;
|
||||
p += cplen;
|
||||
len -= cplen;
|
||||
bytes_written += cplen;
|
||||
if (len)
|
||||
devbufstart = devbufend = 0;
|
||||
}
|
||||
/* As long as there's still something left in the input buffer ... */
|
||||
while (len)
|
||||
{
|
||||
/* Compute the length to write. The problem is that the underlying
|
||||
driver may require sector aligned read/write. So we copy the data
|
||||
over to devbuf, which is guaranteed to be sector aligned. */
|
||||
cplen = MIN (len, devbufsiz);
|
||||
if (cplen >= bytes_per_sector)
|
||||
/* If the remaining len is >= sector size, write out the maximum
|
||||
possible multiple of the sector size which fits into devbuf. */
|
||||
cplen = rounddown (cplen, bytes_per_sector);
|
||||
else
|
||||
{
|
||||
/* If len < sector size, read in the next sector, seek back,
|
||||
and just copy the new data over the old one before writing. */
|
||||
LARGE_INTEGER off = { QuadPart:get_current_position () };
|
||||
if (!read_file (devbuf, bytes_per_sector, &written, &ret))
|
||||
goto err;
|
||||
if (!SetFilePointerEx (get_handle (), off, NULL, FILE_BEGIN))
|
||||
{
|
||||
__seterrno ();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
memcpy (devbuf, p, cplen);
|
||||
if (!write_file (devbuf, MAX (cplen, bytes_per_sector), &written,
|
||||
&ret))
|
||||
{
|
||||
bytes_written += MIN (cplen, written);
|
||||
goto err;
|
||||
}
|
||||
cplen = MIN (cplen, written);
|
||||
p += cplen;
|
||||
len -= cplen;
|
||||
bytes_written += cplen;
|
||||
}
|
||||
return bytes_written;
|
||||
}
|
||||
return bytes_written;
|
||||
|
||||
/* In O_DIRECT case, just write. */
|
||||
if (write_file (p, len, &bytes_written, &ret))
|
||||
return bytes_written;
|
||||
|
||||
err:
|
||||
if (IS_EOM (ret))
|
||||
{
|
||||
eom_detected (true);
|
||||
if (!bytes_written)
|
||||
set_errno (ENOSPC);
|
||||
}
|
||||
else if (!bytes_written)
|
||||
__seterrno ();
|
||||
return bytes_written ?: -1;
|
||||
}
|
||||
|
||||
_off64_t
|
||||
@ -631,20 +703,14 @@ fhandler_dev_floppy::lseek (_off64_t offset, int whence)
|
||||
}
|
||||
}
|
||||
|
||||
sector_aligned_offset.QuadPart = (lloffset / bytes_per_sector)
|
||||
* bytes_per_sector;
|
||||
sector_aligned_offset.QuadPart = rounddown (lloffset, bytes_per_sector);
|
||||
bytes_left = lloffset - sector_aligned_offset.QuadPart;
|
||||
|
||||
/* Invalidate buffer. */
|
||||
devbufstart = devbufend = 0;
|
||||
|
||||
sector_aligned_offset.LowPart =
|
||||
SetFilePointer (get_handle (),
|
||||
sector_aligned_offset.LowPart,
|
||||
§or_aligned_offset.HighPart,
|
||||
FILE_BEGIN);
|
||||
if (sector_aligned_offset.LowPart == INVALID_SET_FILE_POINTER
|
||||
&& GetLastError ())
|
||||
if (!SetFilePointerEx (get_handle (), sector_aligned_offset, NULL,
|
||||
FILE_BEGIN))
|
||||
{
|
||||
__seterrno ();
|
||||
return -1;
|
||||
@ -665,59 +731,69 @@ fhandler_dev_floppy::lseek (_off64_t offset, int whence)
|
||||
int
|
||||
fhandler_dev_floppy::ioctl (unsigned int cmd, void *buf)
|
||||
{
|
||||
DISK_GEOMETRY di;
|
||||
int ret = 0;
|
||||
DWORD bytes_read;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case HDIO_GETGEO:
|
||||
{
|
||||
debug_printf ("HDIO_GETGEO");
|
||||
return get_drive_info ((struct hd_geometry *) buf);
|
||||
}
|
||||
debug_printf ("HDIO_GETGEO");
|
||||
ret = get_drive_info ((struct hd_geometry *) buf);
|
||||
break;
|
||||
case BLKGETSIZE:
|
||||
case BLKGETSIZE64:
|
||||
{
|
||||
debug_printf ("BLKGETSIZE");
|
||||
if (cmd == BLKGETSIZE)
|
||||
*(long *)buf = drive_size >> 9UL;
|
||||
else
|
||||
*(_off64_t *)buf = drive_size;
|
||||
return 0;
|
||||
}
|
||||
debug_printf ("BLKGETSIZE");
|
||||
if (cmd == BLKGETSIZE)
|
||||
*(long *)buf = drive_size >> 9UL;
|
||||
else
|
||||
*(_off64_t *)buf = drive_size;
|
||||
break;
|
||||
case BLKRRPART:
|
||||
{
|
||||
debug_printf ("BLKRRPART");
|
||||
if (!DeviceIoControl (get_handle (),
|
||||
IOCTL_DISK_UPDATE_DRIVE_SIZE,
|
||||
NULL, 0,
|
||||
&di, sizeof (di),
|
||||
&bytes_read, NULL))
|
||||
{
|
||||
__seterrno ();
|
||||
return -1;
|
||||
}
|
||||
debug_printf ("BLKRRPART");
|
||||
if (!DeviceIoControl (get_handle (), IOCTL_DISK_UPDATE_PROPERTIES,
|
||||
NULL, 0, NULL, 0, &bytes_read, NULL))
|
||||
{
|
||||
__seterrno ();
|
||||
ret = -1;
|
||||
}
|
||||
else
|
||||
get_drive_info (NULL);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case BLKSSZGET:
|
||||
{
|
||||
debug_printf ("BLKSSZGET");
|
||||
*(int *)buf = bytes_per_sector;
|
||||
return 0;
|
||||
}
|
||||
debug_printf ("BLKSSZGET");
|
||||
*(int *)buf = bytes_per_sector;
|
||||
break;
|
||||
case BLKIOMIN:
|
||||
debug_printf ("BLKIOMIN");
|
||||
*(int *)buf = bytes_per_sector;
|
||||
break;
|
||||
case BLKIOOPT:
|
||||
debug_printf ("BLKIOOPT");
|
||||
*(int *)buf = bytes_per_sector;
|
||||
break;
|
||||
case BLKPBSZGET:
|
||||
debug_printf ("BLKPBSZGET");
|
||||
*(int *)buf = bytes_per_sector;
|
||||
break;
|
||||
case BLKALIGNOFF:
|
||||
debug_printf ("BLKALIGNOFF");
|
||||
*(int *)buf = 0;
|
||||
break;
|
||||
case RDSETBLK:
|
||||
/* Just check the restriction that blocksize must be a multiple
|
||||
of the sector size of the underlying volume sector size,
|
||||
then fall through to fhandler_dev_raw::ioctl. */
|
||||
debug_printf ("RDSETBLK");
|
||||
if (((struct rdop *) buf)->rd_parm % bytes_per_sector)
|
||||
{
|
||||
SetLastError (ERROR_INVALID_PARAMETER);
|
||||
__seterrno ();
|
||||
set_errno (EINVAL);
|
||||
return -1;
|
||||
}
|
||||
/*FALLTHRU*/
|
||||
default:
|
||||
return fhandler_dev_raw::ioctl (cmd, buf);
|
||||
ret = fhandler_dev_raw::ioctl (cmd, buf);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user