diff options
author | cvs2svn <> | 2012-10-20 19:31:51 +0400 |
---|---|---|
committer | cvs2svn <> | 2012-10-20 19:31:51 +0400 |
commit | 899ce99cebcb67deca7f9b2a4f1e750a2263881e (patch) | |
tree | 49ee41a55b15ab82f82305e4849859c4a2d1cc54 /winsup/cygwin/fhandler_floppy.cc | |
parent | c0956742a74d194b9c18c7a91aa6d6010beb4cd3 (diff) |
This commit was manufactured by cvs2svn to create tag 'cygwin-cygwin-1_7_17-release
1_7_17-release'.
Sprout from cygwin-64bit-branch 2012-08-10 09:37:33 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin-64bit-'
Cherrypick from cygwin-64bit-branch 2012-10-09 12:05:52 UTC cvs2svn 'This commit was manufactured by cvs2svn to create branch 'cygwin-64bit-':
newlib/libc/posix/wordexp2.h
Cherrypick from master 2012-10-20 15:31:50 UTC Corinna Vinschen <corinna@vinschen.de> ' * new-features.sgml (ov-new1.7.17): Add section.':
ChangeLog
Makefile.def
Makefile.in
Makefile.tpl
compile
config.guess
config.sub
config/ChangeLog
config/cloog.m4
config/isl.m4
config/mt-sde
configure
include/ChangeLog
include/demangle.h
include/dis-asm.h
include/dwarf2.def
include/elf/ChangeLog
include/elf/aarch64.h
include/elf/arm.h
include/elf/common.h
include/elf/tilegx.h
include/mach-o/ChangeLog
include/mach-o/codesign.h
include/mach-o/external.h
include/mach-o/loader.h
include/mach-o/reloc.h
include/mach-o/x86-64.h
include/objalloc.h
include/opcode/ChangeLog
include/opcode/aarch64.h
include/opcode/arm.h
include/opcode/hppa.h
include/opcode/ia64.h
include/opcode/mips.h
include/opcode/moxie.h
include/opcode/s390.h
include/opcode/sparc.h
include/plugin-api.h
libtool.m4
ltoptions.m4
ltversion.m4
lt~obsolete.m4
newlib/ChangeLog
newlib/HOWTO
newlib/README
newlib/configure.host
newlib/doc/makedoc.c
newlib/libc/include/_ansi.h
newlib/libc/include/assert.h
newlib/libc/include/machine/_default_types.h
newlib/libc/include/machine/ieeefp.h
newlib/libc/include/machine/setjmp.h
newlib/libc/include/machine/time.h
newlib/libc/include/math.h
newlib/libc/include/stdint.h
newlib/libc/include/sys/config.h
newlib/libc/include/sys/features.h
newlib/libc/include/tgmath.h
newlib/libc/machine/configure
newlib/libc/machine/configure.in
newlib/libc/machine/rl78/Makefile.am
newlib/libc/machine/rl78/Makefile.in
newlib/libc/machine/rl78/aclocal.m4
newlib/libc/machine/rl78/configure
newlib/libc/machine/rl78/configure.in
newlib/libc/machine/rl78/setjmp.S
newlib/libc/posix/engine.c
newlib/libc/posix/wordexp.c
newlib/libc/posix/wordfree.c
newlib/libc/search/hash_buf.c
newlib/libc/stdio/fgets.c
newlib/libc/stdio/flags.c
newlib/libc/stdio/vfprintf.c
newlib/libc/stdlib/btowc.c
newlib/libc/stdlib/getopt.c
newlib/libc/string/strcasestr.c
newlib/libc/sys/sysnecv850/sbrk.c
newlib/libc/time/strftime.c
newlib/libm/machine/configure
newlib/libm/machine/configure.in
newlib/testsuite/newlib.stdio/stdio.exp
newlib/testsuite/newlib.stdio/swprintf.c
winsup/cygwin/ChangeLog
winsup/cygwin/DevNotes
winsup/cygwin/child_info.h
winsup/cygwin/cygheap.cc
winsup/cygwin/cygthread.cc
winsup/cygwin/cygtls.cc
winsup/cygwin/cygtls.h
winsup/cygwin/cygwait.cc
winsup/cygwin/cygwait.h
winsup/cygwin/dll_init.cc
winsup/cygwin/errno.cc
winsup/cygwin/exceptions.cc
winsup/cygwin/fhandler.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_clipboard.cc
winsup/cygwin/fhandler_console.cc
winsup/cygwin/fhandler_floppy.cc
winsup/cygwin/fhandler_process.cc
winsup/cygwin/fhandler_raw.cc
winsup/cygwin/fhandler_socket.cc
winsup/cygwin/fhandler_tape.cc
winsup/cygwin/fhandler_termios.cc
winsup/cygwin/fhandler_tty.cc
winsup/cygwin/flock.cc
winsup/cygwin/gendef
winsup/cygwin/glob.cc
winsup/cygwin/globals.cc
winsup/cygwin/gmon.c
winsup/cygwin/hookapi.cc
winsup/cygwin/include/cygwin/fs.h
winsup/cygwin/include/cygwin/in.h
winsup/cygwin/include/limits.h
winsup/cygwin/miscfuncs.cc
winsup/cygwin/mount.cc
winsup/cygwin/mount.h
winsup/cygwin/net.cc
winsup/cygwin/path.cc
winsup/cygwin/pinfo.cc
winsup/cygwin/posix_ipc.cc
winsup/cygwin/pseudo-reloc.cc
winsup/cygwin/release/1.7.10
winsup/cygwin/release/1.7.11
winsup/cygwin/release/1.7.12
winsup/cygwin/release/1.7.13
winsup/cygwin/release/1.7.14
winsup/cygwin/release/1.7.15
winsup/cygwin/release/1.7.16
winsup/cygwin/release/1.7.17
winsup/cygwin/sec_helper.cc
winsup/cygwin/signal.cc
winsup/cygwin/sigproc.h
winsup/cygwin/smallprint.cc
winsup/cygwin/spawn.cc
winsup/cygwin/syscalls.cc
winsup/cygwin/thread.cc
winsup/cygwin/thread.h
winsup/cygwin/tty.h
winsup/cygwin/wait.cc
winsup/doc/ChangeLog
winsup/doc/faq-what.xml
winsup/doc/new-features.sgml
winsup/utils/ChangeLog
winsup/utils/Makefile.in
winsup/utils/cygcheck.cc
winsup/w32api/ChangeLog
winsup/w32api/include/winbase.h
winsup/w32api/lib/kernel32.def
Diffstat (limited to 'winsup/cygwin/fhandler_floppy.cc')
-rw-r--r-- | winsup/cygwin/fhandler_floppy.cc | 238 |
1 files changed, 153 insertions, 85 deletions
diff --git a/winsup/cygwin/fhandler_floppy.cc b/winsup/cygwin/fhandler_floppy.cc index 0caca96e8..eaa7f6a2e 100644 --- a/winsup/cygwin/fhandler_floppy.cc +++ b/winsup/cygwin/fhandler_floppy.cc @@ -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 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 (!(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 not trying to access a floppy disk, make sure we're actually + allowed to read *all* of the device or volume. 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,58 +565,130 @@ 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 fhandler_dev_floppy::lseek (_off64_t offset, int whence) { char buf[bytes_per_sector]; - _off64_t lloffset = offset; _off64_t current_pos = (_off64_t) -1; LARGE_INTEGER sector_aligned_offset; size_t bytes_left; if (whence == SEEK_END) { - lloffset += drive_size; + offset += drive_size; whence = SEEK_SET; } else if (whence == SEEK_CUR) { current_pos = get_current_position (); - lloffset += current_pos - (devbufend - devbufstart); + _off64_t exact_pos = current_pos - (devbufend - devbufstart); + /* Shortcut when used to get current position. */ + if (offset == 0) + return exact_pos; + offset += exact_pos; whence = SEEK_SET; } - if (whence != SEEK_SET || lloffset < 0 || lloffset > drive_size) + if (whence != SEEK_SET || offset < 0 || offset > drive_size) { set_errno (EINVAL); return -1; @@ -624,27 +699,21 @@ fhandler_dev_floppy::lseek (_off64_t offset, int whence) { if (current_pos == (_off64_t) -1) current_pos = get_current_position (); - if (current_pos - devbufend <= lloffset && lloffset <= current_pos) + if (current_pos - devbufend <= offset && offset <= current_pos) { - devbufstart = devbufend - (current_pos - lloffset); - return lloffset; + devbufstart = devbufend - (current_pos - offset); + return offset; } } - sector_aligned_offset.QuadPart = (lloffset / bytes_per_sector) - * bytes_per_sector; - bytes_left = lloffset - sector_aligned_offset.QuadPart; + sector_aligned_offset.QuadPart = rounddown (offset, bytes_per_sector); + bytes_left = offset - 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 +734,58 @@ 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; - } - get_drive_info (NULL); - return 0; - } - case BLKSSZGET: - { - debug_printf ("BLKSSZGET"); - *(int *)buf = bytes_per_sector; - return 0; - } - 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. */ - if (((struct rdop *) buf)->rd_parm % bytes_per_sector) + debug_printf ("BLKRRPART"); + if (!DeviceIoControl (get_handle (), IOCTL_DISK_UPDATE_PROPERTIES, + NULL, 0, NULL, 0, &bytes_read, NULL)) { - SetLastError (ERROR_INVALID_PARAMETER); __seterrno (); - return -1; + ret = -1; } - /*FALLTHRU*/ + else + get_drive_info (NULL); + break; + case BLKSSZGET: + 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; default: - return fhandler_dev_raw::ioctl (cmd, buf); + ret = fhandler_dev_raw::ioctl (cmd, buf); + break; } + return ret; } |