diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index fad41419f..95fcb5301 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,19 @@ +2011-01-11 Corinna Vinschen + + * fhandler.h (MAX_PARTITIONS): New definition. + (class fhandler_dev_floppy): Add partitions array member. Add close + method. + * fhandler_floppy.cc (fhandler_dev_floppy::fhandler_dev_floppy): Zero + out partitions array. + (fhandler_dev_floppy::open): Fix "entire disk" condition for call to + DeviceIoControl (FSCTL_ALLOW_EXTENDED_DASD_IO). + When opening disks for writing, call DeviceIoControl (FSCTL_LOCK_VOLUME) + on all affected disk partitions starting with Vista. + (fhandler_dev_floppy::close): New method. + (fhandler_dev_floppy::dup): Duplicate handles in partitions, if any. + * wincap.h (wincaps::has_restricted_raw_disk_access): New element. + * wincap.cc: Implement above element throughout. + 2011-01-11 Yaakov Selkowitz * termios.cc (cfgetospeed, cfgetispeed): Constify argument per POSIX. diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 66ebc1198..056199038 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1,7 +1,7 @@ /* fhandler.h Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, - 2005, 2006, 2007, 2008, 2009, 2010 Red Hat, Inc. + 2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. This file is part of Cygwin. @@ -687,11 +687,14 @@ class fhandler_dev_raw: public fhandler_base void fixup_after_exec (); }; +#define MAX_PARTITIONS 15 + class fhandler_dev_floppy: public fhandler_dev_raw { private: _off64_t drive_size; unsigned long bytes_per_sector; + HANDLE partitions[MAX_PARTITIONS]; struct status_flags { unsigned eom_detected : 1; @@ -711,6 +714,7 @@ class fhandler_dev_floppy: public fhandler_dev_raw fhandler_dev_floppy (); int open (int flags, mode_t mode = 0); + int close (); int dup (fhandler_base *child); void __stdcall raw_read (void *ptr, size_t& ulen); ssize_t __stdcall raw_write (const void *ptr, size_t ulen); diff --git a/winsup/cygwin/fhandler_floppy.cc b/winsup/cygwin/fhandler_floppy.cc index 0d906b186..af8b7d2f1 100644 --- a/winsup/cygwin/fhandler_floppy.cc +++ b/winsup/cygwin/fhandler_floppy.cc @@ -2,7 +2,7 @@ fhandler classes. Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009 Red Hat, Inc. + 2009, 2011 Red Hat, Inc. This file is part of Cygwin. @@ -32,6 +32,7 @@ details. */ fhandler_dev_floppy::fhandler_dev_floppy () : fhandler_dev_raw (), status () { + memset (partitions, 0, sizeof partitions); } int @@ -221,25 +222,98 @@ fhandler_dev_floppy::open (int flags, mode_t) 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 () == 0) + && (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) " "failed, %E"); + /* If we're trying to write to a disk partition, lock the partition, + otherwise we will get "Access denied" starting with Vista. */ + if (wincap.has_restricted_raw_disk_access () + && get_major () != DEV_FLOPPY_MAJOR + && get_major () != DEV_CDROM_MAJOR + && (flags & O_ACCMODE) != O_RDONLY) + { + /* Special case: If we try to write to the entire disk, we have to + lock all partitions, otherwise writing fails as soon as we cross + a partition boundary. */ + if (get_minor () % 16 == 0) + { + WCHAR part[MAX_PATH], *p; + + sys_mbstowcs (part, MAX_PATH, get_win32_name ()); + p = wcschr (part, L'\0') - 1; + for (int i = 0; i < MAX_PARTITIONS; ++i) + { + NTSTATUS status; + UNICODE_STRING upart; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + + __small_swprintf (p, L"%d", i + 1); + RtlInitUnicodeString (&upart, part); + InitializeObjectAttributes (&attr, &upart, + OBJ_INHERIT|OBJ_CASE_INSENSITIVE, + NULL, NULL); + status = NtOpenFile (&partitions[i], GENERIC_WRITE, &attr, + &io, FILE_SHARE_VALID_FLAGS, 0); + if (status == STATUS_OBJECT_NAME_NOT_FOUND || + status == STATUS_OBJECT_PATH_NOT_FOUND) + break; + else if (!NT_SUCCESS (status)) + debug_printf ("NtCreateFile(%W): status %p", part, status); + else if (!DeviceIoControl (partitions[i], FSCTL_LOCK_VOLUME, + NULL, 0, NULL, 0, + &bytes_read, NULL)) + debug_printf ("DeviceIoControl (%W, FSCTL_LOCK_VOLUME) " + "failed, %E", part); + } + } + else if (!DeviceIoControl (get_handle (), FSCTL_LOCK_VOLUME, + NULL, 0, NULL, 0, &bytes_read, NULL)) + debug_printf ("DeviceIoControl (FSCTL_LOCK_VOLUME) failed, %E"); + } } return ret; } +int +fhandler_dev_floppy::close () +{ + int ret = fhandler_dev_raw::close (); + + /* See "Special case" comment in fhandler_dev_floppy::open. */ + if (wincap.has_restricted_raw_disk_access ()) + for (int i = 0; i < MAX_PARTITIONS && partitions[i]; ++i) + NtClose (partitions[i]); + + return ret; +} + int fhandler_dev_floppy::dup (fhandler_base *child) { + fhandler_dev_floppy *fhc = (fhandler_dev_floppy *) child; + + /* See "Special case" comment in fhandler_dev_floppy::open. */ + memset (fhc->partitions, 0, sizeof fhc->partitions); + if (wincap.has_restricted_raw_disk_access ()) + for (int i = 0; i < MAX_PARTITIONS && partitions[i]; ++i) + if (!DuplicateHandle (GetCurrentProcess (), partitions[i], + GetCurrentProcess (), &fhc->partitions[i], + 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + __seterrno (); + while (--i >= 0) + NtClose (partitions[i]); + return -1; + } + int ret = fhandler_dev_raw::dup (child); if (!ret) { - fhandler_dev_floppy *fhc = (fhandler_dev_floppy *) child; - fhc->drive_size = drive_size; fhc->bytes_per_sector = bytes_per_sector; fhc->eom_detected (eom_detected ()); diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 7f1688516..c6fe7cde3 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -2,7 +2,7 @@ capability class to the appropriate values. Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010 Red Hat, Inc. + 2009, 2010, 2011 Red Hat, Inc. This file is part of Cygwin. @@ -61,6 +61,7 @@ wincaps wincap_nt4sp4 __attribute__((section (".cygwin_dll_common"), shared)) = has_mwmo_inputavailable:false, has_buggy_thread_startup:false, has_fast_cwd:false, + has_restricted_raw_disk_access:false, }; wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -101,6 +102,7 @@ wincaps wincap_2000 __attribute__((section (".cygwin_dll_common"), shared)) = { has_mwmo_inputavailable:true, has_buggy_thread_startup:false, has_fast_cwd:false, + has_restricted_raw_disk_access:false, }; wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -141,6 +143,7 @@ wincaps wincap_2000sp4 __attribute__((section (".cygwin_dll_common"), shared)) = has_mwmo_inputavailable:true, has_buggy_thread_startup:false, has_fast_cwd:false, + has_restricted_raw_disk_access:false, }; wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -181,6 +184,7 @@ wincaps wincap_xp __attribute__((section (".cygwin_dll_common"), shared)) = { has_mwmo_inputavailable:true, has_buggy_thread_startup:false, has_fast_cwd:false, + has_restricted_raw_disk_access:false, }; wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -221,6 +225,7 @@ wincaps wincap_xpsp1 __attribute__((section (".cygwin_dll_common"), shared)) = { has_mwmo_inputavailable:true, has_buggy_thread_startup:false, has_fast_cwd:false, + has_restricted_raw_disk_access:false, }; wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -261,6 +266,7 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = { has_mwmo_inputavailable:true, has_buggy_thread_startup:false, has_fast_cwd:false, + has_restricted_raw_disk_access:false, }; wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -301,6 +307,7 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = { has_mwmo_inputavailable:true, has_buggy_thread_startup:false, has_fast_cwd:false, + has_restricted_raw_disk_access:false, }; wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -341,6 +348,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = { has_mwmo_inputavailable:true, has_buggy_thread_startup:true, has_fast_cwd:true, + has_restricted_raw_disk_access:true, }; wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { @@ -381,6 +389,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = { has_mwmo_inputavailable:true, has_buggy_thread_startup:false, has_fast_cwd:true, + has_restricted_raw_disk_access:true, }; wincapc wincap __attribute__((section (".cygwin_dll_common"), shared)); diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index decfc1e50..8a704b800 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -1,7 +1,7 @@ /* wincap.h: Header for OS capability class. Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010 Red Hat, Inc. + 2009, 2010, 2011 Red Hat, Inc. This file is part of Cygwin. @@ -51,6 +51,7 @@ struct wincaps unsigned has_mwmo_inputavailable : 1; unsigned has_buggy_thread_startup : 1; unsigned has_fast_cwd : 1; + unsigned has_restricted_raw_disk_access : 1; }; class wincapc @@ -107,6 +108,7 @@ public: bool IMPLEMENT (has_mwmo_inputavailable) bool IMPLEMENT (has_buggy_thread_startup) bool IMPLEMENT (has_fast_cwd) + bool IMPLEMENT (has_restricted_raw_disk_access) #undef IMPLEMENT };