From 95ff6fc6da3cccb2b50600a181c6f9dcb1333283 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 24 Oct 2013 09:41:17 +0000 Subject: * devices.in (dev_storage): Map /dev/zero and /dev/full to \Device\Null. * devices.cc: Regenerate. * dtable.h (struct dtable): Make fhandler_base friend, rather than fhandler_disk_file. * fhandler.cc (fhandler_base::open_with_arch): Create unique id. (fhandler_base::cleanup): Call del_my_locks. (fhandler_base::fcntl): Handle F_GETLK, F_SETLK and F_SETLKW. * fhandler.h (fhandler_base::get_dev): Return real device number. (fhandler_base::set_unique_id): New inline method. (fhandler_disk_file::lock): Drop declaration. (fhandler_disk_file::get_dev): New method, return pc.fs_serial_number. (fhandler_dev_zero::open): Drop declaration. * fhandler_disk_file.cc (fhandler_disk_file::close): Move del_my_locks call to fhandler_base::open_with_arch. (fhandler_disk_file::fcntl): Move handling of locking commands to fhandler_base::fcntl. (fhandler_base::open_fs): Drop call to NtAllocateLocallyUniqueId. * fhandler_zero.cc (fhandler_dev_zero::open): Remove so that default fhandler_base::open is used to open \Device\Null. * flock.cc (fixup_lockf_after_exec): Finding a single fhandler is enough here. (fhandler_base::lock): Replace fhandler_disk_file::lock. Refuse to lock nohandle devices. Handle read/write test using POSIX flags. Explain why. Never fail on SEEK_CUR or SEEK_END, rather assume position 0, just as Linux. * net.cc (fdsock): Create unique id. --- winsup/cygwin/ChangeLog | 29 +++++++++++++++ winsup/cygwin/devices.cc | 4 +-- winsup/cygwin/devices.in | 4 +-- winsup/cygwin/dtable.h | 2 +- winsup/cygwin/fhandler.cc | 19 ++++++++++ winsup/cygwin/fhandler.h | 6 ++-- winsup/cygwin/fhandler_disk_file.cc | 17 +-------- winsup/cygwin/fhandler_zero.cc | 11 +----- winsup/cygwin/flock.cc | 71 +++++++++++++++++++++---------------- winsup/cygwin/net.cc | 5 +++ winsup/cygwin/release/1.7.26 | 5 +++ 11 files changed, 109 insertions(+), 64 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 7e201e5d6..d7974ad96 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,32 @@ +2013-10-24 Corinna Vinschen + + * devices.in (dev_storage): Map /dev/zero and /dev/full to \Device\Null. + * devices.cc: Regenerate. + * dtable.h (struct dtable): Make fhandler_base friend, rather + than fhandler_disk_file. + * fhandler.cc (fhandler_base::open_with_arch): Create unique id. + (fhandler_base::cleanup): Call del_my_locks. + (fhandler_base::fcntl): Handle F_GETLK, F_SETLK and F_SETLKW. + * fhandler.h (fhandler_base::get_dev): Return real device number. + (fhandler_base::set_unique_id): New inline method. + (fhandler_disk_file::lock): Drop declaration. + (fhandler_disk_file::get_dev): New method, return pc.fs_serial_number. + (fhandler_dev_zero::open): Drop declaration. + * fhandler_disk_file.cc (fhandler_disk_file::close): Move + del_my_locks call to fhandler_base::open_with_arch. + (fhandler_disk_file::fcntl): Move handling of locking commands to + fhandler_base::fcntl. + (fhandler_base::open_fs): Drop call to NtAllocateLocallyUniqueId. + * fhandler_zero.cc (fhandler_dev_zero::open): Remove so that default + fhandler_base::open is used to open \Device\Null. + * flock.cc (fixup_lockf_after_exec): Finding a single fhandler is + enough here. + (fhandler_base::lock): Replace fhandler_disk_file::lock. Refuse to lock + nohandle devices. Handle read/write test using POSIX flags. Explain + why. Never fail on SEEK_CUR or SEEK_END, rather assume position 0, + just as Linux. + * net.cc (fdsock): Create unique id. + 2013-10-23 Corinna Vinschen * include /cygwin/config.h (_READ_WRITE_BUFSIZE_TYPE): Define. diff --git a/winsup/cygwin/devices.cc b/winsup/cygwin/devices.cc index 9f37ef827..fd2e7e16d 100644 --- a/winsup/cygwin/devices.cc +++ b/winsup/cygwin/devices.cc @@ -243,7 +243,7 @@ const _RDATA device dev_storage[] = {"/dev/fd13", BRACK(FHDEV(DEV_FLOPPY_MAJOR, 13)), "\\Device\\Floppy13", exists_ntdev, S_IFBLK, true}, {"/dev/fd14", BRACK(FHDEV(DEV_FLOPPY_MAJOR, 14)), "\\Device\\Floppy14", exists_ntdev, S_IFBLK, true}, {"/dev/fd15", BRACK(FHDEV(DEV_FLOPPY_MAJOR, 15)), "\\Device\\Floppy15", exists_ntdev, S_IFBLK, true}, - {"/dev/full", BRACK(FH_FULL), "/dev/full", exists, S_IFCHR, true}, + {"/dev/full", BRACK(FH_FULL), "\\Device\\Null", exists_ntdev, S_IFCHR, true}, {"/dev/kmsg", BRACK(FH_KMSG), "\\Device\\MailSlot\\cygwin\\dev\\kmsg", exists_ntdev, S_IFCHR, true}, {"/dev/nst0", BRACK(FHDEV(DEV_TAPE_MAJOR, 128)), "\\Device\\Tape0", exists_ntdev, S_IFBLK, true}, {"/dev/nst1", BRACK(FHDEV(DEV_TAPE_MAJOR, 129)), "\\Device\\Tape1", exists_ntdev, S_IFBLK, true}, @@ -2715,7 +2715,7 @@ const _RDATA device dev_storage[] = {"/dev/ttyS63", BRACK(FHDEV(DEV_SERIAL_MAJOR, 63)), "\\??\\COM64", exists_ntdev, S_IFCHR, true}, {"/dev/urandom", BRACK(FH_URANDOM), "/dev/urandom", exists, S_IFCHR, true}, {"/dev/windows", BRACK(FH_WINDOWS), "/dev/windows", exists, S_IFCHR, true}, - {"/dev/zero", BRACK(FH_ZERO), "/dev/zero", exists, S_IFCHR, true}, + {"/dev/zero", BRACK(FH_ZERO), "\\Device\\Null", exists_ntdev, S_IFCHR, true}, {":fifo", BRACK(FH_FIFO), "/dev/fifo", exists_internal, S_IFCHR, false}, {":pipe", BRACK(FH_PIPE), "/dev/pipe", exists_internal, S_IFCHR, false}, {":ptym0", BRACK(FHDEV(DEV_PTYM_MAJOR, 0)), "/dev/ptym0", exists_internal, S_IFCHR, false}, diff --git a/winsup/cygwin/devices.in b/winsup/cygwin/devices.in index 785aff0bf..ea26a5337 100644 --- a/winsup/cygwin/devices.in +++ b/winsup/cygwin/devices.in @@ -152,8 +152,8 @@ const device dev_error_storage = "/dev/conin", BRACK(FH_CONIN), "/dev/conin", exists_console, S_IFCHR "/dev/conout", BRACK(FH_CONOUT), "/dev/conout", exists_console, S_IFCHR "/dev/null", BRACK(FH_NULL), "\\Device\\Null", exists_ntdev, S_IFCHR -"/dev/zero", BRACK(FH_ZERO), "/dev/zero", exists, S_IFCHR -"/dev/full", BRACK(FH_FULL), "/dev/full", exists, S_IFCHR +"/dev/zero", BRACK(FH_ZERO), "\\Device\\Null", exists_ntdev, S_IFCHR +"/dev/full", BRACK(FH_FULL), "\\Device\\Null", exists_ntdev, S_IFCHR "/dev/random", BRACK(FH_RANDOM), "/dev/random", exists, S_IFCHR "/dev/urandom", BRACK(FH_URANDOM), "/dev/urandom", exists, S_IFCHR, =urandom_dev "/dev/clipboard", BRACK(FH_CLIPBOARD), "/dev/clipboard", exists, S_IFCHR diff --git a/winsup/cygwin/dtable.h b/winsup/cygwin/dtable.h index 5fae60523..5810e04fe 100644 --- a/winsup/cygwin/dtable.h +++ b/winsup/cygwin/dtable.h @@ -90,7 +90,7 @@ public: friend void dtable_init (); friend void __stdcall close_all_files (bool); friend int dup_finish (int, int, int); - friend class fhandler_disk_file; + friend class fhandler_base; friend class cygheap_fdmanip; friend class cygheap_fdget; friend class cygheap_fdnew; diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index 2c41f31ae..6e4539c72 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -498,6 +498,12 @@ fhandler_base::open_with_arch (int flags, mode_t mode) } close_on_exec (flags & O_CLOEXEC); + /* A unique ID is necessary to recognize fhandler entries which are + duplicated by dup(2) or fork(2). This is used in BSD flock calls + to identify the descriptor. Skip nohandle fhandlers since advisory + locking is unusable for those anyway. */ + if (!nohandle ()) + set_unique_id (); return res; } @@ -1112,6 +1118,10 @@ fhandler_base::close_with_arch () void fhandler_base::cleanup () { + /* Delete all POSIX locks on the file. Delete all flock locks on the + file if this is the last reference to this file. */ + if (unique_id) + del_my_locks (on_close); } int @@ -1366,6 +1376,15 @@ int fhandler_base::fcntl (int cmd, intptr_t arg) } res = 0; break; + case F_GETLK: + case F_SETLK: + case F_SETLKW: + { + struct flock *fl = (struct flock *) arg; + fl->l_type &= F_RDLCK | F_WRLCK | F_UNLCK; + res = mandatory_locking () ? mand_lock (cmd, fl) : lock (cmd, fl); + } + break; default: set_errno (EINVAL); res = -1; diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 73b5f4735..a0cdfa65c 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -296,7 +296,7 @@ class fhandler_base bool has_attribute (DWORD x) const {return pc.has_attribute (x);} const char *get_name () const { return pc.normalized_path; } const char *get_win32_name () { return pc.get_win32 (); } - dev_t get_dev () { return pc.fs_serial_number (); } + virtual dev_t get_dev () { return get_device (); } ino_t get_ino () { return ino ?: ino = hash_path_name (0, pc.get_nt_native_path ()); } long long get_unique_id () const { return unique_id; } /* Returns name used for /proc//fd in buf. */ @@ -312,6 +312,7 @@ class fhandler_base int open_with_arch (int, mode_t = 0); virtual int open (int, mode_t); virtual void open_setup (int flags) { return; } + void set_unique_id () { NtAllocateLocallyUniqueId ((PLUID) &unique_id); } int close_with_arch (); virtual int close (); @@ -979,7 +980,6 @@ class fhandler_disk_file: public fhandler_base int fcntl (int cmd, intptr_t); int dup (fhandler_base *child, int); void fixup_after_fork (HANDLE parent); - int lock (int, struct flock *); int mand_lock (int, struct flock *); bool isdevice () const { return false; } int __reg2 fstat (struct stat *buf); @@ -1012,6 +1012,7 @@ class fhandler_disk_file: public fhandler_base ssize_t __reg3 pwrite (void *, size_t, off_t); fhandler_disk_file (void *) {} + dev_t get_dev () { return pc.fs_serial_number (); } void copyto (fhandler_base *x) { @@ -1618,7 +1619,6 @@ class fhandler_dev_zero: public fhandler_base { public: fhandler_dev_zero (); - int open (int flags, mode_t mode = 0); ssize_t __stdcall write (const void *ptr, size_t len); void __reg3 read (void *ptr, size_t& len); off_t lseek (off_t offset, int whence); diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index fe321cda0..32f02bd5f 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -1401,9 +1401,6 @@ fhandler_disk_file::close () /* Close extra pread/pwrite handle, if it exists. */ if (prw_handle) NtClose (prw_handle); - /* Delete all POSIX locks on the file. Delete all flock locks on the - file if this is the last reference to this file. */ - del_my_locks (on_close); return fhandler_base::close (); } @@ -1414,20 +1411,11 @@ fhandler_disk_file::fcntl (int cmd, intptr_t arg) switch (cmd) { - case F_LCK_MANDATORY: + case F_LCK_MANDATORY: /* Mandatory locking only works on files. */ mandatory_locking (!!arg); need_fork_fixup (true); res = 0; break; - case F_GETLK: - case F_SETLK: - case F_SETLKW: - { - struct flock *fl = (struct flock *) arg; - fl->l_type &= F_RDLCK | F_WRLCK | F_UNLCK; - res = mandatory_locking () ? mand_lock (cmd, fl) : lock (cmd, fl); - } - break; default: res = fhandler_base::fcntl (cmd, arg); break; @@ -1487,9 +1475,6 @@ fhandler_base::open_fs (int flags, mode_t mode) } ino = pc.get_ino_by_handle (get_handle ()); - /* A unique ID is necessary to recognize fhandler entries which are - duplicated by dup(2) or fork(2). */ - NtAllocateLocallyUniqueId ((PLUID) &unique_id); out: syscall_printf ("%d = fhandler_disk_file::open(%S, %y)", res, diff --git a/winsup/cygwin/fhandler_zero.cc b/winsup/cygwin/fhandler_zero.cc index 1fd874614..03319a7dd 100644 --- a/winsup/cygwin/fhandler_zero.cc +++ b/winsup/cygwin/fhandler_zero.cc @@ -1,6 +1,6 @@ /* fhandler_dev_zero.cc: code to access /dev/zero - Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 Red Hat, Inc. + Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009, 2013 Red Hat, Inc. Written by DJ Delorie (dj@cygnus.com) @@ -21,15 +21,6 @@ fhandler_dev_zero::fhandler_dev_zero () { } -int -fhandler_dev_zero::open (int flags, mode_t) -{ - set_flags ((flags & ~O_TEXT) | O_BINARY); - nohandle (true); - set_open_status (); - return 1; -} - ssize_t __stdcall fhandler_dev_zero::write (const void *, size_t len) { diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 33f16af06..0cb2274d0 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -454,7 +454,7 @@ fixup_lockf_after_exec () while (cfd.next () >= 0) if (cfd->get_dev () == node->i_dev && cfd->get_ino () == node->i_ino - && ++cnt > 1) + && ++cnt >= 1) break; if (cnt == 0) { @@ -919,14 +919,7 @@ static void lf_wakelock (lockf_t *, HANDLE); of mandatory locks using the Windows mandatory locking functions, see the fhandler_disk_file::mand_lock method at the end of this file. */ int -fhandler_base::lock (int, struct flock *) -{ - set_errno (EINVAL); - return -1; -} - -int -fhandler_disk_file::lock (int a_op, struct flock *fl) +fhandler_base::lock (int a_op, struct flock *fl) { off_t start, end, oadd; int error = 0; @@ -934,6 +927,13 @@ fhandler_disk_file::lock (int a_op, struct flock *fl) short a_flags = fl->l_type & (F_POSIX | F_FLOCK); short type = fl->l_type & (F_RDLCK | F_WRLCK | F_UNLCK); + if (nohandle ()) + { + set_errno (EINVAL); + debug_printf ("Locking on nohandle device, return EINVAL."); + return -1; + } + if (!a_flags) a_flags = F_POSIX; /* default */ if (a_op == F_SETLKW) @@ -952,16 +952,24 @@ fhandler_disk_file::lock (int a_op, struct flock *fl) been opened with a specific open mode, in contrast to POSIX locks which require that a file is opened for reading to place a read lock and opened for writing to place a write lock. */ - if ((a_flags & F_POSIX) && !(get_access () & GENERIC_READ)) + /* CV 2013-10-22: Test POSIX R/W mode flags rather than Windows R/W + access flags. The reason is that POSIX mode flags are set for + all types of fhandlers, while Windows access flags are only set + for most of the actual Windows device backed fhandlers. */ + if ((a_flags & F_POSIX) + && ((get_flags () & O_ACCMODE) == O_WRONLY)) { + system_printf ("get_access() == %x", get_access ()); set_errno (EBADF); return -1; } break; case F_WRLCK: /* See above comment. */ - if ((a_flags & F_POSIX) && !(get_access () & GENERIC_WRITE)) + if ((a_flags & F_POSIX) + && ((get_flags () & O_ACCMODE) == O_RDONLY)) { + system_printf ("get_access() == %x", get_access ()); set_errno (EBADF); return -1; } @@ -982,29 +990,32 @@ fhandler_disk_file::lock (int a_op, struct flock *fl) case SEEK_CUR: if ((start = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK) - return -1; + start = 0; break; case SEEK_END: - { - NTSTATUS status; - IO_STATUS_BLOCK io; - FILE_STANDARD_INFORMATION fsi; + if (get_device () != FH_FS) + start = 0; + else + { + NTSTATUS status; + IO_STATUS_BLOCK io; + FILE_STANDARD_INFORMATION fsi; - status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi, - FileStandardInformation); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - return -1; - } - if (fl->l_start > 0 && fsi.EndOfFile.QuadPart > OFF_MAX - fl->l_start) - { - set_errno (EOVERFLOW); - return -1; - } - start = fsi.EndOfFile.QuadPart + fl->l_start; - } + status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi, + FileStandardInformation); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + return -1; + } + if (fl->l_start > 0 && fsi.EndOfFile.QuadPart > OFF_MAX - fl->l_start) + { + set_errno (EOVERFLOW); + return -1; + } + start = fsi.EndOfFile.QuadPart + fl->l_start; + } break; default: diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index 053c66718..e81de79c1 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -636,6 +636,11 @@ fdsock (cygheap_fdmanip& fd, const device *dev, SOCKET soc) system_printf ("getsockopt(SO_SNDBUF) failed, %u", WSAGetLastError ()); } + /* A unique ID is necessary to recognize fhandler entries which are + duplicated by dup(2) or fork(2). This is used in BSD flock calls + to identify the descriptor. */ + ((fhandler_socket *) fd)->set_unique_id (); + return true; } diff --git a/winsup/cygwin/release/1.7.26 b/winsup/cygwin/release/1.7.26 index 378385527..3656715fa 100644 --- a/winsup/cygwin/release/1.7.26 +++ b/winsup/cygwin/release/1.7.26 @@ -7,6 +7,11 @@ What changed: - Slightly improve randomness of /dev/random emulation. +- Allow to use advisory locking on any device which is backed by an OS handle. + Right now this excludes /dev/clipboard, /dev/dsp, /dev/random, /dev/urandom, + as well as almost all virtual files under /proc. + + Bug fixes: ---------- -- cgit v1.2.3