diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 51ebe5489..7bd689c3c 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,48 @@ +2014-08-21 Corinna Vinschen + + * Throughout, use __try/__except/__endtry blocks, rather than myfault + handler. + * cygtls.cc (_cygtls::remove): Accommodate the fact that pathbufs + has been moved from _local_storage to _cygtls. + * cygtls.h (class tls_pathbuf): Add comment to hint to gendef usage + of counters. Change type of counters to uint32_t for clarity. + Remove _cygtls as friend class. + (struct _local_storage): Move pathbufs from here... + (struct _cygtls): ...to here, allowing to access it from _sigbe. + (class san): Only define on 32 bit. Remove errno, _c_cnt and _w_cnt + members. + (san::setup): Drop parameter. Don't initialize removed members. + (san::leave): Don't set removed members. + (class myfault): Only define on 32 bit. + (myfault::faulted): Only keep implementation not taking any parameter. + Drop argument in call to sebastian.setup. + (__try/__leave/__except/__endtry): Implement to support real SEH. For + now stick to SJLJ on 32 bit. + * dcrt0.cc (dll_crt0_0): Drop 64 bit call to + exception::install_myfault_handler. + * exception.h (exception_handler): Define with EXCEPTION_DISPOSITION + as return type. + (PDISPATCHER_CONTEXT): Define as void * on 32 bit. Define as pointer + to _DISPATCHER_CONTEXT on 64 bit. + (class exception): Define separately for 32 and 64 bit. + (exception::myfault): Add handler for myfault SEH handling on 64 bit. + (exception::exception): Fix mangled method name to account for change + in type of last parameter. + (exception::install_myfault_handler): Remove. + * exceptions.cc (exception::myfault_handle): Remove. + (exception::myfault): New SEH handler for 64 bit. + * gendef (_sigbe): Set tls_pathbuf counters to 0 explicitely when + returning to the caller. + * ntdll.h: Move a comment to a better place. + (struct _SCOPE_TABLE): Define on 64 bit. + * thread.cc (verifyable_object_isvalid): Remove gcc 4.7 workaround. + * tls_pbuf.cc (tls_pbuf): Fix to accommodate new place of pathbufs. + (tls_pathbuf::destroy): Change type of loop variables to uint32_t. + * tls_pbuf.h (class tmp_pathbuf): Change type of buffer counters to + uint32_t. Accommodate new place of pathbufs. + * tlsoffsets.h: Regenerate. + * tlsoffsets64.h: Regenerate. + 2014-08-21 Corinna Vinschen * miscfuncs.cc (__import_address): Cover the first dereference to imp diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc index 1ccbbaf5f..067aa68dd 100644 --- a/winsup/cygwin/cygheap.cc +++ b/winsup/cygwin/cygheap.cc @@ -638,10 +638,7 @@ init_cygheap::find_tls (int sig, bool& issig_wait) _cygtls *t = NULL; issig_wait = false; - myfault efault; - if (efault.faulted ()) - threadlist[ix]->remove (INFINITE); - else + __try { ix = -1; /* Scan thread list looking for valid signal-delivery candidates */ @@ -652,11 +649,15 @@ init_cygheap::find_tls (int sig, bool& issig_wait) { t = cygheap->threadlist[ix]; issig_wait = true; - goto out; + __leave; } else if (!t && !sigismember (&(threadlist[ix]->sigmask), sig)) t = cygheap->threadlist[ix]; } -out: + __except (NO_ERROR) + { + threadlist[ix]->remove (INFINITE); + } + __endtry return t; } diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 5cc9405eb..234882130 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -193,7 +193,7 @@ _cygtls::remove (DWORD wait) free_local (servent_buf); free_local (hostent_buf); /* Free temporary TLS path buffers. */ - locals.pathbufs.destroy (); + pathbufs.destroy (); /* Close timer handle. */ if (locals.cw_timer) NtClose (locals.cw_timer); diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h index 32838744d..c05c19563 100644 --- a/winsup/cygwin/cygtls.h +++ b/winsup/cygwin/cygtls.h @@ -44,18 +44,21 @@ details. */ #else #pragma pack(push,4) #endif + /* Defined here to support auto rebuild of tlsoffsets.h. */ class tls_pathbuf { - int c_cnt; - int w_cnt; + /* Make sure that c_cnt and w_cnt are always the first two members of this + class, and never change the size (32 bit), unless you also change the + mov statements in sigbe! */ + uint32_t c_cnt; + uint32_t w_cnt; char *c_buf[TP_NUM_C_BUFS]; WCHAR *w_buf[TP_NUM_W_BUFS]; public: void destroy (); friend class tmp_pathbuf; - friend class _cygtls; friend class san; }; @@ -129,8 +132,6 @@ struct _local_storage /* thread.cc */ HANDLE cw_timer; - /* All functions requiring temporary path buffers. */ - tls_pathbuf pathbufs; char ttybuf[32]; }; @@ -188,6 +189,7 @@ public: struct pthread *tid; class cygthread *_ctinfo; class san *andreas; + tls_pathbuf pathbufs; waitq wq; int sig; unsigned incyg; @@ -281,34 +283,25 @@ const int CYGTLS_PADSIZE = 12700; extern PVOID _tlsbase __asm__ ("%fs:4"); extern PVOID _tlstop __asm__ ("%fs:8"); #endif + #define _my_tls (*((_cygtls *) ((char *)_tlsbase - CYGTLS_PADSIZE))) extern _cygtls *_main_tls; extern _cygtls *_sig_tls; +#ifndef __x86_64__ class san { san *_clemente; jmp_buf _context; - int _errno; - unsigned _c_cnt; - unsigned _w_cnt; public: - int setup (int myerrno = 0) __attribute__ ((always_inline)) + int setup () __attribute__ ((always_inline)) { _clemente = _my_tls.andreas; _my_tls.andreas = this; - _errno = myerrno; - _c_cnt = _my_tls.locals.pathbufs.c_cnt; - _w_cnt = _my_tls.locals.pathbufs.w_cnt; return __sjfault (_context); } void leave () __attribute__ ((always_inline)) { - if (_errno) - set_errno (_errno); - /* Restore tls_pathbuf counters in case of error. */ - _my_tls.locals.pathbufs.c_cnt = _c_cnt; - _my_tls.locals.pathbufs.w_cnt = _w_cnt; __ljfault (_context, 1); } void reset () __attribute__ ((always_inline)) @@ -324,17 +317,73 @@ public: ~myfault () __attribute__ ((always_inline)) { sebastian.reset (); } inline int faulted () __attribute__ ((always_inline)) { - return sebastian.setup (0); - } - inline int faulted (void const *obj, int myerrno = 0) __attribute__ ((always_inline)) - { - return !obj || !(*(const char **) obj) || sebastian.setup (myerrno); - } - inline int faulted (int myerrno) __attribute__ ((always_inline)) - { - return sebastian.setup (myerrno); + return sebastian.setup (); } }; +#endif + +/* Exception handling macros. These are required because SEH differs a lot + between 32 and 64 bit. Essentially, on 64 bit, we have to create compile + time SEH tables which define the handler and try/except labels, while on + 32 bit we can simply set up an SJLJ handler within the myfault class. */ +#define __mem_barrier __asm__ __volatile__ ("" ::: "memory") +#ifdef __x86_64__ +#define __try \ + { \ + __label__ __l_try, __l_except, __l_endtry; \ + __mem_barrier; \ + __asm__ goto ("\n" \ + " .seh_handler _ZN9exception7myfaultEP17_EXCEPTION_RECORDPvP8_CONTEXTP19_DISPATCHER_CONTEXT, @except \n" \ + " .seh_handlerdata \n" \ + " .long 1 \n" \ + " .rva %l[__l_try],%l[__l_endtry],%l[__l_except],%l[__l_except] \n" \ + " .seh_code \n" \ + : : : : __l_try, __l_endtry, __l_except); \ + { \ + __l_try: \ + __mem_barrier; + +#define __leave \ + goto __l_endtry + +#define __except(__errno) \ + goto __l_endtry; \ + } \ + { \ + __l_except: \ + __mem_barrier; \ + if (__errno) \ + set_errno (__errno); + +#define __endtry \ + } \ + __l_endtry: \ + __mem_barrier; \ + } + +#else /* !__x86_64__ */ +#define __try \ + { \ + myfault efault; \ + if (!efault.faulted ()) \ + { + +#define __leave \ + goto __l_endtry + +#define __except(__errno) \ + goto __l_endtry; \ + } \ + { \ + if (__errno) \ + set_errno (__errno); + +#define __endtry \ + } \ + __l_endtry: \ + __mem_barrier; \ + } +#endif /* __x86_64__ */ class set_signal_arrived { diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 5150107e8..02c0ad11d 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -796,10 +796,6 @@ dll_crt0_0 () _main_tls = &_my_tls; -#ifdef __x86_64__ - exception::install_myfault_handler (); -#endif - /* Initialize signal processing here, early, in the hopes that the creation of a thread early in the process will cause more predictability in memory layout for the main thread. */ diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index bdc1a859b..a8eeb2327 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -28,16 +28,16 @@ details. */ extern "C" int dirfd (DIR *dir) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (dir->__d_cookie != __DIRENT_COOKIE) + __try { - set_errno (EINVAL); + if (dir->__d_cookie == __DIRENT_COOKIE) + return dir->__d_fd; syscall_printf ("-1 = dirfd (%p)", dir); - return -1; + set_errno (EINVAL); } - return dir->__d_fd; + __except (EFAULT) {} + __endtry + return -1; } /* Symbol kept for backward compatibility. Don't remove. Don't declare @@ -93,79 +93,86 @@ fdopendir (int fd) static int readdir_worker (DIR *dir, dirent *de) { - myfault efault; - if (efault.faulted ()) - return EFAULT; + int res = 0; - if (dir->__d_cookie != __DIRENT_COOKIE) + __try { - syscall_printf ("%p = readdir (%p)", NULL, dir); - return EBADF; - } - - de->d_ino = 0; - de->d_type = DT_UNKNOWN; - memset (&de->__d_unused1, 0, sizeof (de->__d_unused1)); - - int res = ((fhandler_base *) dir->__fh)->readdir (dir, de); - - if (res == ENMFILE) - { - if (!(dir->__flags & dirent_saw_dot)) + if (dir->__d_cookie != __DIRENT_COOKIE) { - strcpy (de->d_name, "."); - dir->__flags |= dirent_saw_dot; - dir->__d_position++; - res = 0; - } - else if (!(dir->__flags & dirent_saw_dot_dot)) - { - strcpy (de->d_name, ".."); - dir->__flags |= dirent_saw_dot_dot; - dir->__d_position++; - res = 0; - } - } - - if (!res && !de->d_ino) - { - bool is_dot = false; - bool is_dot_dot = false; - - if (de->d_name[0] == '.') - { - if (de->d_name[1] == '\0') - is_dot = true; - else if (de->d_name[1] == '.' && de->d_name[2] == '\0') - is_dot_dot = true; + syscall_printf ("%p = readdir (%p)", NULL, dir); + res = EBADF; + __leave; } - if (is_dot_dot && !(dir->__flags & dirent_isroot)) - de->d_ino = readdir_get_ino (((fhandler_base *) dir->__fh)->get_name (), - true); - else + de->d_ino = 0; + de->d_type = DT_UNKNOWN; + memset (&de->__d_unused1, 0, sizeof (de->__d_unused1)); + + res = ((fhandler_base *) dir->__fh)->readdir (dir, de); + + if (res == ENMFILE) { - /* Compute d_ino by combining filename hash with directory hash. */ - de->d_ino = ((fhandler_base *) dir->__fh)->get_ino (); - if (!is_dot && !is_dot_dot) + if (!(dir->__flags & dirent_saw_dot)) { - PUNICODE_STRING w32name = - ((fhandler_base *) dir->__fh)->pc.get_nt_native_path (); - DWORD devn = ((fhandler_base *) dir->__fh)->get_device (); - /* Paths below /proc don't have a Win32 pendant. */ - if (isproc_dev (devn)) - de->d_ino = hash_path_name (de->d_ino, L"/"); - else if (w32name->Buffer[w32name->Length / sizeof (WCHAR) - 1] - != L'\\') - de->d_ino = hash_path_name (de->d_ino, L"\\"); - de->d_ino = hash_path_name (de->d_ino, de->d_name); + strcpy (de->d_name, "."); + dir->__flags |= dirent_saw_dot; + dir->__d_position++; + res = 0; + } + else if (!(dir->__flags & dirent_saw_dot_dot)) + { + strcpy (de->d_name, ".."); + dir->__flags |= dirent_saw_dot_dot; + dir->__d_position++; + res = 0; } } - } - /* This fills out the old 32 bit d_ino field for old applications, - build under Cygwin before 1.5.x. */ - de->__d_internal1 = de->d_ino; + if (!res && !de->d_ino) + { + bool is_dot = false; + bool is_dot_dot = false; + + if (de->d_name[0] == '.') + { + if (de->d_name[1] == '\0') + is_dot = true; + else if (de->d_name[1] == '.' && de->d_name[2] == '\0') + is_dot_dot = true; + } + + if (is_dot_dot && !(dir->__flags & dirent_isroot)) + de->d_ino = readdir_get_ino (((fhandler_base *) + dir->__fh)->get_name (), + true); + else + { + /* Compute d_ino by combining filename hash with directory hash. */ + de->d_ino = ((fhandler_base *) dir->__fh)->get_ino (); + if (!is_dot && !is_dot_dot) + { + PUNICODE_STRING w32name = + ((fhandler_base *) dir->__fh)->pc.get_nt_native_path (); + DWORD devn = ((fhandler_base *) dir->__fh)->get_device (); + /* Paths below /proc don't have a Win32 pendant. */ + if (isproc_dev (devn)) + de->d_ino = hash_path_name (de->d_ino, L"/"); + else if (w32name->Buffer[w32name->Length / sizeof (WCHAR) - 1] + != L'\\') + de->d_ino = hash_path_name (de->d_ino, L"\\"); + de->d_ino = hash_path_name (de->d_ino, de->d_name); + } + } + } + /* This fills out the old 32 bit d_ino field for old applications, + build under Cygwin before 1.5.x. */ + de->__d_internal1 = de->d_ino; + } + __except (NO_ERROR) + { + res = EFAULT; + } + __endtry return res; } @@ -200,16 +207,15 @@ readdir_r (DIR *__restrict dir, dirent *__restrict de, dirent **__restrict ode) extern "C" long telldir (DIR *dir) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - if (dir->__d_cookie != __DIRENT_COOKIE) + __try { + if (dir->__d_cookie == __DIRENT_COOKIE) + return ((fhandler_base *) dir->__fh)->telldir (dir); set_errno (EBADF); - return -1; } - return ((fhandler_base *) dir->__fh)->telldir (dir); + __except (EFAULT) {} + __endtry + return -1; } /* telldir was never defined using off_t in POSIX, only in early versions @@ -225,14 +231,17 @@ telldir64 (DIR *dir) extern "C" void seekdir (DIR *dir, long loc) { - myfault efault; - if (efault.faulted (EFAULT)) - return; - - if (dir->__d_cookie != __DIRENT_COOKIE) - return; - dir->__flags &= dirent_info_mask; - return ((fhandler_base *) dir->__fh)->seekdir (dir, loc); + __try + { + if (dir->__d_cookie == __DIRENT_COOKIE) + { + dir->__flags &= dirent_info_mask; + ((fhandler_base *) dir->__fh)->seekdir (dir, loc); + } + set_errno (EINVAL); /* Diagnosis */ + } + __except (EFAULT) {} + __endtry } /* seekdir was never defined using off_t in POSIX, only in early versions @@ -248,42 +257,45 @@ seekdir64 (DIR *dir, off_t loc) extern "C" void rewinddir (DIR *dir) { - myfault efault; - if (efault.faulted (EFAULT)) - return; - - if (dir->__d_cookie != __DIRENT_COOKIE) - return; - dir->__flags &= dirent_info_mask; - return ((fhandler_base *) dir->__fh)->rewinddir (dir); + __try + { + if (dir->__d_cookie == __DIRENT_COOKIE) + { + dir->__flags &= dirent_info_mask; + ((fhandler_base *) dir->__fh)->rewinddir (dir); + } + set_errno (EINVAL); /* Diagnosis */ + } + __except (EFAULT) {} + __endtry } /* closedir: POSIX 5.1.2.1 */ extern "C" int closedir (DIR *dir) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - if (dir->__d_cookie != __DIRENT_COOKIE) + __try { + if (dir->__d_cookie == __DIRENT_COOKIE) + { + /* Reset the marker in case the caller tries to use `dir' again. */ + dir->__d_cookie = 0; + + int res = ((fhandler_base *) dir->__fh)->closedir (dir); + + close (dir->__d_fd); + free (dir->__d_dirname); + free (dir->__d_dirent); + free (dir); + syscall_printf ("%R = closedir(%p)", res, dir); + return res; + } set_errno (EBADF); - syscall_printf ("%R = closedir(%p)", -1, dir); - return -1; } - - /* Reset the marker in case the caller tries to use `dir' again. */ - dir->__d_cookie = 0; - - int res = ((fhandler_base *) dir->__fh)->closedir (dir); - - close (dir->__d_fd); - free (dir->__d_dirname); - free (dir->__d_dirent); - free (dir); - syscall_printf ("%R = closedir(%p)", res, dir); - return res; + __except (EFAULT) {} + __endtry + syscall_printf ("%R = closedir(%p)", -1, dir); + return -1; } /* mkdir: POSIX 5.4.1.1 */ @@ -294,43 +306,42 @@ mkdir (const char *dir, mode_t mode) fhandler_base *fh = NULL; tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - /* POSIX says mkdir("symlink-to-missing/") should create the - directory "missing", but Linux rejects it with EEXIST. Copy - Linux behavior for now. */ - - if (!*dir) + __try { - set_errno (ENOENT); - goto done; - } - if (isdirsep (dir[strlen (dir) - 1])) - { - /* This converts // to /, but since both give EEXIST, we're okay. */ - char *buf; - char *p = stpcpy (buf = tp.c_get (), dir) - 1; - dir = buf; - while (p > dir && isdirsep (*p)) - *p-- = '\0'; - } - if (!(fh = build_fh_name (dir, PC_SYM_NOFOLLOW))) - goto done; /* errno already set */; + /* POSIX says mkdir("symlink-to-missing/") should create the + directory "missing", but Linux rejects it with EEXIST. Copy + Linux behavior for now. */ - if (fh->error ()) - { - debug_printf ("got %d error from build_fh_name", fh->error ()); - set_errno (fh->error ()); - } - else if (has_dot_last_component (dir, true)) - set_errno (fh->exists () ? EEXIST : ENOENT); - else if (!fh->mkdir (mode)) - res = 0; - delete fh; + if (!*dir) + { + set_errno (ENOENT); + __leave; + } + if (isdirsep (dir[strlen (dir) - 1])) + { + /* This converts // to /, but since both give EEXIST, we're okay. */ + char *buf; + char *p = stpcpy (buf = tp.c_get (), dir) - 1; + dir = buf; + while (p > dir && isdirsep (*p)) + *p-- = '\0'; + } + if (!(fh = build_fh_name (dir, PC_SYM_NOFOLLOW))) + __leave; /* errno already set */; - done: + if (fh->error ()) + { + debug_printf ("got %d error from build_fh_name", fh->error ()); + set_errno (fh->error ()); + } + else if (has_dot_last_component (dir, true)) + set_errno (fh->exists () ? EEXIST : ENOENT); + else if (!fh->mkdir (mode)) + res = 0; + delete fh; + } + __except (EFAULT) {} + __endtry syscall_printf ("%R = mkdir(%s, %d)", res, dir, mode); return res; } @@ -342,30 +353,28 @@ rmdir (const char *dir) int res = -1; fhandler_base *fh = NULL; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - if (!(fh = build_fh_name (dir, PC_SYM_NOFOLLOW))) - goto done; /* errno already set */; - - if (fh->error ()) + __try { - debug_printf ("got %d error from build_fh_name", fh->error ()); - set_errno (fh->error ()); + if (!(fh = build_fh_name (dir, PC_SYM_NOFOLLOW))) + __leave; /* errno already set */; + + if (fh->error ()) + { + debug_printf ("got %d error from build_fh_name", fh->error ()); + set_errno (fh->error ()); + } + else if (!fh->exists ()) + set_errno (ENOENT); + else if (has_dot_last_component (dir, false)) + set_errno (EINVAL); + else if (isdev_dev (fh->dev ())) + set_errno (ENOTEMPTY); + else if (!fh->rmdir ()) + res = 0; + delete fh; } - else if (!fh->exists ()) - set_errno (ENOENT); - else if (has_dot_last_component (dir, false)) - set_errno (EINVAL); - else if (isdev_dev (fh->dev ())) - set_errno (ENOTEMPTY); - else if (!fh->rmdir ()) - res = 0; - - delete fh; - - done: + __except (EFAULT) {} + __endtry syscall_printf ("%R = rmdir(%s)", res, dir); return res; } diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index f56d19517..817439b0a 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -2,7 +2,7 @@ process's environment. Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc. + 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for @@ -664,19 +664,22 @@ _addenv (const char *name, const char *value, int overwrite) extern "C" int putenv (char *str) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (*str) + __try { - char *eq = strchr (str, '='); - if (eq) - return _addenv (str, eq + 1, -1); + if (*str) + { + char *eq = strchr (str, '='); + if (eq) + return _addenv (str, eq + 1, -1); - /* Remove str from the environment. */ - unsetenv (str); + /* Remove str from the environment. */ + unsetenv (str); + } + return 0; } - return 0; + __except (EFAULT) {} + __endtry + return -1; } /* Set the value of the environment variable "name" to be @@ -684,15 +687,18 @@ putenv (char *str) extern "C" int setenv (const char *name, const char *value, int overwrite) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (!name || !*name || strchr (name, '=')) + __try { - set_errno (EINVAL); - return -1; + if (!name || !*name || strchr (name, '=')) + { + set_errno (EINVAL); + __leave; + } + return _addenv (name, value, !!overwrite); } - return _addenv (name, value, !!overwrite); + __except (EFAULT) {} + __endtry + return -1; } /* Delete environment variable "name". */ @@ -701,22 +707,26 @@ unsetenv (const char *name) { register char **e; int offset; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (!name || *name == '\0' || strchr (name, '=')) + + __try { - set_errno (EINVAL); - return -1; + if (!name || *name == '\0' || strchr (name, '=')) + { + set_errno (EINVAL); + __leave; + } + + while (my_findenv (name, &offset)) /* if set multiple times */ + /* Move up the rest of the array */ + for (e = cur_environ () + offset; ; e++) + if (!(*e = *(e + 1))) + break; + + return 0; } - - while (my_findenv (name, &offset)) /* if set multiple times */ - /* Move up the rest of the array */ - for (e = cur_environ () + offset; ; e++) - if (!(*e = *(e + 1))) - break; - - return 0; + __except (EFAULT) {} + __endtry + return -1; } /* Minimal list of Windows vars which must be converted to uppercase. @@ -822,96 +832,101 @@ environ_init (char **envp, int envc) bool envp_passed_in; bool got_something_from_registry; static char NO_COPY cygterm[] = "TERM=cygwin"; - myfault efault; tmp_pathbuf tp; - if (efault.faulted ()) - api_fatal ("internal error reading the windows environment - too many environment variables?"); - - char *tmpbuf = tp.t_get (); - got_something_from_registry = regopt (L"default", tmpbuf); - if (myself->progname[0]) - got_something_from_registry = regopt (myself->progname, tmpbuf) - || got_something_from_registry; - - if (!envp) - envp_passed_in = 0; - else + __try { - envc++; - envc *= sizeof (char *); - char **newenv = (char **) malloc (envc); - memcpy (newenv, envp, envc); - cfree (envp); + char *tmpbuf = tp.t_get (); + got_something_from_registry = regopt (L"default", tmpbuf); + if (myself->progname[0]) + got_something_from_registry = regopt (myself->progname, tmpbuf) + || got_something_from_registry; - /* Older applications relied on the fact that cygwin malloced elements of the - environment list. */ - envp = newenv; - if (ENVMALLOC) - for (char **e = newenv; *e; e++) - { - char *p = *e; - *e = strdup (p); - cfree (p); - } - envp_passed_in = 1; - goto out; + if (!envp) + envp_passed_in = 0; + else + { + envc++; + envc *= sizeof (char *); + char **newenv = (char **) malloc (envc); + memcpy (newenv, envp, envc); + cfree (envp); + + /* Older applications relied on the fact that cygwin malloced elements of the + environment list. */ + envp = newenv; + if (ENVMALLOC) + for (char **e = newenv; *e; e++) + { + char *p = *e; + *e = strdup (p); + cfree (p); + } + envp_passed_in = 1; + goto out; + } + + /* Allocate space for environment + trailing NULL + CYGWIN env. */ + lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *)); + + rawenv = GetEnvironmentStringsW (); + if (!rawenv) + { + system_printf ("GetEnvironmentStrings returned NULL, %E"); + return; + } + debug_printf ("GetEnvironmentStrings returned %p", rawenv); + + /* Current directory information is recorded as variables of the + form "=X:=X:\foo\bar; these must be changed into something legal + (we could just ignore them but maybe an application will + eventually want to use them). */ + for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++) + { + sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w); + if (i >= envc) + envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *)); + envp[i] = newp; + if (*newp == '=') + *newp = '!'; + char *eq = strchrnul (newp, '='); + ucenv (newp, eq); /* uppercase env vars which need it */ + if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0) + sawTERM = 1; + else if (*newp == 'C' && strncmp (newp, "CYGWIN=", 7) == 0) + parse_options (newp + 7); + if (*eq) + posify_maybe (envp + i, *++eq ? eq : --eq, tmpbuf); + debug_printf ("%p: %s", envp[i], envp[i]); + } + + if (!sawTERM) + envp[i++] = strdup (cygterm); + envp[i] = NULL; + FreeEnvironmentStringsW (rawenv); + + out: + findenv_func = (char * (*)(const char*, int*)) my_findenv; + __cygwin_environ = envp; + update_envptrs (); + if (envp_passed_in) + { + p = getenv ("CYGWIN"); + if (p) + parse_options (p); + } + + if (got_something_from_registry) + parse_options (NULL); /* possibly export registry settings to + environment */ + MALLOC_CHECK; } - - /* Allocate space for environment + trailing NULL + CYGWIN env. */ - lastenviron = envp = (char **) malloc ((4 + (envc = 100)) * sizeof (char *)); - - rawenv = GetEnvironmentStringsW (); - if (!rawenv) + __except (NO_ERROR) { - system_printf ("GetEnvironmentStrings returned NULL, %E"); - return; + api_fatal ("internal error reading the windows environment " + "- too many environment variables?"); } - debug_printf ("GetEnvironmentStrings returned %p", rawenv); - - /* Current directory information is recorded as variables of the - form "=X:=X:\foo\bar; these must be changed into something legal - (we could just ignore them but maybe an application will - eventually want to use them). */ - for (i = 0, w = rawenv; *w != L'\0'; w = wcschr (w, L'\0') + 1, i++) - { - sys_wcstombs_alloc (&newp, HEAP_NOTHEAP, w); - if (i >= envc) - envp = (char **) realloc (envp, (4 + (envc += 100)) * sizeof (char *)); - envp[i] = newp; - if (*newp == '=') - *newp = '!'; - char *eq = strchrnul (newp, '='); - ucenv (newp, eq); /* uppercase env vars which need it */ - if (*newp == 'T' && strncmp (newp, "TERM=", 5) == 0) - sawTERM = 1; - else if (*newp == 'C' && strncmp (newp, "CYGWIN=", 7) == 0) - parse_options (newp + 7); - if (*eq) - posify_maybe (envp + i, *++eq ? eq : --eq, tmpbuf); - debug_printf ("%p: %s", envp[i], envp[i]); - } - - if (!sawTERM) - envp[i++] = strdup (cygterm); - envp[i] = NULL; - FreeEnvironmentStringsW (rawenv); - -out: - findenv_func = (char * (*)(const char*, int*)) my_findenv; - __cygwin_environ = envp; - update_envptrs (); - if (envp_passed_in) - { - p = getenv ("CYGWIN"); - if (p) - parse_options (p); - } - - if (got_something_from_registry) - parse_options (NULL); /* possibly export registry settings to - environment */ - MALLOC_CHECK; + __endtry } /* Function called by qsort to sort environment strings. */ diff --git a/winsup/cygwin/exception.h b/winsup/cygwin/exception.h index 83cb21fcf..9e34799fe 100644 --- a/winsup/cygwin/exception.h +++ b/winsup/cygwin/exception.h @@ -94,8 +94,10 @@ to install your own exception filter. This one is documented. a teensy bit of detail of the innards of exception handling (i.e. what we have to do). */ -typedef int (exception_handler) (EXCEPTION_RECORD *, struct _exception_list *, - CONTEXT *, void *); +typedef EXCEPTION_DISPOSITION (exception_handler) (EXCEPTION_RECORD *, + struct _exception_list *, + CONTEXT *, + void *); typedef struct _exception_list { @@ -104,70 +106,53 @@ typedef struct _exception_list } exception_list; extern exception_list *_except_list asm ("%fs:0"); -#else -typedef void exception_list; -#endif /* !__x86_64 */ +typedef void *PDISPATCHER_CONTEXT; class exception { -#ifdef __x86_64__ - static LONG myfault_handle (LPEXCEPTION_POINTERS ep); -#else exception_list el; exception_list *save; -#endif /* __x86_64__ */ - static int handle (EXCEPTION_RECORD *, exception_list *, CONTEXT *, void *); + static EXCEPTION_DISPOSITION handle (EXCEPTION_RECORD *, exception_list *, + CONTEXT *, PDISPATCHER_CONTEXT); public: exception () __attribute__ ((always_inline)) { /* Install SEH handler. */ + save = _except_list; + el.handler = handle; + el.prev = _except_list; + _except_list = ⪙ + }; + ~exception () __attribute__ ((always_inline)) { _except_list = save; } +}; + +#else + +#define exception_list void +typedef struct _DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT; + +class exception +{ #ifdef __x86_64__ + static EXCEPTION_DISPOSITION myfault (EXCEPTION_RECORD *, exception_list *, + CONTEXT *, PDISPATCHER_CONTEXT); +#endif + static EXCEPTION_DISPOSITION handle (EXCEPTION_RECORD *, exception_list *, + CONTEXT *, PDISPATCHER_CONTEXT); +public: + exception () __attribute__ ((always_inline)) + { + /* Install SEH handler. */ asm volatile ("\n\ 1: \n\ .seh_handler \ - _ZN9exception6handleEP17_EXCEPTION_RECORDPvP8_CONTEXTS2_, \ + _ZN9exception6handleEP17_EXCEPTION_RECORDPvP8_CONTEXTP19_DISPATCHER_CONTEXT, \ @except \n\ .seh_handlerdata \n\ .long 1 \n\ .rva 1b, 2f, 2f, 2f \n\ .seh_code \n"); -#else - save = _except_list; - el.handler = handle; - el.prev = _except_list; - _except_list = ⪙ -#endif /* __x86_64__ */ }; -#ifdef __x86_64__ - static void install_myfault_handler () __attribute__ ((always_inline)) - { - /* Install myfault exception handler as VEH. Here's what happens: - Some Windows DLLs (advapi32, for instance) are using SEH to catch - exceptions inside its own functions. If we install a VEH handler - to catch all exceptions, our Cygwin VEH handler would illegitimatly - handle exceptions inside of Windows DLLs which are usually handled - by its own SEH handler. So, for standard exceptions we use an SEH - handler as installed in the constructor above so as not to override - the SEH handlers in Windows DLLs. - But we have a special case, myfault handling. The myfault handling - catches exceptions inside of the Cygwin DLL, some of them entirely - expected as in verifyable_object_isvalid. The ultimately right thing - to do would be to install SEH handlers for each of these cases. - But there are two problems with that: - - 1. It would be a massive and, partially unreliable change in the - calling functions due to the incomplete SEH support in GCC. - - 2. It doesn't always work. Certain DLLs appear to call Cygwin - functions during DLL initialization while the SEH handler is - not installed in the active call frame. For these cases we - need a more generic approach. - - So, what we do here is to install a myfault VEH handler. This - function is called from dll_crt0_0, so the myfault handler is - available very early. */ - AddVectoredExceptionHandler (1, myfault_handle); - } ~exception () __attribute__ ((always_inline)) { asm volatile ("\n\ @@ -175,11 +160,10 @@ public: 2: \n\ nop \n"); } -#else - ~exception () __attribute__ ((always_inline)) { _except_list = save; } -#endif /* !__x86_64__ */ }; +#endif /* !__x86_64 */ + class cygwin_exception { PUINT_PTR framep; diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 0e8a977d4..4e9c77036 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -341,38 +341,41 @@ void cygwin_exception::dumpstack () { static bool already_dumped; - myfault efault; - if (efault.faulted ()) - return; - if (already_dumped || cygheap->rlim_core == 0Ul) - return; - already_dumped = true; - open_stackdumpfile (); - - if (e) - dump_exception (); - - int i; - - thestack.init (framep, 1, ctx); /* Initialize from the input CONTEXT */ -#ifdef __x86_64__ - small_printf ("Stack trace:\r\nFrame Function Args\r\n"); -#else - small_printf ("Stack trace:\r\nFrame Function Args\r\n"); -#endif - for (i = 0; i < 16 && thestack++; i++) + __try { - small_printf (_AFMT " " _AFMT, thestack.sf.AddrFrame.Offset, - thestack.sf.AddrPC.Offset); - for (unsigned j = 0; j < NPARAMS; j++) - small_printf ("%s" _AFMT, j == 0 ? " (" : ", ", thestack.sf.Params[j]); - small_printf (")\r\n"); + if (already_dumped || cygheap->rlim_core == 0Ul) + return; + already_dumped = true; + open_stackdumpfile (); + + if (e) + dump_exception (); + + int i; + + thestack.init (framep, 1, ctx); /* Initialize from the input CONTEXT */ +#ifdef __x86_64__ + small_printf ("Stack trace:\r\nFrame Function Args\r\n"); +#else + small_printf ("Stack trace:\r\nFrame Function Args\r\n"); +#endif + for (i = 0; i < 16 && thestack++; i++) + { + small_printf (_AFMT " " _AFMT, thestack.sf.AddrFrame.Offset, + thestack.sf.AddrPC.Offset); + for (unsigned j = 0; j < NPARAMS; j++) + small_printf ("%s" _AFMT, j == 0 ? " (" : ", ", + thestack.sf.Params[j]); + small_printf (")\r\n"); + } + small_printf ("End of stack trace%s\n", + i == 16 ? " (more stack frames may be present)" : ""); + if (h) + NtClose (h); } - small_printf ("End of stack trace%s\n", - i == 16 ? " (more stack frames may be present)" : ""); - if (h) - NtClose (h); + __except (NO_ERROR) {} + __endtry } bool @@ -549,40 +552,24 @@ rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e) #endif /* __x86_64 */ #ifdef __x86_64__ -/* myfault vectored exception handler */ -LONG -exception::myfault_handle (LPEXCEPTION_POINTERS ep) +/* myfault exception handler. */ +EXCEPTION_DISPOSITION +exception::myfault (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, + PDISPATCHER_CONTEXT dispatch) { - _cygtls& me = _my_tls; - - if (me.andreas) - { - /* Only handle the minimum amount of exceptions the myfault handler - was designed for. */ - switch (ep->ExceptionRecord->ExceptionCode) - { - case STATUS_ACCESS_VIOLATION: - case STATUS_DATATYPE_MISALIGNMENT: -#if 0 - /* PAGE_GUARD-based stack commits are based on structured exception - handling. Short-circuiting STATUS_STACK_OVERFLOW in a vectored - exception handler disables that, which can ultimately result in - a spurious SEGV. */ - case STATUS_STACK_OVERFLOW: -#endif - case STATUS_ARRAY_BOUNDS_EXCEEDED: - me.andreas->leave (); /* Return from a "san" caught fault */ - default: - break; - } - } - return EXCEPTION_CONTINUE_SEARCH; + PSCOPE_TABLE table = (PSCOPE_TABLE) dispatch->HandlerData; + RtlUnwindEx (frame, + (char *) dispatch->ImageBase + table->ScopeRecord[0].JumpTarget, + e, 0, in, dispatch->HistoryTable); + /* NOTREACHED, make gcc happy. */ + return ExceptionContinueSearch; } -#endif /* __x86_64 */ +#endif /* Main exception handler. */ -int -exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *) +EXCEPTION_DISPOSITION +exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, + PDISPATCHER_CONTEXT dispatch) { static bool NO_COPY debugging; _cygtls& me = _my_tls; diff --git a/winsup/cygwin/fcntl.cc b/winsup/cygwin/fcntl.cc index ea9a71a5e..babb06424 100644 --- a/winsup/cygwin/fcntl.cc +++ b/winsup/cygwin/fcntl.cc @@ -1,7 +1,7 @@ /* fcntl.cc: fcntl syscall Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2008, 2009, - 2010, 2011, 2012, 2013 Red Hat, Inc. + 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -28,53 +28,54 @@ fcntl64 (int fd, int cmd, ...) pthread_testcancel (); - debug_printf ("fcntl(%d, %d, ...)", fd, cmd); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - cygheap_fdget cfd (fd, true); - if (cfd < 0) - goto done; - - /* FIXME? All numerical args to fcntl are defined as long on Linux. - This relies on a really dirty trick on x86_64: A 32 bit mov to - a register (e.g. mov $1, %edx) always sets the high 32 bit to 0. - We're following the Linux lead here since the third arg to any - function is in a register anyway (%r8 in MS ABI). That's the easy - case which is covered here by always reading the arg with - sizeof (intptr_t) == sizeof (long) == sizeof (void*) which matches - all targets. - - However, the POSIX standard defines all numerical args as type int. - If we take that literally, we had a (small) problem on 64 bit, since - sizeof (void*) != sizeof (int). If we would like to follow POSIX - more closely than Linux, we'd have to call va_arg on a per cmd basis. */ - - va_start (args, cmd); - arg = va_arg (args, intptr_t); - va_end (args); - - switch (cmd) + __try { - case F_DUPFD: - case F_DUPFD_CLOEXEC: - if (arg >= 0 && arg < OPEN_MAX_MAX) + + debug_printf ("fcntl(%d, %d, ...)", fd, cmd); + cygheap_fdget cfd (fd, true); + if (cfd < 0) + __leave; + + /* FIXME? All numerical args to fcntl are defined as long on Linux. + This relies on a really dirty trick on x86_64: A 32 bit mov to + a register (e.g. mov $1, %edx) always sets the high 32 bit to 0. + We're following the Linux lead here since the third arg to any + function is in a register anyway (%r8 in MS ABI). That's the easy + case which is covered here by always reading the arg with + sizeof (intptr_t) == sizeof (long) == sizeof (void*) which matches + all targets. + + However, the POSIX standard defines all numerical args as type int. + If we take that literally, we had a (small) problem on 64 bit, since + sizeof (void*) != sizeof (int). If we would like to follow POSIX more + closely than Linux, we'd have to call va_arg on a per cmd basis. */ + + va_start (args, cmd); + arg = va_arg (args, intptr_t); + va_end (args); + + switch (cmd) { - int flags = cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0; - res = cygheap->fdtab.dup3 (fd, cygheap_fdnew ((arg) - 1), flags); + case F_DUPFD: + case F_DUPFD_CLOEXEC: + if (arg >= 0 && arg < OPEN_MAX_MAX) + { + int flags = cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0; + res = cygheap->fdtab.dup3 (fd, cygheap_fdnew ((arg) - 1), flags); + } + else + { + set_errno (EINVAL); + res = -1; + } + break; + default: + res = cfd->fcntl (cmd, arg); + break; } - else - { - set_errno (EINVAL); - res = -1; - } - break; - default: - res = cfd->fcntl (cmd, arg); - break; } -done: + __except (EFAULT) {} + __endtry syscall_printf ("%R = fcntl(%d, %d, %ly)", res, fd, cmd, arg); return res; } @@ -91,32 +92,34 @@ _fcntl (int fd, int cmd, ...) struct __flock32 *src = NULL; struct flock dst; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - va_start (args, cmd); - arg = va_arg (args, intptr_t); - va_end (args); - if (cmd == F_GETLK || cmd == F_SETLK || cmd == F_SETLKW) + __try { - src = (struct __flock32 *) arg; - dst.l_type = src->l_type; - dst.l_whence = src->l_whence; - dst.l_start = src->l_start; - dst.l_len = src->l_len; - dst.l_pid = src->l_pid; - arg = (intptr_t) &dst; + va_start (args, cmd); + arg = va_arg (args, intptr_t); + va_end (args); + if (cmd == F_GETLK || cmd == F_SETLK || cmd == F_SETLKW) + { + src = (struct __flock32 *) arg; + dst.l_type = src->l_type; + dst.l_whence = src->l_whence; + dst.l_start = src->l_start; + dst.l_len = src->l_len; + dst.l_pid = src->l_pid; + arg = (intptr_t) &dst; + } + int res = fcntl64 (fd, cmd, arg); + if (cmd == F_GETLK) + { + src->l_type = dst.l_type; + src->l_whence = dst.l_whence; + src->l_start = dst.l_start; + src->l_len = dst.l_len; + src->l_pid = (short) dst.l_pid; + } + return res; } - int res = fcntl64 (fd, cmd, arg); - if (cmd == F_GETLK) - { - src->l_type = dst.l_type; - src->l_whence = dst.l_whence; - src->l_start = dst.l_start; - src->l_len = dst.l_len; - src->l_pid = (short) dst.l_pid; - } - return res; + __except (EFAULT) + __endtry + return -1; } #endif diff --git a/winsup/cygwin/fhandler_socket.cc b/winsup/cygwin/fhandler_socket.cc index 59c002c03..0354ee246 100644 --- a/winsup/cygwin/fhandler_socket.cc +++ b/winsup/cygwin/fhandler_socket.cc @@ -2293,14 +2293,17 @@ fhandler_socket::getpeereid (pid_t *pid, uid_t *euid, gid_t *egid) return -1; } - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (pid) - *pid = sec_peer_pid; - if (euid) - *euid = sec_peer_uid; - if (egid) - *egid = sec_peer_gid; - return 0; + __try + { + if (pid) + *pid = sec_peer_pid; + if (euid) + *euid = sec_peer_uid; + if (egid) + *egid = sec_peer_gid; + return 0; + } + __except (EFAULT) {} + __endtry + return -1; } diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc index 91d5b12aa..5b09e4262 100644 --- a/winsup/cygwin/fhandler_tape.cc +++ b/winsup/cygwin/fhandler_tape.cc @@ -2,7 +2,7 @@ classes. Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, - 2010, 2011, 2012, 2013 Red Hat, Inc. + 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -977,159 +977,163 @@ mtinfo_drive::set_options (HANDLE mt, int32_t options) int mtinfo_drive::ioctl (HANDLE mt, unsigned int cmd, void *buf) { - myfault efault; - if (efault.faulted ()) - return ERROR_NOACCESS; - if (cmd == MTIOCTOP) + __try { - struct mtop *op = (struct mtop *) buf; - if (lasterr == ERROR_BUS_RESET) + if (cmd == MTIOCTOP) { - /* If a bus reset occurs, block further access to this device - until the user rewinds, unloads or in any other way tries - to maintain a well-known tape position. */ - if (op->mt_op != MTREW && op->mt_op != MTOFFL - && op->mt_op != MTRETEN && op->mt_op != MTERASE - && op->mt_op != MTSEEK && op->mt_op != MTEOM) - return ERROR_BUS_RESET; - /* Try to maintain last lock state after bus reset. */ - if (lock >= auto_locked && PrepareTape (mt, TAPE_LOCK, FALSE)) + struct mtop *op = (struct mtop *) buf; + if (lasterr == ERROR_BUS_RESET) { - debug_printf ("Couldn't relock drive after bus reset."); - lock = unlocked; + /* If a bus reset occurs, block further access to this device + until the user rewinds, unloads or in any other way tries + to maintain a well-known tape position. */ + if (op->mt_op != MTREW && op->mt_op != MTOFFL + && op->mt_op != MTRETEN && op->mt_op != MTERASE + && op->mt_op != MTSEEK && op->mt_op != MTEOM) + return ERROR_BUS_RESET; + /* Try to maintain last lock state after bus reset. */ + if (lock >= auto_locked && PrepareTape (mt, TAPE_LOCK, FALSE)) + { + debug_printf ("Couldn't relock drive after bus reset."); + lock = unlocked; + } } - } - switch (op->mt_op) - { - case MTRESET: - break; - case MTFSF: - set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, false); - break; - case MTBSF: - set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, false); - break; - case MTFSR: - set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count, false); - break; - case MTBSR: - set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, -op->mt_count, false); - break; - case MTWEOF: - write_marks (mt, TAPE_FILEMARKS, op->mt_count); - break; - case MTREW: - set_pos (mt, TAPE_REWIND, 0, false); - break; - case MTOFFL: - case MTUNLOAD: - prepare (mt, TAPE_UNLOAD); - break; - case MTNOP: - lasterr = 0; - break; - case MTRETEN: - if (!get_feature (TAPE_DRIVE_TENSION)) - lasterr = ERROR_INVALID_PARAMETER; - else if (!set_pos (mt, TAPE_REWIND, 0, false)) - prepare (mt, TAPE_TENSION); - break; - case MTBSFM: - set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, true); - break; - case MTFSFM: - set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, true); - break; - case MTEOM: - if (fast_eom () && get_feature (TAPE_DRIVE_END_OF_DATA)) - set_pos (mt, TAPE_SPACE_END_OF_DATA, 0, false); - else - set_pos (mt, TAPE_SPACE_FILEMARKS, 32767, false); - break; - case MTERASE: - erase (mt, TAPE_ERASE_LONG); - break; - case MTRAS1: - case MTRAS2: - case MTRAS3: - lasterr = ERROR_INVALID_PARAMETER; - break; - case MTSETBLK: - if (!get_feature (TAPE_DRIVE_SET_BLOCK_SIZE)) - { - lasterr = ERROR_INVALID_PARAMETER; + switch (op->mt_op) + { + case MTRESET: break; - } - if ((DWORD) op->mt_count == mp ()->BlockSize) - { - /* Nothing has changed. */ + case MTFSF: + set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, false); + break; + case MTBSF: + set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, false); + break; + case MTFSR: + set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count, false); + break; + case MTBSR: + set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, -op->mt_count, false); + break; + case MTWEOF: + write_marks (mt, TAPE_FILEMARKS, op->mt_count); + break; + case MTREW: + set_pos (mt, TAPE_REWIND, 0, false); + break; + case MTOFFL: + case MTUNLOAD: + prepare (mt, TAPE_UNLOAD); + break; + case MTNOP: lasterr = 0; break; - } - if ((op->mt_count == 0 && !get_feature (TAPE_DRIVE_VARIABLE_BLOCK)) - || (op->mt_count > 0 - && ((DWORD) op->mt_count < dp ()->MinimumBlockSize - || (DWORD) op->mt_count > dp ()->MaximumBlockSize))) - { + case MTRETEN: + if (!get_feature (TAPE_DRIVE_TENSION)) + lasterr = ERROR_INVALID_PARAMETER; + else if (!set_pos (mt, TAPE_REWIND, 0, false)) + prepare (mt, TAPE_TENSION); + break; + case MTBSFM: + set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, true); + break; + case MTFSFM: + set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, true); + break; + case MTEOM: + if (fast_eom () && get_feature (TAPE_DRIVE_END_OF_DATA)) + set_pos (mt, TAPE_SPACE_END_OF_DATA, 0, false); + else + set_pos (mt, TAPE_SPACE_FILEMARKS, 32767, false); + break; + case MTERASE: + erase (mt, TAPE_ERASE_LONG); + break; + case MTRAS1: + case MTRAS2: + case MTRAS3: lasterr = ERROR_INVALID_PARAMETER; break; - } - if (set_blocksize (mt, op->mt_count) - && lasterr == ERROR_INVALID_FUNCTION) - lasterr = ERROR_INVALID_BLOCK_LENGTH; - break; - case MTSEEK: - if (get_feature (TAPE_DRIVE_LOGICAL_BLK)) - set_pos (mt, TAPE_LOGICAL_BLOCK, op->mt_count, false); - else if (!get_pos (mt)) - set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, - op->mt_count - block, false); - break; - case MTTELL: - if (!get_pos (mt)) - op->mt_count = (int) block; - break; - case MTFSS: - set_pos (mt, TAPE_SPACE_SETMARKS, op->mt_count, false); - break; - case MTBSS: - set_pos (mt, TAPE_SPACE_SETMARKS, -op->mt_count, false); - break; - case MTWSM: - write_marks (mt, TAPE_SETMARKS, op->mt_count); - break; - case MTLOCK: - prepare (mt, TAPE_LOCK); - break; - case MTUNLOCK: - prepare (mt, TAPE_UNLOCK); - break; - case MTLOAD: - prepare (mt, TAPE_LOAD); - break; - case MTCOMPRESSION: - set_compression (mt, op->mt_count); - break; - case MTSETPART: - set_partition (mt, op->mt_count); - break; - case MTMKPART: - create_partitions (mt, op->mt_count); - break; - case MTSETDRVBUFFER: - set_options (mt, op->mt_count); - break; - case MTSETDENSITY: - default: - lasterr = ERROR_INVALID_PARAMETER; - break; + case MTSETBLK: + if (!get_feature (TAPE_DRIVE_SET_BLOCK_SIZE)) + { + lasterr = ERROR_INVALID_PARAMETER; + break; + } + if ((DWORD) op->mt_count == mp ()->BlockSize) + { + /* Nothing has changed. */ + lasterr = 0; + break; + } + if ((op->mt_count == 0 && !get_feature (TAPE_DRIVE_VARIABLE_BLOCK)) + || (op->mt_count > 0 + && ((DWORD) op->mt_count < dp ()->MinimumBlockSize + || (DWORD) op->mt_count > dp ()->MaximumBlockSize))) + { + lasterr = ERROR_INVALID_PARAMETER; + break; + } + if (set_blocksize (mt, op->mt_count) + && lasterr == ERROR_INVALID_FUNCTION) + lasterr = ERROR_INVALID_BLOCK_LENGTH; + break; + case MTSEEK: + if (get_feature (TAPE_DRIVE_LOGICAL_BLK)) + set_pos (mt, TAPE_LOGICAL_BLOCK, op->mt_count, false); + else if (!get_pos (mt)) + set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, + op->mt_count - block, false); + break; + case MTTELL: + if (!get_pos (mt)) + op->mt_count = (int) block; + break; + case MTFSS: + set_pos (mt, TAPE_SPACE_SETMARKS, op->mt_count, false); + break; + case MTBSS: + set_pos (mt, TAPE_SPACE_SETMARKS, -op->mt_count, false); + break; + case MTWSM: + write_marks (mt, TAPE_SETMARKS, op->mt_count); + break; + case MTLOCK: + prepare (mt, TAPE_LOCK); + break; + case MTUNLOCK: + prepare (mt, TAPE_UNLOCK); + break; + case MTLOAD: + prepare (mt, TAPE_LOAD); + break; + case MTCOMPRESSION: + set_compression (mt, op->mt_count); + break; + case MTSETPART: + set_partition (mt, op->mt_count); + break; + case MTMKPART: + create_partitions (mt, op->mt_count); + break; + case MTSETDRVBUFFER: + set_options (mt, op->mt_count); + break; + case MTSETDENSITY: + default: + lasterr = ERROR_INVALID_PARAMETER; + break; + } } + else if (cmd == MTIOCGET) + get_status (mt, (struct mtget *) buf); + else if (cmd == MTIOCPOS && !get_pos (mt)) + ((struct mtpos *) buf)->mt_blkno = (long) block; } - else if (cmd == MTIOCGET) - get_status (mt, (struct mtget *) buf); - else if (cmd == MTIOCPOS && !get_pos (mt)) - ((struct mtpos *) buf)->mt_blkno = (long) block; - + __except (NO_ERROR) + { + lasterr = ERROR_NOACCESS; + } + __endtry return lasterr; } diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index 4250aba3f..540d914e3 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -1761,37 +1761,37 @@ flock (int fd, int operation) int cmd; struct flock fl = { 0, SEEK_SET, 0, 0, 0 }; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - cygheap_fdget cfd (fd, true); - if (cfd < 0) - goto done; - - cmd = (operation & LOCK_NB) ? F_SETLK : F_SETLKW; - switch (operation & (~LOCK_NB)) + __try { - case LOCK_EX: - fl.l_type = F_WRLCK; - break; - case LOCK_SH: - fl.l_type = F_RDLCK; - break; - case LOCK_UN: - fl.l_type = F_UNLCK; - break; - default: - set_errno (EINVAL); - goto done; + cygheap_fdget cfd (fd, true); + if (cfd < 0) + __leave; + + cmd = (operation & LOCK_NB) ? F_SETLK : F_SETLKW; + switch (operation & (~LOCK_NB)) + { + case LOCK_EX: + fl.l_type = F_WRLCK; + break; + case LOCK_SH: + fl.l_type = F_RDLCK; + break; + case LOCK_UN: + fl.l_type = F_UNLCK; + break; + default: + set_errno (EINVAL); + __leave; + } + if (!cfd->mandatory_locking ()) + fl.l_type |= F_FLOCK; + res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl) + : cfd->lock (cmd, &fl); + if ((res == -1) && ((get_errno () == EAGAIN) || (get_errno () == EACCES))) + set_errno (EWOULDBLOCK); } - if (!cfd->mandatory_locking ()) - fl.l_type |= F_FLOCK; - res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl) - : cfd->lock (cmd, &fl); - if ((res == -1) && ((get_errno () == EAGAIN) || (get_errno () == EACCES))) - set_errno (EWOULDBLOCK); -done: + __except (EFAULT) {} + __endtry syscall_printf ("%R = flock(%d, %d)", res, fd, operation); return res; } @@ -1805,50 +1805,50 @@ lockf (int filedes, int function, off_t size) pthread_testcancel (); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - cygheap_fdget cfd (filedes, true); - if (cfd < 0) - goto done; - - fl.l_start = 0; - fl.l_len = size; - fl.l_whence = SEEK_CUR; - - switch (function) + __try { - case F_ULOCK: - cmd = F_SETLK; - fl.l_type = F_UNLCK; - break; - case F_LOCK: - cmd = F_SETLKW; - fl.l_type = F_WRLCK; - break; - case F_TLOCK: - cmd = F_SETLK; - fl.l_type = F_WRLCK; - break; - case F_TEST: - fl.l_type = F_WRLCK; - if (cfd->lock (F_GETLK, &fl) == -1) - goto done; - if (fl.l_type == F_UNLCK || fl.l_pid == getpid ()) - res = 0; - else - errno = EAGAIN; - goto done; - /* NOTREACHED */ - default: - errno = EINVAL; - goto done; - /* NOTREACHED */ + cygheap_fdget cfd (filedes, true); + if (cfd < 0) + __leave; + + fl.l_start = 0; + fl.l_len = size; + fl.l_whence = SEEK_CUR; + + switch (function) + { + case F_ULOCK: + cmd = F_SETLK; + fl.l_type = F_UNLCK; + break; + case F_LOCK: + cmd = F_SETLKW; + fl.l_type = F_WRLCK; + break; + case F_TLOCK: + cmd = F_SETLK; + fl.l_type = F_WRLCK; + break; + case F_TEST: + fl.l_type = F_WRLCK; + if (cfd->lock (F_GETLK, &fl) == -1) + __leave; + if (fl.l_type == F_UNLCK || fl.l_pid == getpid ()) + res = 0; + else + errno = EAGAIN; + __leave; + /* NOTREACHED */ + default: + errno = EINVAL; + __leave; + /* NOTREACHED */ + } + res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl) + : cfd->lock (cmd, &fl); } - res = cfd->mandatory_locking () ? cfd->mand_lock (cmd, &fl) - : cfd->lock (cmd, &fl); -done: + __except (EFAULT) {} + __endtry syscall_printf ("%R = lockf(%d, %d, %D)", res, filedes, function, size); return res; } diff --git a/winsup/cygwin/gendef b/winsup/cygwin/gendef index cef34a5ab..150bd3531 100755 --- a/winsup/cygwin/gendef +++ b/winsup/cygwin/gendef @@ -1,5 +1,5 @@ #!/usr/bin/perl -# Copyright 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011, 2012, 2013 +# Copyright 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011, 2012, 2013, 2014 # Red Hat, Inc. # # This file is part of Cygwin. @@ -181,6 +181,8 @@ _sigbe: # return here after cygwin syscall movq -8(%r11),%r11 # get return address from signal stack decl $tls::incyg(%r10) decl $tls::stacklock(%r10) # release lock + leaq $tls::pathbufs(%r10),%r10 # Address of tls_pathbufs + movq \$0,(%r10) # Set c_cnt and w_cnt to 0 jmp *%r11 # "return" to caller .seh_endproc @@ -366,7 +368,7 @@ stabilize_sig_stack: movq %gs:8,%r12 1: movl \$1,%r10d xchgl %r10d,$tls::stacklock(%r12) - movl %r10d,$tls::spinning(%r12) # flag if we are waiting for lock + movl %r10d,$tls::spinning(%r12) # flag if we are waiting for lock testl %r10d,%r10d jz 2f pause @@ -374,14 +376,14 @@ stabilize_sig_stack: 2: incl $tls::incyg(%r12) cmpl \$0,$tls::sig(%r12) jz 3f - decl $tls::stacklock(%r12) # unlock - movq \$$tls::start_offset,%rcx # point to beginning - addq %r12,%rcx # of tls block + decl $tls::stacklock(%r12) # unlock + movq \$$tls::start_offset,%rcx # point to beginning + addq %r12,%rcx # of tls block call _ZN7_cygtls19call_signal_handlerEv jmp 1b 3: decl $tls::incyg(%r12) addq \$0x20,%rsp - movq %r12,%r11 # return tls addr in r11 + movq %r12,%r11 # return tls addr in r11 popq %r12 ret .seh_endproc @@ -393,13 +395,13 @@ EOF __sigfe_maybe: pushl %ebx pushl %edx - movl %fs:4,%ebx # location of bottom of stack - addl \$$tls::initialized,%ebx # where we will be looking - cmpl %ebx,%esp # stack loc > than tls - jge 0f # yep. we don't have a tls. - subl \$$tls::initialized,%ebx # where we will be looking + movl %fs:4,%ebx # location of bottom of stack + addl \$$tls::initialized,%ebx # where we will be looking + cmpl %ebx,%esp # stack loc > than tls + jge 0f # yep. we don't have a tls. + subl \$$tls::initialized,%ebx # where we will be looking movl $tls::initialized(%ebx),%eax - cmpl \$0xc763173f,%eax # initialized? + cmpl \$0xc763173f,%eax # initialized? je 1f 0: popl %edx popl %ebx @@ -408,43 +410,46 @@ __sigfe_maybe: __sigfe: pushl %ebx pushl %edx - movl %fs:4,%ebx # location of bottom of stack -1: movl \$1,%eax # potential lock value - xchgl %eax,$tls::stacklock(%ebx) # see if we can grab it - movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock - testl %eax,%eax # it will be zero - jz 2f # if so - call _yield # should be a short-time thing, so - jmp 1b # sleep and loop -2: movl \$4,%eax # have the lock, now increment the - xadd %eax,$tls::stackptr(%ebx) # stack pointer and get pointer - leal __sigbe,%edx # new place to return to - xchgl %edx,12(%esp) # exchange with real return value - movl %edx,(%eax) # store real return value on alt stack + movl %fs:4,%ebx # location of bottom of stack +1: movl \$1,%eax # potential lock value + xchgl %eax,$tls::stacklock(%ebx) # see if we can grab it + movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock + testl %eax,%eax # it will be zero + jz 2f # if so + call _yield # should be a short-time thing, so + jmp 1b # sleep and loop +2: movl \$4,%eax # have the lock, now increment the + xadd %eax,$tls::stackptr(%ebx) # stack pointer and get pointer + leal __sigbe,%edx # new place to return to + xchgl %edx,12(%esp) # exchange with real return value + movl %edx,(%eax) # store real return value on alt stack incl $tls::incyg(%ebx) - decl $tls::stacklock(%ebx) # remove lock - popl %edx # restore saved value + decl $tls::stacklock(%ebx) # remove lock + popl %edx # restore saved value popl %ebx ret .global __sigbe -__sigbe: # return here after cygwin syscall - pushl %eax # don't clobber - pushl %ebx # tls pointer -1: movl %fs:4,%ebx # address of bottom of tls - movl \$1,%eax # potential lock value - xchgl %eax,$tls::stacklock(%ebx) # see if we can grab it - movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock - testl %eax,%eax # it will be zero - jz 2f # if so - call _yield # sleep - jmp 1b # and loop -2: movl \$-4,%eax # now decrement aux stack - xadd %eax,$tls::stackptr(%ebx) # and get pointer - movl -4(%eax),%eax # get return address from signal stack - xchgl %eax,4(%esp) # swap return address with saved eax +__sigbe: # return here after cygwin syscall + pushl %eax # don't clobber + pushl %ebx # tls pointer +1: movl %fs:4,%ebx # address of bottom of tls + movl \$1,%eax # potential lock value + xchgl %eax,$tls::stacklock(%ebx) # see if we can grab it + movl %eax,$tls::spinning(%ebx) # flag if we are waiting for lock + testl %eax,%eax # it will be zero + jz 2f # if so + call _yield # sleep + jmp 1b # and loop +2: movl \$-4,%eax # now decrement aux stack + xadd %eax,$tls::stackptr(%ebx) # and get pointer + movl -4(%eax),%eax # get return address from signal stack + xchgl %eax,4(%esp) # swap return address with saved eax decl $tls::incyg(%ebx) - decl $tls::stacklock(%ebx) # release lock + decl $tls::stacklock(%ebx) # release lock + leal $tls::pathbufs(%ebx),%ebx # Address of tls_pathbufs + movl \$0,(%ebx) # Set c_cnt to 0 + movl \$0,4(%ebx) # Set w_cnt to 0 popl %ebx ret diff --git a/winsup/cygwin/libc/bsdlib.cc b/winsup/cygwin/libc/bsdlib.cc index 696a9f856..89bc9431c 100644 --- a/winsup/cygwin/libc/bsdlib.cc +++ b/winsup/cygwin/libc/bsdlib.cc @@ -249,8 +249,7 @@ getprogname (void) extern "C" void setprogname (const char *newprogname) { - myfault efault; - if (!efault.faulted (EFAULT)) + __try { /* Per BSD man page, setprogname keeps a pointer to the last path component of the argument. It does *not* copy the @@ -261,6 +260,8 @@ setprogname (const char *newprogname) else __progname = (char *)newprogname; } + __except (EFAULT) {} + __endtry } extern "C" void diff --git a/winsup/cygwin/libc/rexec.cc b/winsup/cygwin/libc/rexec.cc index c3074d381..f9be2231a 100644 --- a/winsup/cygwin/libc/rexec.cc +++ b/winsup/cygwin/libc/rexec.cc @@ -312,100 +312,101 @@ extern "C" int cygwin_rexec (char **ahost, unsigned short rport, char *name, char *pass, char *cmd, int *fd2p) { - struct sockaddr_in sin, sin2, from; - struct hostent *hp; - u_short port = 0; - int s, timo = 1, s3; - char c; - static char ahostbuf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + struct sockaddr_in sin, sin2, from; + struct hostent *hp; + u_short port = 0; + int s, timo = 1, s3; + char c; + static char ahostbuf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - hp = cygwin_gethostbyname(*ahost); - if (hp == 0) { - cygwin_herror(*ahost); - return (-1); - } - *ahost = strcpy (ahostbuf, hp->h_name); - ruserpass(hp->h_name, &name, &pass, NULL); - if (!name) - name = getlogin (); - if (!pass) - pass = almost_null; + __try + { + hp = cygwin_gethostbyname(*ahost); + if (hp == 0) { + cygwin_herror(*ahost); + return (-1); + } + *ahost = strcpy (ahostbuf, hp->h_name); + ruserpass(hp->h_name, &name, &pass, NULL); + if (!name) + name = getlogin (); + if (!pass) + pass = almost_null; retry: - s = cygwin_socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) { - perror("rexec: socket"); - return (-1); - } - sin.sin_family = hp->h_addrtype; - sin.sin_port = rport; - bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); - if (cygwin_connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { - if (errno == ECONNREFUSED && timo <= 16) { - (void) close(s); - sleep(timo); - timo *= 2; - goto retry; - } - perror(hp->h_name); - return (-1); - } - if (fd2p == 0) { - (void) write(s, "", 1); - } else { - char num[8]; - int s2, sin2len; + s = cygwin_socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) { + perror("rexec: socket"); + return (-1); + } + sin.sin_family = hp->h_addrtype; + sin.sin_port = rport; + bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); + if (cygwin_connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if (errno == ECONNREFUSED && timo <= 16) { + (void) close(s); + sleep(timo); + timo *= 2; + goto retry; + } + perror(hp->h_name); + return (-1); + } + if (fd2p == 0) { + (void) write(s, "", 1); + } else { + char num[8]; + int s2, sin2len; - s2 = cygwin_socket(AF_INET, SOCK_STREAM, 0); - if (s2 < 0) { - (void) close(s); - return (-1); + s2 = cygwin_socket(AF_INET, SOCK_STREAM, 0); + if (s2 < 0) { + (void) close(s); + return (-1); + } + cygwin_listen(s2, 1); + sin2len = sizeof (sin2); + if (cygwin_getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 || + sin2len != sizeof (sin2)) { + perror("getsockname"); + (void) close(s2); + goto bad; + } + port = ntohs((u_short)sin2.sin_port); + (void) sprintf(num, "%u", port); + (void) write(s, num, strlen(num)+1); + { int len = sizeof (from); + s3 = cygwin_accept(s2, (struct sockaddr *)&from, &len); + close(s2); + if (s3 < 0) { + perror("accept"); + port = 0; + goto bad; } - cygwin_listen(s2, 1); - sin2len = sizeof (sin2); - if (cygwin_getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 || - sin2len != sizeof (sin2)) { - perror("getsockname"); - (void) close(s2); - goto bad; - } - port = ntohs((u_short)sin2.sin_port); - (void) sprintf(num, "%u", port); - (void) write(s, num, strlen(num)+1); - { int len = sizeof (from); - s3 = cygwin_accept(s2, (struct sockaddr *)&from, &len); - close(s2); - if (s3 < 0) { - perror("accept"); - port = 0; - goto bad; - } - } - *fd2p = s3; - } - (void) write(s, name, strlen(name) + 1); - /* should public key encypt the password here */ - (void) write(s, pass, strlen(pass) + 1); - (void) write(s, cmd, strlen(cmd) + 1); - if (read(s, &c, 1) != 1) { - perror(*ahost); - goto bad; - } - if (c != 0) { - while (read(s, &c, 1) == 1) { - (void) write(2, &c, 1); - if (c == '\n') - break; - } - goto bad; - } - return (s); + } + *fd2p = s3; + } + (void) write(s, name, strlen(name) + 1); + /* should public key encypt the password here */ + (void) write(s, pass, strlen(pass) + 1); + (void) write(s, cmd, strlen(cmd) + 1); + if (read(s, &c, 1) != 1) { + perror(*ahost); + goto bad; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void) write(2, &c, 1); + if (c == '\n') + break; + } + goto bad; + } + return (s); bad: - if (port) - (void) close(*fd2p); - (void) close(s); - return (-1); + if (port) + (void) close(*fd2p); + (void) close(s); + } + __except (EFAULT) {} + __endtry + return (-1); } diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc index 741e6726b..eee47a53a 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -202,35 +202,38 @@ check_iovec (const struct iovec *iov, int iovcnt, bool forwrite) return -1; } - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - size_t tot = 0; - - while (iovcnt != 0) + __try { - if (iov->iov_len > SSIZE_MAX || (tot += iov->iov_len) > SSIZE_MAX) + + size_t tot = 0; + + while (iovcnt != 0) { - set_errno (EINVAL); - return -1; + if (iov->iov_len > SSIZE_MAX || (tot += iov->iov_len) > SSIZE_MAX) + { + set_errno (EINVAL); + __leave; + } + + volatile char *p = ((char *) iov->iov_base) + iov->iov_len - 1; + if (!iov->iov_len) + /* nothing to do */; + else if (!forwrite) + *p = dummytest (p); + else + dummytest (p); + + iov++; + iovcnt--; } - volatile char *p = ((char *) iov->iov_base) + iov->iov_len - 1; - if (!iov->iov_len) - /* nothing to do */; - else if (!forwrite) - *p = dummytest (p); - else - dummytest (p); + assert (tot <= SSIZE_MAX); - iov++; - iovcnt--; + return (ssize_t) tot; } - - assert (tot <= SSIZE_MAX); - - return (ssize_t) tot; + __except (EFAULT) + __endtry + return -1; } /* Try hard to schedule another thread. @@ -512,18 +515,23 @@ slashify (const char *src, char *dst, bool trailing_slash_p) void * __reg1 __import_address (void *imp) { - myfault efault; - if (efault.faulted ()) - return NULL; - if (*((uint16_t *) imp) != 0x25ff) - return NULL; - const char *ptr = (const char *) imp; + __try + { + if (*((uint16_t *) imp) == 0x25ff) + { + const char *ptr = (const char *) imp; #ifdef __x86_64__ - const uintptr_t *jmpto = (uintptr_t *) (ptr + 6 + *(int32_t *)(ptr + 2)); + const uintptr_t *jmpto = (uintptr_t *) + (ptr + 6 + *(int32_t *)(ptr + 2)); #else - const uintptr_t *jmpto = (uintptr_t *) *((uintptr_t *) (ptr + 2)); + const uintptr_t *jmpto = (uintptr_t *) *((uintptr_t *) (ptr + 2)); #endif - return (void *) *jmpto; + return (void *) *jmpto; + } + } + __except (NO_ERROR) {} + __endtry + return NULL; } /* CygwinCreateThread. diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index eecd72692..94e305489 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -1700,50 +1700,54 @@ mount (const char *win32_path, const char *posix_path, unsigned flags) isn't really supported except from fstab? */ int res = -1; - myfault efault; - if (efault.faulted (EFAULT)) - /* errno set */; - else if (!*posix_path) - set_errno (EINVAL); - else if (strpbrk (posix_path, "\\:")) - set_errno (EINVAL); - else if (flags & MOUNT_CYGDRIVE) /* normal mount */ + __try { - /* When flags include MOUNT_CYGDRIVE, take this to mean that - we actually want to change the cygdrive prefix and flags - without actually mounting anything. */ - res = mount_table->write_cygdrive_info (posix_path, flags); - win32_path = NULL; - } - else if (!*win32_path) - set_errno (EINVAL); - else - { - char *w32_path = (char *) win32_path; - if (flags & MOUNT_BIND) + if (!*posix_path) + set_errno (EINVAL); + else if (strpbrk (posix_path, "\\:")) + set_errno (EINVAL); + else if (flags & MOUNT_CYGDRIVE) /* normal mount */ { - /* Prepend root path to bound path. */ - tmp_pathbuf tp; - device dev; - - unsigned conv_flags = 0; - const char *bound_path = w32_path; - - w32_path = tp.c_get (); - int error = mount_table->conv_to_win32_path (bound_path, w32_path, - dev, &conv_flags); - if (error || strlen (w32_path) >= MAX_PATH) - return true; - if ((flags & ~MOUNT_SYSTEM) == (MOUNT_BIND | MOUNT_BINARY)) - flags = (MOUNT_BIND | conv_flags) - & ~(MOUNT_IMMUTABLE | MOUNT_AUTOMATIC); + /* When flags include MOUNT_CYGDRIVE, take this to mean that + we actually want to change the cygdrive prefix and flags + without actually mounting anything. */ + res = mount_table->write_cygdrive_info (posix_path, flags); + win32_path = NULL; } - /* Make sure all mounts are user mounts, even those added via mount -a. */ - flags &= ~MOUNT_SYSTEM; - res = mount_table->add_item (w32_path, posix_path, flags); - } + else if (!*win32_path) + set_errno (EINVAL); + else + { + char *w32_path = (char *) win32_path; + if (flags & MOUNT_BIND) + { + /* Prepend root path to bound path. */ + tmp_pathbuf tp; + device dev; - syscall_printf ("%R = mount(%s, %s, %y)", res, win32_path, posix_path, flags); + unsigned conv_flags = 0; + const char *bound_path = w32_path; + + w32_path = tp.c_get (); + int error = mount_table->conv_to_win32_path (bound_path, w32_path, + dev, &conv_flags); + if (error || strlen (w32_path) >= MAX_PATH) + return true; + if ((flags & ~MOUNT_SYSTEM) == (MOUNT_BIND | MOUNT_BINARY)) + flags = (MOUNT_BIND | conv_flags) + & ~(MOUNT_IMMUTABLE | MOUNT_AUTOMATIC); + } + /* Make sure all mounts are user mounts, even those added via + mount -a. */ + flags &= ~MOUNT_SYSTEM; + res = mount_table->add_item (w32_path, posix_path, flags); + } + + syscall_printf ("%R = mount(%s, %s, %y)", + res, win32_path, posix_path, flags); + } + __except (EFAULT) {} + __endtry return res; } @@ -1755,15 +1759,18 @@ mount (const char *win32_path, const char *posix_path, unsigned flags) extern "C" int umount (const char *path) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (!*path) + __try { - set_errno (EINVAL); - return -1; + if (!*path) + { + set_errno (EINVAL); + __leave; + } + return cygwin_umount (path, 0); } - return cygwin_umount (path, 0); + __except (EFAULT) {} + __endtry + return -1; } /* cygwin_umount: This is like umount but takes an additional flags diff --git a/winsup/cygwin/msg.cc b/winsup/cygwin/msg.cc index f970121c9..5505dc453 100644 --- a/winsup/cygwin/msg.cc +++ b/winsup/cygwin/msg.cc @@ -1,6 +1,6 @@ /* msg.cc: XSI IPC interface for Cygwin. - Copyright 2002, 2003, 2004, 2005, 2008, 2009 Red Hat, Inc. + Copyright 2002, 2003, 2004, 2005, 2008, 2009, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -91,38 +91,40 @@ client_request_msg::client_request_msg (int msqid, extern "C" int msgctl (int msqid, int cmd, struct msqid_ds *buf) { - syscall_printf ("msgctl (msqid = %d, cmd = %y, buf = %p)", - msqid, cmd, buf); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - switch (cmd) + syscall_printf ("msgctl (msqid = %d, cmd = %y, buf = %p)", msqid, cmd, buf); + __try { - case IPC_STAT: - break; - case IPC_SET: - break; - case IPC_RMID: - break; - case IPC_INFO: - break; - case MSG_INFO: - break; - default: - syscall_printf ("-1 [%d] = msgctl ()", EINVAL); - set_errno (EINVAL); - return -1; + switch (cmd) + { + case IPC_STAT: + break; + case IPC_SET: + break; + case IPC_RMID: + break; + case IPC_INFO: + break; + case MSG_INFO: + break; + default: + syscall_printf ("-1 [%d] = msgctl ()", EINVAL); + set_errno (EINVAL); + __leave; + } + client_request_msg request (msqid, cmd, buf); + if (request.make_request () == -1 || request.retval () == -1) + { + syscall_printf ("-1 [%d] = msgctl ()", request.error_code ()); + set_errno (request.error_code ()); + if (request.error_code () == ENOSYS) + raise (SIGSYS); + __leave; + } + return request.retval (); } - client_request_msg request (msqid, cmd, buf); - if (request.make_request () == -1 || request.retval () == -1) - { - syscall_printf ("-1 [%d] = msgctl ()", request.error_code ()); - set_errno (request.error_code ()); - if (request.error_code () == ENOSYS) - raise (SIGSYS); - return -1; - } - return request.retval (); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -147,19 +149,22 @@ msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) syscall_printf ("msgrcv (msqid = %d, msgp = %p, msgsz = %ld, " "msgtyp = %d, msgflg = %y)", msqid, msgp, msgsz, msgtyp, msgflg); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - client_request_msg request (msqid, msgp, msgsz, msgtyp, msgflg); - if (request.make_request () == -1 || request.rcvval () == -1) + __try { - syscall_printf ("-1 [%d] = msgrcv ()", request.error_code ()); - set_errno (request.error_code ()); - if (request.error_code () == ENOSYS) - raise (SIGSYS); - return -1; + client_request_msg request (msqid, msgp, msgsz, msgtyp, msgflg); + if (request.make_request () == -1 || request.rcvval () == -1) + { + syscall_printf ("-1 [%d] = msgrcv ()", request.error_code ()); + set_errno (request.error_code ()); + if (request.error_code () == ENOSYS) + raise (SIGSYS); + __leave; + } + return request.rcvval (); } - return request.rcvval (); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -167,17 +172,20 @@ msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) { syscall_printf ("msgsnd (msqid = %d, msgp = %p, msgsz = %ld, msgflg = %y)", msqid, msgp, msgsz, msgflg); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - client_request_msg request (msqid, msgp, msgsz, msgflg); - if (request.make_request () == -1 || request.retval () == -1) + __try { - syscall_printf ("-1 [%d] = msgsnd ()", request.error_code ()); - set_errno (request.error_code ()); - if (request.error_code () == ENOSYS) - raise (SIGSYS); - return -1; + client_request_msg request (msqid, msgp, msgsz, msgflg); + if (request.make_request () == -1 || request.retval () == -1) + { + syscall_printf ("-1 [%d] = msgsnd ()", request.error_code ()); + set_errno (request.error_code ()); + if (request.error_code () == ENOSYS) + raise (SIGSYS); + __leave; + } + return request.retval (); } - return request.retval (); + __except (EFAULT) {} + __endtry + return -1; } diff --git a/winsup/cygwin/net.cc b/winsup/cygwin/net.cc index aed92fd9f..b6c0f7257 100644 --- a/winsup/cygwin/net.cc +++ b/winsup/cygwin/net.cc @@ -500,10 +500,13 @@ dup_ent (servent *src) extern "C" struct protoent * cygwin_getprotobyname (const char *p) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - return dup_ent (getprotobyname (p)); + __try + { + return dup_ent (getprotobyname (p)); + } + __except (EFAULT) {} + __endtry + return NULL; } /* exported as getprotobynumber: standards? */ @@ -731,18 +734,18 @@ extern "C" ssize_t cygwin_sendto (int fd, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { - ssize_t res; + ssize_t res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - res = fh->sendto (buf, len, flags, to, tolen); - + __try + { + fhandler_socket *fh = get (fd); + if (fh) + res = fh->sendto (buf, len, flags, to, tolen); + } + __except (EFAULT) {} + __endtry syscall_printf ("%lR = sendto(%d, %p, %ld, %y, %p, %d)", res, fd, buf, len, flags, to, tolen); return res; @@ -753,22 +756,22 @@ extern "C" ssize_t cygwin_recvfrom (int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { - ssize_t res; + ssize_t res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - /* Originally we shortcircuited here if res == 0. - Allow 0 bytes buffer. This is valid in POSIX and handled in - fhandler_socket::recv_internal. If we shortcircuit, we fail - to deliver valid error conditions and peer address. */ - res = fh->recvfrom (buf, len, flags, from, fromlen); - + __try + { + fhandler_socket *fh = get (fd); + if (fh) + /* Originally we shortcircuited here if res == 0. + Allow 0 bytes buffer. This is valid in POSIX and handled in + fhandler_socket::recv_internal. If we shortcircuit, we fail + to deliver valid error conditions and peer address. */ + res = fh->recvfrom (buf, len, flags, from, fromlen); + } + __except (EFAULT) {} + __endtry syscall_printf ("%lR = recvfrom(%d, %p, %ld, %y, %p, %p)", res, fd, buf, len, flags, from, fromlen); return res; @@ -800,14 +803,13 @@ extern "C" int cygwin_setsockopt (int fd, int level, int optname, const void *optval, socklen_t optlen) { - int res; - fhandler_socket *fh = get (fd); + int res = -1; - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else + __try { + fhandler_socket *fh = get (fd); + if (!fh) + __leave; /* Old applications still use the old WinSock1 IPPROTO_IP values. */ if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES) optname = convert_ws1_ip_optname (optname); @@ -892,7 +894,11 @@ cygwin_setsockopt (int fd, int level, int optname, const void *optval, break; } } - + __except (EFAULT) + { + res = -1; + } + __endtry syscall_printf ("%R = setsockopt(%d, %d, %y, %p, %d)", res, fd, level, optname, optval, optlen); return res; @@ -903,19 +909,19 @@ extern "C" int cygwin_getsockopt (int fd, int level, int optname, void *optval, socklen_t *optlen) { - int res; - fhandler_socket *fh = get (fd); + int res = -1; - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else if (optname == SO_PEERCRED && level == SOL_SOCKET) - { - struct ucred *cred = (struct ucred *) optval; - res = fh->getpeereid (&cred->pid, &cred->uid, &cred->gid); - } - else + __try { + fhandler_socket *fh = get (fd); + if (!fh) + __leave; + if (optname == SO_PEERCRED && level == SOL_SOCKET) + { + struct ucred *cred = (struct ucred *) optval; + res = fh->getpeereid (&cred->pid, &cred->uid, &cred->gid); + __leave; + } /* Old applications still use the old WinSock1 IPPROTO_IP values. */ if (level == IPPROTO_IP && CYGWIN_VERSION_CHECK_FOR_USING_WINSOCK1_VALUES) optname = convert_ws1_ip_optname (optname); @@ -930,7 +936,7 @@ cygwin_getsockopt (int fd, int level, int optname, void *optval, *e = find_winsock_errno (*e); } else if (*optlen == 1) - { + { /* Regression in Vista and later: instead of a 4 byte BOOL value, a 1 byte BOOLEAN value is returned, in contrast to older systems and the documentation. Since an int type is expected by the @@ -947,7 +953,11 @@ cygwin_getsockopt (int fd, int level, int optname, void *optval, } } } - + __except (EFAULT) + { + res = -1; + } + __endtry syscall_printf ("%R = getsockopt(%d, %d, %y, %p, %p)", res, fd, level, optname, optval, optlen); return res; @@ -966,20 +976,19 @@ getpeereid (int fd, uid_t *euid, gid_t *egid) extern "C" int cygwin_connect (int fd, const struct sockaddr *name, socklen_t namelen) { - int res; + int res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - res = fh->connect (name, namelen); - + __try + { + fhandler_socket *fh = get (fd); + if (fh) + res = fh->connect (name, namelen); + } + __except (EFAULT) {} + __endtry syscall_printf ("%R = connect(%d, %p, %d)", res, fd, name, namelen); - return res; } @@ -987,11 +996,14 @@ cygwin_connect (int fd, const struct sockaddr *name, socklen_t namelen) extern "C" struct servent * cygwin_getservbyname (const char *name, const char *proto) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; + servent *res = NULL; - servent *res = dup_ent (getservbyname (name, proto)); + __try + { + res = dup_ent (getservbyname (name, proto)); + } + __except (EFAULT) {} + __endtry syscall_printf ("%p = getservbyname (%s, %s)", res, name, proto); return res; } @@ -1000,11 +1012,14 @@ cygwin_getservbyname (const char *name, const char *proto) extern "C" struct servent * cygwin_getservbyport (int port, const char *proto) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; + servent *res = NULL; - servent *res = dup_ent (getservbyport (port, proto)); + __try + { + res = dup_ent (getservbyport (port, proto)); + } + __except (EFAULT) {} + __endtry syscall_printf ("%p = getservbyport (%d, %s)", res, port, proto); return res; } @@ -1012,67 +1027,77 @@ cygwin_getservbyport (int port, const char *proto) extern "C" int cygwin_gethostname (char *name, size_t len) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; + int res = -1; - if (gethostname (name, len)) + __try { - DWORD local_len = len; - - if (!GetComputerNameExA (ComputerNameDnsFullyQualified, name, &local_len)) + if (gethostname (name, len)) { - set_winsock_errno (); - return -1; + DWORD local_len = len; + + if (!GetComputerNameExA (ComputerNameDnsFullyQualified, name, + &local_len)) + { + set_winsock_errno (); + __leave; + } } + debug_printf ("name %s", name); + res = 0; } - debug_printf ("name %s", name); - return 0; + __except (EFAULT) {} + __endtry + return res; } /* exported as gethostbyname: standards? */ extern "C" struct hostent * cygwin_gethostbyname (const char *name) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - unsigned char tmp_addr[4]; struct hostent tmp, *h; char *tmp_aliases[1] = {0}; char *tmp_addr_list[2] = {0,0}; unsigned int a, b, c, d; char dummy; + hostent *res = NULL; - if (sscanf (name, "%u.%u.%u.%u%c", &a, &b, &c, &d, &dummy) != 4 - || a >= 256 || b >= 256 || c >= 256 || d >= 256) - h = gethostbyname (name); - else + __try { - /* In case you don't have DNS, at least x.x.x.x still works */ - memset (&tmp, 0, sizeof (tmp)); - tmp_addr[0] = a; - tmp_addr[1] = b; - tmp_addr[2] = c; - tmp_addr[3] = d; - tmp_addr_list[0] = (char *) tmp_addr; - tmp.h_name = name; - tmp.h_aliases = tmp_aliases; - tmp.h_addrtype = 2; - tmp.h_length = 4; - tmp.h_addr_list = tmp_addr_list; - h = &tmp; - } + if (sscanf (name, "%u.%u.%u.%u%c", &a, &b, &c, &d, &dummy) != 4 + || a >= 256 || b >= 256 || c >= 256 || d >= 256) + h = gethostbyname (name); + else + { + /* In case you don't have DNS, at least x.x.x.x still works */ + memset (&tmp, 0, sizeof (tmp)); + tmp_addr[0] = a; + tmp_addr[1] = b; + tmp_addr[2] = c; + tmp_addr[3] = d; + tmp_addr_list[0] = (char *) tmp_addr; + tmp.h_name = name; + tmp.h_aliases = tmp_aliases; + tmp.h_addrtype = 2; + tmp.h_length = 4; + tmp.h_addr_list = tmp_addr_list; + h = &tmp; + } - hostent *res = dup_ent (h); - if (res) - debug_printf ("h_name %s", res->h_name); - else - { - debug_printf ("dup_ent returned NULL for name %s, h %p", name, h); - set_host_errno (); + res = dup_ent (h); + if (res) + debug_printf ("h_name %s", res->h_name); + else + { + debug_printf ("dup_ent returned NULL for name %s, h %p", name, h); + set_host_errno (); + } } + __except (EFAULT) + { + res = NULL; + } + __endtry return res; } @@ -1080,15 +1105,21 @@ cygwin_gethostbyname (const char *name) extern "C" struct hostent * cygwin_gethostbyaddr (const char *addr, int len, int type) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; + hostent *res = NULL; - hostent *res = dup_ent (gethostbyaddr (addr, len, type)); - if (res) - debug_printf ("h_name %s", res->h_name); - else - set_host_errno (); + __try + { + res = dup_ent (gethostbyaddr (addr, len, type)); + if (res) + debug_printf ("h_name %s", res->h_name); + else + set_host_errno (); + } + __except (EFAULT) + { + res = NULL; + } + __endtry return res; } @@ -1311,51 +1342,56 @@ gethostby_helper (const char *name, const int af, const int type, extern "C" struct hostent * gethostbyname2 (const char *name, int af) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; + hostent *res = NULL; - if (!(_res.options & RES_INIT)) - res_init(); - bool v4to6 = _res.options & RES_USE_INET6; - - int type, addrsize_in, addrsize_out; - switch (af) + __try { - case AF_INET: - addrsize_in = NS_INADDRSZ; - addrsize_out = (v4to6) ? NS_IN6ADDRSZ : NS_INADDRSZ; - type = ns_t_a; - break; - case AF_INET6: - addrsize_in = addrsize_out = NS_IN6ADDRSZ; - type = ns_t_aaaa; - break; - default: - set_errno (EAFNOSUPPORT); - h_errno = NETDB_INTERNAL; - return NULL; - } + if (!(_res.options & RES_INIT)) + res_init(); + bool v4to6 = _res.options & RES_USE_INET6; - return gethostby_helper (name, af, type, addrsize_in, addrsize_out); + int type, addrsize_in, addrsize_out; + switch (af) + { + case AF_INET: + addrsize_in = NS_INADDRSZ; + addrsize_out = (v4to6) ? NS_IN6ADDRSZ : NS_INADDRSZ; + type = ns_t_a; + break; + case AF_INET6: + addrsize_in = addrsize_out = NS_IN6ADDRSZ; + type = ns_t_aaaa; + break; + default: + set_errno (EAFNOSUPPORT); + h_errno = NETDB_INTERNAL; + __leave; + } + + res = gethostby_helper (name, af, type, addrsize_in, addrsize_out); + } + __except (EFAULT) {} + __endtry + return res; } /* exported as accept: standards? */ extern "C" int cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len) { - int res; + int res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - res = fh->accept4 (peer, len, fh->is_nonblocking () ? SOCK_NONBLOCK : 0); - + __try + { + fhandler_socket *fh = get (fd); + if (fh) + res = fh->accept4 (peer, len, + fh->is_nonblocking () ? SOCK_NONBLOCK : 0); + } + __except (EFAULT) {} + __endtry syscall_printf ("%R = accept(%d, %p, %p)", res, fd, peer, len); return res; } @@ -1363,23 +1399,22 @@ cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len) extern "C" int accept4 (int fd, struct sockaddr *peer, socklen_t *len, int flags) { - int res; + int res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) + __try { - set_errno (EINVAL); - res = -1; + fhandler_socket *fh = get (fd); + if (!fh) + __leave; + if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) + set_errno (EINVAL); + else + res = fh->accept4 (peer, len, flags); } - else - res = fh->accept4 (peer, len, flags); - + __except (EFAULT) {} + __endtry syscall_printf ("%R = accept4(%d, %p, %p, %y)", res, fd, peer, len, flags); return res; } @@ -1388,15 +1423,16 @@ accept4 (int fd, struct sockaddr *peer, socklen_t *len, int flags) extern "C" int cygwin_bind (int fd, const struct sockaddr *my_addr, socklen_t addrlen) { - int res; - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - res = fh->bind (my_addr, addrlen); + int res = -1; + __try + { + fhandler_socket *fh = get (fd); + if (fh) + res = fh->bind (my_addr, addrlen); + } + __except (EFAULT) {} + __endtry syscall_printf ("%R = bind(%d, %p, %d)", res, fd, my_addr, addrlen); return res; } @@ -1405,16 +1441,16 @@ cygwin_bind (int fd, const struct sockaddr *my_addr, socklen_t addrlen) extern "C" int cygwin_getsockname (int fd, struct sockaddr *addr, socklen_t *namelen) { - int res; - - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - res = fh->getsockname (addr, namelen); + int res = -1; + __try + { + fhandler_socket *fh = get (fd); + if (fh) + res = fh->getsockname (addr, namelen); + } + __except (EFAULT) {} + __endtry syscall_printf ("%R =getsockname (%d, %p, %p)", res, fd, addr, namelen); return res; } @@ -1423,14 +1459,16 @@ cygwin_getsockname (int fd, struct sockaddr *addr, socklen_t *namelen) extern "C" int cygwin_listen (int fd, int backlog) { - int res; - fhandler_socket *fh = get (fd); - - if (!fh) - res = -1; - else - res = fh->listen (backlog); + int res = -1; + __try + { + fhandler_socket *fh = get (fd); + if (fh) + res = fh->listen (backlog); + } + __except (EFAULT) {} + __endtry syscall_printf ("%R = listen(%d, %d)", res, fd, backlog); return res; } @@ -1439,15 +1477,11 @@ cygwin_listen (int fd, int backlog) extern "C" int cygwin_shutdown (int fd, int how) { - int res; + int res = -1; fhandler_socket *fh = get (fd); - - if (!fh) - res = -1; - else + if (fh) res = fh->shutdown (how); - syscall_printf ("%R = shutdown(%d, %d)", res, fd, how); return res; } @@ -1469,51 +1503,54 @@ cygwin_hstrerror (int err) extern "C" void cygwin_herror (const char *s) { - myfault efault; - if (efault.faulted ()) - return; - if (cygheap->fdtab.not_open (2)) - return; - - if (s) + __try { - write (2, s, strlen (s)); - write (2, ": ", 2); + if (cygheap->fdtab.not_open (2)) + return; + + if (s) + { + write (2, s, strlen (s)); + write (2, ": ", 2); + } + + const char *h_errstr = cygwin_hstrerror (h_errno); + + if (!h_errstr) + switch (h_errno) + { + case NETDB_INTERNAL: + h_errstr = "Resolver internal error"; + break; + case NETDB_SUCCESS: + h_errstr = "Resolver error 0 (no error)"; + break; + default: + h_errstr = "Unknown resolver error"; + break; + } + write (2, h_errstr, strlen (h_errstr)); + write (2, "\n", 1); } - - const char *h_errstr = cygwin_hstrerror (h_errno); - - if (!h_errstr) - switch (h_errno) - { - case NETDB_INTERNAL: - h_errstr = "Resolver internal error"; - break; - case NETDB_SUCCESS: - h_errstr = "Resolver error 0 (no error)"; - break; - default: - h_errstr = "Unknown resolver error"; - break; - } - write (2, h_errstr, strlen (h_errstr)); - write (2, "\n", 1); + __except (NO_ERROR) {} + __endtry } /* exported as getpeername: standards? */ extern "C" int cygwin_getpeername (int fd, struct sockaddr *name, socklen_t *len) { - int res; - - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - res = fh->getpeername (name, len); + int res = -1; + fhandler_socket *fh = NULL; + __try + { + fh = get (fd); + if (fh) + res = fh->getpeername (name, len); + } + __except (EFAULT) {} + __endtry syscall_printf ("%R = getpeername(%d) %p", res, fd, (fh ? fh->get_socket () : (SOCKET) -1)); return res; @@ -1523,22 +1560,22 @@ cygwin_getpeername (int fd, struct sockaddr *name, socklen_t *len) extern "C" ssize_t cygwin_recv (int fd, void *buf, size_t len, int flags) { - ssize_t res; + ssize_t res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - /* Originally we shortcircuited here if res == 0. - Allow 0 bytes buffer. This is valid in POSIX and handled in - fhandler_socket::recv_internal. If we shortcircuit, we fail - to deliver valid error conditions. */ - res = fh->recvfrom (buf, len, flags, NULL, NULL); - + __try + { + fhandler_socket *fh = get (fd); + if (fh) + /* Originally we shortcircuited here if res == 0. + Allow 0 bytes buffer. This is valid in POSIX and handled in + fhandler_socket::recv_internal. If we shortcircuit, we fail + to deliver valid error conditions. */ + res = fh->recvfrom (buf, len, flags, NULL, NULL); + } + __except (EFAULT) {} + __endtry syscall_printf ("%lR = recv(%d, %p, %ld, %y)", res, fd, buf, len, flags); return res; } @@ -1547,18 +1584,18 @@ cygwin_recv (int fd, void *buf, size_t len, int flags) extern "C" ssize_t cygwin_send (int fd, const void *buf, size_t len, int flags) { - ssize_t res; + ssize_t res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else - res = fh->sendto (buf, len, flags, NULL, 0); - + __try + { + fhandler_socket *fh = get (fd); + if (fh) + res = fh->sendto (buf, len, flags, NULL, 0); + } + __except (EFAULT) + __endtry syscall_printf ("%lR = send(%d, %p, %ld, %y)", res, fd, buf, len, flags); return res; } @@ -1567,21 +1604,22 @@ cygwin_send (int fd, const void *buf, size_t len, int flags) extern "C" int getdomainname (char *domain, size_t len) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - PFIXED_INFO info = NULL; - ULONG size = 0; - - if (GetNetworkParams(info, &size) == ERROR_BUFFER_OVERFLOW - && (info = (PFIXED_INFO) alloca(size)) - && GetNetworkParams(info, &size) == ERROR_SUCCESS) + __try { - strncpy(domain, info->DomainName, len); - return 0; + PFIXED_INFO info = NULL; + ULONG size = 0; + + if (GetNetworkParams(info, &size) == ERROR_BUFFER_OVERFLOW + && (info = (PFIXED_INFO) alloca(size)) + && GetNetworkParams(info, &size) == ERROR_SUCCESS) + { + strncpy(domain, info->DomainName, len); + return 0; + } + __seterrno (); } - __seterrno (); + __except (EFAULT) + __endtry return -1; } @@ -2176,85 +2214,88 @@ freeifaddrs (struct ifaddrs *ifp) int get_ifconf (struct ifconf *ifc, int what) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - /* Ensure we have space for at least one struct ifreqs, fail if not. */ - if (ifc->ifc_len < (int) sizeof (struct ifreq)) + __try { - set_errno (EINVAL); - return -1; - } - - struct ifall *ifret, *ifp; - ifret = get_ifs (AF_INET); - if (!ifret) - return -1; - - struct sockaddr_in *sin; - struct ifreq *ifr = ifc->ifc_req; - int cnt = 0; - for (ifp = ifret; ifp; ifp = (struct ifall *) ifp->ifa_ifa.ifa_next) - { - ++cnt; - strcpy (ifr->ifr_name, ifp->ifa_name); - switch (what) + /* Ensure we have space for at least one struct ifreqs, fail if not. */ + if (ifc->ifc_len < (int) sizeof (struct ifreq)) { - case SIOCGIFFLAGS: - ifr->ifr_flags = ifp->ifa_ifa.ifa_flags; - break; - case SIOCGIFCONF: - case SIOCGIFADDR: - sin = (struct sockaddr_in *) &ifr->ifr_addr; - memcpy (sin, &ifp->ifa_addr, sizeof *sin); - break; - case SIOCGIFNETMASK: - sin = (struct sockaddr_in *) &ifr->ifr_netmask; - memcpy (sin, &ifp->ifa_netmask, sizeof *sin); - break; - case SIOCGIFDSTADDR: - sin = (struct sockaddr_in *) &ifr->ifr_dstaddr; - if (ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT) - memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin); - else /* Return addr as on Linux. */ - memcpy (sin, &ifp->ifa_addr, sizeof *sin); - break; - case SIOCGIFBRDADDR: - sin = (struct sockaddr_in *) &ifr->ifr_broadaddr; - if (!(ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT)) - memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin); - else - { - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_family = AF_INET; - sin->sin_port = 0; - } - break; - case SIOCGIFHWADDR: - memcpy (&ifr->ifr_hwaddr, &ifp->ifa_hwaddr, sizeof ifr->ifr_hwaddr); - break; - case SIOCGIFMETRIC: - ifr->ifr_metric = ifp->ifa_metric; - break; - case SIOCGIFMTU: - ifr->ifr_mtu = ifp->ifa_mtu; - break; - case SIOCGIFINDEX: - ifr->ifr_ifindex = ifp->ifa_ifindex; - break; - case SIOCGIFFRNDLYNAM: - memcpy (ifr->ifr_frndlyname, &ifp->ifa_frndlyname, - sizeof (struct ifreq_frndlyname)); + set_errno (EINVAL); + __leave; } - if ((caddr_t) ++ifr > - ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq)) - break; + + struct ifall *ifret, *ifp; + ifret = get_ifs (AF_INET); + if (!ifret) + __leave; + + struct sockaddr_in *sin; + struct ifreq *ifr = ifc->ifc_req; + int cnt = 0; + for (ifp = ifret; ifp; ifp = (struct ifall *) ifp->ifa_ifa.ifa_next) + { + ++cnt; + strcpy (ifr->ifr_name, ifp->ifa_name); + switch (what) + { + case SIOCGIFFLAGS: + ifr->ifr_flags = ifp->ifa_ifa.ifa_flags; + break; + case SIOCGIFCONF: + case SIOCGIFADDR: + sin = (struct sockaddr_in *) &ifr->ifr_addr; + memcpy (sin, &ifp->ifa_addr, sizeof *sin); + break; + case SIOCGIFNETMASK: + sin = (struct sockaddr_in *) &ifr->ifr_netmask; + memcpy (sin, &ifp->ifa_netmask, sizeof *sin); + break; + case SIOCGIFDSTADDR: + sin = (struct sockaddr_in *) &ifr->ifr_dstaddr; + if (ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT) + memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin); + else /* Return addr as on Linux. */ + memcpy (sin, &ifp->ifa_addr, sizeof *sin); + break; + case SIOCGIFBRDADDR: + sin = (struct sockaddr_in *) &ifr->ifr_broadaddr; + if (!(ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT)) + memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin); + else + { + sin->sin_addr.s_addr = INADDR_ANY; + sin->sin_family = AF_INET; + sin->sin_port = 0; + } + break; + case SIOCGIFHWADDR: + memcpy (&ifr->ifr_hwaddr, &ifp->ifa_hwaddr, + sizeof ifr->ifr_hwaddr); + break; + case SIOCGIFMETRIC: + ifr->ifr_metric = ifp->ifa_metric; + break; + case SIOCGIFMTU: + ifr->ifr_mtu = ifp->ifa_mtu; + break; + case SIOCGIFINDEX: + ifr->ifr_ifindex = ifp->ifa_ifindex; + break; + case SIOCGIFFRNDLYNAM: + memcpy (ifr->ifr_frndlyname, &ifp->ifa_frndlyname, + sizeof (struct ifreq_frndlyname)); + } + if ((caddr_t) ++ifr > + ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq)) + break; + } + /* Set the correct length */ + ifc->ifc_len = cnt * sizeof (struct ifreq); + free (ifret); + return 0; } - /* Set the correct length */ - ifc->ifc_len = cnt * sizeof (struct ifreq); - free (ifret); - return 0; + __except (EFAULT) {} + __endtry + return -1; } extern "C" unsigned @@ -2263,26 +2304,30 @@ if_nametoindex (const char *name) PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; unsigned index = 0; - myfault efault; - if (efault.faulted (EFAULT)) - return 0; - - if (get_adapters_addresses (&pa0, AF_UNSPEC)) + __try { - char lname[IF_NAMESIZE], *c; + if (get_adapters_addresses (&pa0, AF_UNSPEC)) + { + char lname[IF_NAMESIZE], *c; - lname[0] = '\0'; - strncat (lname, name, IF_NAMESIZE - 1); - if (lname[0] == '{' && (c = strchr (lname, ':'))) - *c = '\0'; - for (pap = pa0; pap; pap = pap->Next) - if (strcasematch (lname, pap->AdapterName)) - { - index = pap->Ipv6IfIndex ?: pap->IfIndex; - break; - } - free (pa0); + lname[0] = '\0'; + strncat (lname, name, IF_NAMESIZE - 1); + if (lname[0] == '{' && (c = strchr (lname, ':'))) + *c = '\0'; + for (pap = pa0; pap; pap = pap->Next) + if (strcasematch (lname, pap->AdapterName)) + { + index = pap->Ipv6IfIndex ?: pap->IfIndex; + break; + } + free (pa0); + } } + __except (EFAULT) + { + index = 0; + } + __endtry return index; } @@ -2292,35 +2337,38 @@ if_indextoname (unsigned ifindex, char *ifname) PIP_ADAPTER_ADDRESSES pa0 = NULL, pap; char *name = NULL; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - - if (get_adapters_addresses (&pa0, AF_UNSPEC)) + __try { - for (pap = pa0; pap; pap = pap->Next) - if (ifindex == (pap->Ipv6IfIndex ?: pap->IfIndex)) - { - /* Unfortunately the pre-Vista IPv6 stack has a distinct loopback - device with the same Ipv6IfIndex as the IfIndex of the IPv4 - loopback device, but with a different adapter name. - For consistency with /proc/net/if_inet6, try to find the - IPv6 loopback device and use that adapter name instead. - We identify the loopback device by its IfIndex of 1. */ - if (pap->IfIndex == 1 && pap->Ipv6IfIndex == 0) - for (PIP_ADAPTER_ADDRESSES pap2 = pa0; pap2; pap2 = pap2->Next) - if (pap2->Ipv6IfIndex == 1) - { - pap = pap2; - break; - } - name = strcpy (ifname, pap->AdapterName); - break; - } - free (pa0); + if (get_adapters_addresses (&pa0, AF_UNSPEC)) + { + for (pap = pa0; pap; pap = pap->Next) + if (ifindex == (pap->Ipv6IfIndex ?: pap->IfIndex)) + { + /* Unfortunately the pre-Vista IPv6 stack has a distinct + loopback device with the same Ipv6IfIndex as the IfIndex + of the IPv4 loopback device, but with a different adapter + name. For consistency with /proc/net/if_inet6, try to find + the IPv6 loopback device and use that adapter name instead. + We identify the loopback device by its IfIndex of 1. */ + if (pap->IfIndex == 1 && pap->Ipv6IfIndex == 0) + for (PIP_ADAPTER_ADDRESSES pap2 = pa0; + pap2; + pap2 = pap2->Next) + if (pap2->Ipv6IfIndex == 1) + { + pap = pap2; + break; + } + name = strcpy (ifname, pap->AdapterName); + break; + } + free (pa0); + } + else + set_errno (ENXIO); } - else - set_errno (ENXIO); + __except (EFAULT) {} + __endtry return name; } @@ -2331,49 +2379,54 @@ if_nameindex (void) struct if_nameindex *iflist = NULL; char (*ifnamelist)[IF_NAMESIZE]; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - - if (get_adapters_addresses (&pa0, AF_UNSPEC)) + __try { - int cnt = 0; - for (pap = pa0; pap; pap = pap->Next) - ++cnt; - iflist = (struct if_nameindex *) - malloc ((cnt + 1) * sizeof (struct if_nameindex) - + cnt * IF_NAMESIZE); - if (!iflist) - set_errno (ENOBUFS); - else + if (get_adapters_addresses (&pa0, AF_UNSPEC)) { - ifnamelist = (char (*)[IF_NAMESIZE]) (iflist + cnt + 1); - for (pap = pa0, cnt = 0; pap; pap = pap->Next) + int cnt = 0; + for (pap = pa0; pap; pap = pap->Next) + ++cnt; + iflist = (struct if_nameindex *) + malloc ((cnt + 1) * sizeof (struct if_nameindex) + + cnt * IF_NAMESIZE); + if (!iflist) + set_errno (ENOBUFS); + else { - for (int i = 0; i < cnt; ++i) - if (iflist[i].if_index == (pap->Ipv6IfIndex ?: pap->IfIndex)) - goto outer_loop; - iflist[cnt].if_index = pap->Ipv6IfIndex ?: pap->IfIndex; - strcpy (iflist[cnt].if_name = ifnamelist[cnt], pap->AdapterName); - /* See comment in if_indextoname. */ - if (pap->IfIndex == 1 && pap->Ipv6IfIndex == 0) - for (PIP_ADAPTER_ADDRESSES pap2 = pa0; pap2; pap2 = pap2->Next) - if (pap2->Ipv6IfIndex == 1) - { - strcpy (ifnamelist[cnt], pap2->AdapterName); - break; - } - ++cnt; - outer_loop: - ; + ifnamelist = (char (*)[IF_NAMESIZE]) (iflist + cnt + 1); + for (pap = pa0, cnt = 0; pap; pap = pap->Next) + { + for (int i = 0; i < cnt; ++i) + if (iflist[i].if_index + == (pap->Ipv6IfIndex ?: pap->IfIndex)) + goto outer_loop; + iflist[cnt].if_index = pap->Ipv6IfIndex ?: pap->IfIndex; + strcpy (iflist[cnt].if_name = ifnamelist[cnt], + pap->AdapterName); + /* See comment in if_indextoname. */ + if (pap->IfIndex == 1 && pap->Ipv6IfIndex == 0) + for (PIP_ADAPTER_ADDRESSES pap2 = pa0; + pap2; + pap2 = pap2->Next) + if (pap2->Ipv6IfIndex == 1) + { + strcpy (ifnamelist[cnt], pap2->AdapterName); + break; + } + ++cnt; + outer_loop: + ; + } + iflist[cnt].if_index = 0; + iflist[cnt].if_name = NULL; } - iflist[cnt].if_index = 0; - iflist[cnt].if_name = NULL; + free (pa0); } - free (pa0); + else + set_errno (ENXIO); } - else - set_errno (ENXIO); + __except (EFAULT) {} + __endtry return iflist; } @@ -2395,72 +2448,75 @@ cygwin_bindresvport_sa (int fd, struct sockaddr *sa) struct sockaddr_in6 *sin6 = NULL; in_port_t port; socklen_t salen; - int ret; + int ret = -1; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - fhandler_socket *fh = get (fd); - if (!fh) - return -1; - - if (!sa) + __try { - sa = (struct sockaddr *) &sst; - memset (&sst, 0, sizeof sst); - sa->sa_family = fh->get_addr_family (); + fhandler_socket *fh = get (fd); + if (!fh) + __leave; + + if (!sa) + { + sa = (struct sockaddr *) &sst; + memset (&sst, 0, sizeof sst); + sa->sa_family = fh->get_addr_family (); + } + + switch (sa->sa_family) + { + case AF_INET: + salen = sizeof (struct sockaddr_in); + sin = (struct sockaddr_in *) sa; + port = sin->sin_port; + break; + case AF_INET6: + salen = sizeof (struct sockaddr_in6); + sin6 = (struct sockaddr_in6 *) sa; + port = sin6->sin6_port; + break; + default: + set_errno (EPFNOSUPPORT); + __leave; + } + + /* If a non-zero port number is given, try this first. If that succeeds, + or if the error message is serious, return. */ + if (port) + { + ret = fh->bind (sa, salen); + if (!ret || (get_errno () != EADDRINUSE && get_errno () != EINVAL)) + __leave; + } + + LONG myport; + + for (int i = 0; i < NUM_PORTS; i++) + { + while ((myport = InterlockedExchange ( + &cygwin_shared->last_used_bindresvport, -1)) == -1) + yield (); + if (myport == 0 || --myport < PORT_LOW) + myport = PORT_HIGH; + InterlockedExchange (&cygwin_shared->last_used_bindresvport, myport); + + if (sa->sa_family == AF_INET6) + sin6->sin6_port = htons (myport); + else + sin->sin_port = htons (myport); + if (!(ret = fh->bind (sa, salen))) + break; + if (get_errno () != EADDRINUSE && get_errno () != EINVAL) + break; + } + } - - switch (sa->sa_family) - { - case AF_INET: - salen = sizeof (struct sockaddr_in); - sin = (struct sockaddr_in *) sa; - port = sin->sin_port; - break; - case AF_INET6: - salen = sizeof (struct sockaddr_in6); - sin6 = (struct sockaddr_in6 *) sa; - port = sin6->sin6_port; - break; - default: - set_errno (EPFNOSUPPORT); - return -1; - } - - /* If a non-zero port number is given, try this first. If that succeeds, - or if the error message is serious, return. */ - if (port) - { - ret = fh->bind (sa, salen); - if (!ret || (get_errno () != EADDRINUSE && get_errno () != EINVAL)) - return ret; - } - - LONG myport; - - for (int i = 0; i < NUM_PORTS; i++) - { - while ((myport = InterlockedExchange (&cygwin_shared->last_used_bindresvport, -1)) == -1) - yield (); - if (myport == 0 || --myport < PORT_LOW) - myport = PORT_HIGH; - InterlockedExchange (&cygwin_shared->last_used_bindresvport, myport); - - if (sa->sa_family == AF_INET6) - sin6->sin6_port = htons (myport); - else - sin->sin_port = htons (myport); - if (!(ret = fh->bind (sa, salen))) - break; - if (get_errno () != EADDRINUSE && get_errno () != EINVAL) - break; - } - + __except (EFAULT) {} + __endtry return ret; } + extern "C" int cygwin_bindresvport (int fd, struct sockaddr_in *sin) { @@ -2473,204 +2529,195 @@ extern "C" int socketpair (int family, int type, int protocol, int *sb) { int res = -1; - SOCKET insock, outsock, newsock; + SOCKET insock = INVALID_SOCKET; + SOCKET outsock = INVALID_SOCKET; + SOCKET newsock = INVALID_SOCKET; struct sockaddr_in sock_in, sock_out; int len; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; + __try + { + int flags = type & _SOCK_FLAG_MASK; + type &= ~_SOCK_FLAG_MASK; - int flags = type & _SOCK_FLAG_MASK; - type &= ~_SOCK_FLAG_MASK; + if (family != AF_LOCAL && family != AF_INET) + { + set_errno (EAFNOSUPPORT); + __leave; + } + if (type != SOCK_STREAM && type != SOCK_DGRAM) + { + set_errno (EPROTOTYPE); + __leave; + } + if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) + { + set_errno (EINVAL); + __leave; + } + if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL) + || (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET)) + { + set_errno (EPROTONOSUPPORT); + __leave; + } - if (family != AF_LOCAL && family != AF_INET) - { - set_errno (EAFNOSUPPORT); - goto done; - } - if (type != SOCK_STREAM && type != SOCK_DGRAM) - { - set_errno (EPROTOTYPE); - goto done; - } - if ((flags & ~(SOCK_NONBLOCK | SOCK_CLOEXEC)) != 0) - { - set_errno (EINVAL); - goto done; - } - if ((family == AF_LOCAL && protocol != PF_UNSPEC && protocol != PF_LOCAL) - || (family == AF_INET && protocol != PF_UNSPEC && protocol != PF_INET)) - { - set_errno (EPROTONOSUPPORT); - goto done; - } + /* create the first socket */ + newsock = socket (AF_INET, type, 0); + if (newsock == INVALID_SOCKET) + { + debug_printf ("first socket call failed"); + set_winsock_errno (); + __leave; + } - /* create the first socket */ - newsock = socket (AF_INET, type, 0); - if (newsock == INVALID_SOCKET) - { - debug_printf ("first socket call failed"); - set_winsock_errno (); - goto done; - } - - /* bind the socket to any unused port */ - sock_in.sin_family = AF_INET; - sock_in.sin_port = 0; - sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) - { - debug_printf ("bind failed"); - set_winsock_errno (); - closesocket (newsock); - goto done; - } - len = sizeof (sock_in); - if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0) - { - debug_printf ("getsockname error"); - set_winsock_errno (); - closesocket (newsock); - goto done; - } - - /* For stream sockets, create a listener */ - if (type == SOCK_STREAM) - listen (newsock, 2); - - /* create a connecting socket */ - outsock = socket (AF_INET, type, 0); - if (outsock == INVALID_SOCKET) - { - debug_printf ("second socket call failed"); - set_winsock_errno (); - closesocket (newsock); - goto done; - } - - /* For datagram sockets, bind the 2nd socket to an unused address, too */ - if (type == SOCK_DGRAM) - { - sock_out.sin_family = AF_INET; - sock_out.sin_port = 0; - sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0) + /* bind the socket to any unused port */ + sock_in.sin_family = AF_INET; + sock_in.sin_port = 0; + sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (bind (newsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) { debug_printf ("bind failed"); set_winsock_errno (); - closesocket (newsock); - closesocket (outsock); - goto done; + __leave; } - len = sizeof (sock_out); - if (getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0) + len = sizeof (sock_in); + if (getsockname (newsock, (struct sockaddr *) &sock_in, &len) < 0) { debug_printf ("getsockname error"); set_winsock_errno (); - closesocket (newsock); - closesocket (outsock); - goto done; + __leave; } - } - /* Force IP address to loopback */ - sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - if (type == SOCK_DGRAM) - sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + /* For stream sockets, create a listener */ + if (type == SOCK_STREAM) + listen (newsock, 2); - /* Do a connect */ - if (connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) - { - debug_printf ("connect error"); - set_winsock_errno (); - closesocket (newsock); - closesocket (outsock); - goto done; - } - - if (type == SOCK_STREAM) - { - /* For stream sockets, accept the connection and close the listener */ - len = sizeof (sock_in); - insock = accept (newsock, (struct sockaddr *) &sock_in, &len); - if (insock == INVALID_SOCKET) + /* create a connecting socket */ + outsock = socket (AF_INET, type, 0); + if (outsock == INVALID_SOCKET) { - debug_printf ("accept error"); + debug_printf ("second socket call failed"); set_winsock_errno (); - closesocket (newsock); - closesocket (outsock); - goto done; + __leave; } - closesocket (newsock); - } - else - { - /* For datagram sockets, connect the 2nd socket */ - if (connect (newsock, (struct sockaddr *) &sock_out, - sizeof (sock_out)) < 0) + + /* For datagram sockets, bind the 2nd socket to an unused address, too */ + if (type == SOCK_DGRAM) + { + sock_out.sin_family = AF_INET; + sock_out.sin_port = 0; + sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (bind (outsock, (struct sockaddr *) &sock_out, sizeof (sock_out)) < 0) + { + debug_printf ("bind failed"); + set_winsock_errno (); + __leave; + } + len = sizeof (sock_out); + if (getsockname (outsock, (struct sockaddr *) &sock_out, &len) < 0) + { + debug_printf ("getsockname error"); + set_winsock_errno (); + __leave; + } + } + + /* Force IP address to loopback */ + sock_in.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (type == SOCK_DGRAM) + sock_out.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + /* Do a connect */ + if (connect (outsock, (struct sockaddr *) &sock_in, sizeof (sock_in)) < 0) { debug_printf ("connect error"); set_winsock_errno (); - closesocket (newsock); - closesocket (outsock); - goto done; + __leave; + } + + if (type == SOCK_STREAM) + { + /* For stream sockets, accept the connection and close the listener */ + len = sizeof (sock_in); + insock = accept (newsock, (struct sockaddr *) &sock_in, &len); + if (insock == INVALID_SOCKET) + { + debug_printf ("accept error"); + set_winsock_errno (); + __leave; + } + closesocket (newsock); + newsock = INVALID_SOCKET; + } + else + { + /* For datagram sockets, connect the 2nd socket */ + if (connect (newsock, (struct sockaddr *) &sock_out, + sizeof (sock_out)) < 0) + { + debug_printf ("connect error"); + set_winsock_errno (); + __leave; + } + insock = newsock; + newsock = INVALID_SOCKET; + } + + cygheap_fdnew sb0; + const device *dev; + + if (family == AF_INET) + dev = (type == SOCK_STREAM ? tcp_dev : udp_dev); + else + dev = (type == SOCK_STREAM ? stream_dev : dgram_dev); + + if (sb0 >= 0 && fdsock (sb0, dev, insock)) + { + ((fhandler_socket *) sb0)->set_addr_family (family); + ((fhandler_socket *) sb0)->set_socket_type (type); + ((fhandler_socket *) sb0)->connect_state (connected); + if (flags & SOCK_NONBLOCK) + ((fhandler_socket *) sb0)->set_nonblocking (true); + if (flags & SOCK_CLOEXEC) + ((fhandler_socket *) sb0)->set_close_on_exec (true); + if (family == AF_LOCAL && type == SOCK_STREAM) + ((fhandler_socket *) sb0)->af_local_set_sockpair_cred (); + + cygheap_fdnew sb1 (sb0, false); + + if (sb1 >= 0 && fdsock (sb1, dev, outsock)) + { + ((fhandler_socket *) sb1)->set_addr_family (family); + ((fhandler_socket *) sb1)->set_socket_type (type); + ((fhandler_socket *) sb1)->connect_state (connected); + if (flags & SOCK_NONBLOCK) + ((fhandler_socket *) sb1)->set_nonblocking (true); + if (flags & SOCK_CLOEXEC) + ((fhandler_socket *) sb1)->set_close_on_exec (true); + if (family == AF_LOCAL && type == SOCK_STREAM) + ((fhandler_socket *) sb1)->af_local_set_sockpair_cred (); + + sb[0] = sb0; + sb[1] = sb1; + res = 0; + } + else + sb0.release (); } - insock = newsock; } - - { - cygheap_fdnew sb0; - const device *dev; - - if (family == AF_INET) - dev = (type == SOCK_STREAM ? tcp_dev : udp_dev); - else - dev = (type == SOCK_STREAM ? stream_dev : dgram_dev); - - if (sb0 >= 0 && fdsock (sb0, dev, insock)) - { - ((fhandler_socket *) sb0)->set_addr_family (family); - ((fhandler_socket *) sb0)->set_socket_type (type); - ((fhandler_socket *) sb0)->connect_state (connected); - if (flags & SOCK_NONBLOCK) - ((fhandler_socket *) sb0)->set_nonblocking (true); - if (flags & SOCK_CLOEXEC) - ((fhandler_socket *) sb0)->set_close_on_exec (true); - if (family == AF_LOCAL && type == SOCK_STREAM) - ((fhandler_socket *) sb0)->af_local_set_sockpair_cred (); - - cygheap_fdnew sb1 (sb0, false); - - if (sb1 >= 0 && fdsock (sb1, dev, outsock)) - { - ((fhandler_socket *) sb1)->set_addr_family (family); - ((fhandler_socket *) sb1)->set_socket_type (type); - ((fhandler_socket *) sb1)->connect_state (connected); - if (flags & SOCK_NONBLOCK) - ((fhandler_socket *) sb1)->set_nonblocking (true); - if (flags & SOCK_CLOEXEC) - ((fhandler_socket *) sb1)->set_close_on_exec (true); - if (family == AF_LOCAL && type == SOCK_STREAM) - ((fhandler_socket *) sb1)->af_local_set_sockpair_cred (); - - sb[0] = sb0; - sb[1] = sb1; - res = 0; - } - else - sb0.release (); - } - - if (res == -1) - { - closesocket (insock); - closesocket (outsock); - } - } - -done: + __except (EFAULT) {} + __endtry syscall_printf ("%R = socketpair(...)", res); + if (res == -1) + { + if (insock != INVALID_SOCKET) + closesocket (insock); + if (outsock != INVALID_SOCKET) + closesocket (outsock); + if (newsock != INVALID_SOCKET) + closesocket (newsock); + } return res; } @@ -2690,26 +2737,29 @@ endhostent (void) extern "C" ssize_t cygwin_recvmsg (int fd, struct msghdr *msg, int flags) { - ssize_t res; + ssize_t res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else + __try { - res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen); - /* Originally we shortcircuited here if res == 0. - Allow 0 bytes buffer. This is valid in POSIX and handled in - fhandler_socket::recv_internal. If we shortcircuit, we fail - to deliver valid error conditions and peer address. */ - if (res >= 0) - res = fh->recvmsg (msg, flags); + fhandler_socket *fh = get (fd); + if (fh) + { + res = check_iovec_for_read (msg->msg_iov, msg->msg_iovlen); + /* Originally we shortcircuited here if res == 0. + Allow 0 bytes buffer. This is valid in POSIX and handled in + fhandler_socket::recv_internal. If we shortcircuit, we fail + to deliver valid error conditions and peer address. */ + if (res >= 0) + res = fh->recvmsg (msg, flags); + } } - + __except (EFAULT) + { + res = -1; + } + __endtry syscall_printf ("%lR = recvmsg(%d, %p, %y)", res, fd, msg, flags); return res; } @@ -2718,22 +2768,25 @@ cygwin_recvmsg (int fd, struct msghdr *msg, int flags) extern "C" ssize_t cygwin_sendmsg (int fd, const struct msghdr *msg, int flags) { - ssize_t res; + ssize_t res = -1; pthread_testcancel (); - fhandler_socket *fh = get (fd); - - myfault efault; - if (efault.faulted (EFAULT) || !fh) - res = -1; - else + __try { - res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen); - if (res >= 0) - res = fh->sendmsg (msg, flags); + fhandler_socket *fh = get (fd); + if (fh) + { + res = check_iovec_for_write (msg->msg_iov, msg->msg_iovlen); + if (res >= 0) + res = fh->sendmsg (msg, flags); + } } - + __except (EFAULT) + { + res = -1; + } + __endtry syscall_printf ("%lR = sendmsg(%d, %p, %y)", res, fd, msg, flags); return res; } @@ -3108,10 +3161,6 @@ cygwin_freeaddrinfo (struct addrinfo *addr) { struct addrinfo *ai, *ainext; - myfault efault; - if (efault.faulted (EFAULT)) - return; - for (ai = addr; ai != NULL; ai = ainext) { if (ai->ai_addr != NULL) @@ -3287,9 +3336,8 @@ extern "C" int cygwin_getaddrinfo (const char *hostname, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { - myfault efault; - if (efault.faulted (EFAULT)) - return EAI_SYSTEM; + int ret = 0; + /* Windows' getaddrinfo implementations lets all possible values in ai_flags slip through and just ignores unknown values. So we check manually here. */ @@ -3300,140 +3348,148 @@ cygwin_getaddrinfo (const char *hostname, const char *servname, #ifndef AI_DISABLE_IDN_ENCODING #define AI_DISABLE_IDN_ENCODING 0x80000 #endif - if (hints && (hints->ai_flags - & ~(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_ALL - | AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED - | AI_IDN_MASK))) - return EAI_BADFLAGS; - /* AI_NUMERICSERV is not supported prior to Windows Vista. We just check - the servname parameter by ourselves here. */ - if (hints && (hints->ai_flags & AI_NUMERICSERV)) + __try { - char *p; - if (servname && *servname && (strtoul (servname, &p, 10), *p)) - return EAI_NONAME; - } - - int idn_flags = hints ? (hints->ai_flags & AI_IDN_MASK) : 0; - const char *src; - mbstate_t ps; - tmp_pathbuf tp; - wchar_t *whost = NULL, *wserv = NULL; - struct addrinfoW whints, *wres; - - if (hostname) - { - memset (&ps, 0, sizeof ps); - src = hostname; - whost = tp.w_get (); - if (mbsrtowcs (whost, &src, NT_MAX_PATH, &ps) == (size_t) -1) - return EAI_IDN_ENCODE; - if (src) - return EAI_MEMORY; - if (idn_flags & AI_IDN) + if (hints && (hints->ai_flags + & ~(AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST | AI_ALL + | AI_NUMERICSERV | AI_ADDRCONFIG | AI_V4MAPPED + | AI_IDN_MASK))) + return EAI_BADFLAGS; + /* AI_NUMERICSERV is not supported prior to Windows Vista. We just check + the servname parameter by ourselves here. */ + if (hints && (hints->ai_flags & AI_NUMERICSERV)) { - /* Map flags to equivalent IDN_* flags. */ - wchar_t *ascbuf = tp.w_get (); - if (IdnToAscii (idn_flags >> 16, whost, -1, ascbuf, NT_MAX_PATH)) - whost = ascbuf; - else if (GetLastError () != ERROR_PROC_NOT_FOUND) + char *p; + if (servname && *servname && (strtoul (servname, &p, 10), *p)) + return EAI_NONAME; + } + + int idn_flags = hints ? (hints->ai_flags & AI_IDN_MASK) : 0; + const char *src; + mbstate_t ps; + tmp_pathbuf tp; + wchar_t *whost = NULL, *wserv = NULL; + struct addrinfoW whints, *wres; + + if (hostname) + { + memset (&ps, 0, sizeof ps); + src = hostname; + whost = tp.w_get (); + if (mbsrtowcs (whost, &src, NT_MAX_PATH, &ps) == (size_t) -1) return EAI_IDN_ENCODE; + if (src) + return EAI_MEMORY; + if (idn_flags & AI_IDN) + { + /* Map flags to equivalent IDN_* flags. */ + wchar_t *ascbuf = tp.w_get (); + if (IdnToAscii (idn_flags >> 16, whost, -1, ascbuf, NT_MAX_PATH)) + whost = ascbuf; + else if (GetLastError () != ERROR_PROC_NOT_FOUND) + return EAI_IDN_ENCODE; + } } - } - if (servname) - { - memset (&ps, 0, sizeof ps); - src = servname; - wserv = tp.w_get (); - if (mbsrtowcs (wserv, &src, NT_MAX_PATH, &ps) == (size_t) -1) - return EAI_IDN_ENCODE; - if (src) - return EAI_MEMORY; - } - - if (!hints) - { - /* Default settings per glibc man page. */ - memset (&whints, 0, sizeof whints); - whints.ai_family = PF_UNSPEC; - whints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; - } - else - { - /* sizeof addrinfo == sizeof addrinfoW */ - memcpy (&whints, hints, sizeof whints); - whints.ai_flags &= ~AI_IDN_MASK; -#ifdef __x86_64__ - /* ai_addrlen is socklen_t (4 bytes) in POSIX but size_t (8 bytes) in - Winsock. Sert upper 4 bytes explicitely to 0 to avoid EAI_FAIL. */ - whints.ai_addrlen &= UINT32_MAX; -#endif - /* AI_ADDRCONFIG is not supported prior to Vista. Rather it's - the default and only possible setting. - On Vista, the default behaviour is as if AI_ADDRCONFIG is set, - apparently for performance reasons. To get the POSIX default - behaviour, the AI_ALL flag has to be set. */ - if (wincap.supports_all_posix_ai_flags () - && whints.ai_family == PF_UNSPEC - && !(whints.ai_flags & AI_ADDRCONFIG)) - whints.ai_flags |= AI_ALL; - } - /* Disable automatic IDN conversion on W8 and later. */ - whints.ai_flags |= AI_DISABLE_IDN_ENCODING; - int ret = w32_to_gai_err (GetAddrInfoW (whost, wserv, &whints, &wres)); - /* Always copy over to self-allocated memory. */ - if (!ret) - { - *res = ga_duplist (wres, false, idn_flags, ret); - FreeAddrInfoW (wres); - if (!*res) - return ret; - } - /* AI_V4MAPPED and AI_ALL are not supported prior to Vista. So, what - we do here is to emulate AI_V4MAPPED. If no IPv6 addresses are - returned, or the AI_ALL flag is set, we try with AF_INET again, and - convert the returned IPv4 addresses into v4-in-v6 entries. This - is done in ga_dup if the v4mapped flag is set. */ - if (!wincap.supports_all_posix_ai_flags () - && hints - && hints->ai_family == AF_INET6 - && (hints->ai_flags & AI_V4MAPPED) - && (ret == EAI_NODATA || ret == EAI_NONAME - || (hints->ai_flags & AI_ALL))) - { - /* sizeof addrinfo == sizeof addrinfoW */ - memcpy (&whints, hints, sizeof whints); - whints.ai_family = AF_INET; -#ifdef __x86_64__ - /* ai_addrlen is socklen_t (4 bytes) in POSIX but size_t (8 bytes) in - Winsock. Sert upper 4 bytes explicitely to 0 to avoid EAI_FAIL. */ - whints.ai_addrlen &= UINT32_MAX; -#endif - int ret2 = w32_to_gai_err (GetAddrInfoW (whost, wserv, &whints, &wres)); - if (!ret2) + if (servname) { - struct addrinfo *v4res = ga_duplist (wres, true, idn_flags, ret); + memset (&ps, 0, sizeof ps); + src = servname; + wserv = tp.w_get (); + if (mbsrtowcs (wserv, &src, NT_MAX_PATH, &ps) == (size_t) -1) + return EAI_IDN_ENCODE; + if (src) + return EAI_MEMORY; + } + + if (!hints) + { + /* Default settings per glibc man page. */ + memset (&whints, 0, sizeof whints); + whints.ai_family = PF_UNSPEC; + whints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; + } + else + { + /* sizeof addrinfo == sizeof addrinfoW */ + memcpy (&whints, hints, sizeof whints); + whints.ai_flags &= ~AI_IDN_MASK; +#ifdef __x86_64__ + /* ai_addrlen is socklen_t (4 bytes) in POSIX but size_t (8 bytes) in + Winsock. Sert upper 4 bytes explicitely to 0 to avoid EAI_FAIL. */ + whints.ai_addrlen &= UINT32_MAX; +#endif + /* AI_ADDRCONFIG is not supported prior to Vista. Rather it's + the default and only possible setting. + On Vista, the default behaviour is as if AI_ADDRCONFIG is set, + apparently for performance reasons. To get the POSIX default + behaviour, the AI_ALL flag has to be set. */ + if (wincap.supports_all_posix_ai_flags () + && whints.ai_family == PF_UNSPEC + && !(whints.ai_flags & AI_ADDRCONFIG)) + whints.ai_flags |= AI_ALL; + } + /* Disable automatic IDN conversion on W8 and later. */ + whints.ai_flags |= AI_DISABLE_IDN_ENCODING; + ret = w32_to_gai_err (GetAddrInfoW (whost, wserv, &whints, &wres)); + /* Always copy over to self-allocated memory. */ + if (!ret) + { + *res = ga_duplist (wres, false, idn_flags, ret); FreeAddrInfoW (wres); - if (!v4res) + if (!*res) + __leave; + } + /* AI_V4MAPPED and AI_ALL are not supported prior to Vista. So, what + we do here is to emulate AI_V4MAPPED. If no IPv6 addresses are + returned, or the AI_ALL flag is set, we try with AF_INET again, and + convert the returned IPv4 addresses into v4-in-v6 entries. This + is done in ga_dup if the v4mapped flag is set. */ + if (!wincap.supports_all_posix_ai_flags () + && hints + && hints->ai_family == AF_INET6 + && (hints->ai_flags & AI_V4MAPPED) + && (ret == EAI_NODATA || ret == EAI_NONAME + || (hints->ai_flags & AI_ALL))) + { + /* sizeof addrinfo == sizeof addrinfoW */ + memcpy (&whints, hints, sizeof whints); + whints.ai_family = AF_INET; +#ifdef __x86_64__ + /* ai_addrlen is socklen_t (4 bytes) in POSIX but size_t (8 bytes) in + Winsock. Sert upper 4 bytes explicitely to 0 to avoid EAI_FAIL. */ + whints.ai_addrlen &= UINT32_MAX; +#endif + int ret2 = w32_to_gai_err (GetAddrInfoW (whost, wserv, &whints, &wres)); + if (!ret2) { + struct addrinfo *v4res = ga_duplist (wres, true, idn_flags, ret); + FreeAddrInfoW (wres); + if (!v4res) + { + if (!ret) + cygwin_freeaddrinfo (*res); + __leave; + } + /* If a list of v6 addresses exists, append the v4-in-v6 address + list. Otherwise just return the v4-in-v6 address list. */ if (!ret) - cygwin_freeaddrinfo (*res); - return ret; + { + struct addrinfo *ptr; + for (ptr = *res; ptr->ai_next; ptr = ptr->ai_next) + ; + ptr->ai_next = v4res; + } + else + *res = v4res; + ret = 0; } - /* If a list of v6 addresses exists, append the v4-in-v6 address - list. Otherwise just return the v4-in-v6 address list. */ - if (!ret) - { - struct addrinfo *ptr; - for (ptr = *res; ptr->ai_next; ptr = ptr->ai_next) - ; - ptr->ai_next = v4res; - } - else - *res = v4res; - ret = 0; } } + __except (EFAULT) + { + ret = EAI_SYSTEM; + } + __endtry return ret; } @@ -3442,89 +3498,98 @@ cygwin_getnameinfo (const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) { - myfault efault; - if (efault.faulted (EFAULT)) - return EAI_SYSTEM; + int ret = 0; - /* When the incoming port number does not resolve to a well-known service, - WinSock's getnameinfo up to Windows 2003 returns with error WSANO_DATA - instead of setting `serv' to the numeric port number string, as required - by RFC 3493. This is fixed on Vista and later. To avoid the error on - systems up to Windows 2003, we check if the port number resolves - to a well-known service. If not, we set the NI_NUMERICSERV flag. */ - if (!wincap.supports_all_posix_ai_flags ()) + __try { - int port = 0; - - switch (sa->sa_family) + /* When the incoming port number does not resolve to a well-known service, + WinSock's getnameinfo up to Windows 2003 returns with error WSANO_DATA + instead of setting `serv' to the numeric port number string, as + required by RFC 3493. This is fixed on Vista and later. To avoid the + error on systems up to Windows 2003, we check if the port number + resolves to a well-known service. If not, we set the NI_NUMERICSERV + flag. */ + if (!wincap.supports_all_posix_ai_flags ()) { - case AF_INET: - port = ((struct sockaddr_in *) sa)->sin_port; - break; - case AF_INET6: - port = ((struct sockaddr_in6 *) sa)->sin6_port; - break; + int port = 0; + + switch (sa->sa_family) + { + case AF_INET: + port = ((struct sockaddr_in *) sa)->sin_port; + break; + case AF_INET6: + port = ((struct sockaddr_in6 *) sa)->sin6_port; + break; + default: + return EAI_FAMILY; + } + if (!port || !getservbyport (port, flags & NI_DGRAM ? "udp" : "tcp")) + flags |= NI_NUMERICSERV; } - if (!port || !getservbyport (port, flags & NI_DGRAM ? "udp" : "tcp")) - flags |= NI_NUMERICSERV; - } - /* We call GetNameInfoW with local buffers and convert to locale - charset to allow RFC 3490 IDNs like glibc 2.3.4 and later. */ + /* We call GetNameInfoW with local buffers and convert to locale + charset to allow RFC 3490 IDNs like glibc 2.3.4 and later. */ #define NI_IDN_MASK (NI_IDN | \ NI_IDN_ALLOW_UNASSIGNED | \ NI_IDN_USE_STD3_ASCII_RULES) - int idn_flags = flags & NI_IDN_MASK; - flags &= ~NI_IDN_MASK; - tmp_pathbuf tp; - wchar_t *whost = NULL, *wserv = NULL; - DWORD whlen = 0, wslen = 0; + int idn_flags = flags & NI_IDN_MASK; + flags &= ~NI_IDN_MASK; + tmp_pathbuf tp; + wchar_t *whost = NULL, *wserv = NULL; + DWORD whlen = 0, wslen = 0; - if (host && hostlen) - { - whost = tp.w_get (); - whlen = NT_MAX_PATH; - } - if (serv && servlen) - { - wserv = tp.w_get (); - wslen = NT_MAX_PATH; - } + if (host && hostlen) + { + whost = tp.w_get (); + whlen = NT_MAX_PATH; + } + if (serv && servlen) + { + wserv = tp.w_get (); + wslen = NT_MAX_PATH; + } - int ret = w32_to_gai_err (GetNameInfoW (sa, salen, whost, whlen, + ret = w32_to_gai_err (GetNameInfoW (sa, salen, whost, whlen, wserv, wslen, flags)); - if (!ret) - { - const wchar_t *src; + if (!ret) + { + const wchar_t *src; - if (whost) - { - if (idn_flags & NI_IDN) + if (whost) { - /* Map flags to equivalent IDN_* flags. */ - wchar_t *idnbuf = tp.w_get (); - if (IdnToUnicode (idn_flags >> 16, whost, -1, - idnbuf, NT_MAX_PATH)) - whost = idnbuf; - else if (GetLastError () != ERROR_PROC_NOT_FOUND) + if (idn_flags & NI_IDN) + { + /* Map flags to equivalent IDN_* flags. */ + wchar_t *idnbuf = tp.w_get (); + if (IdnToUnicode (idn_flags >> 16, whost, -1, + idnbuf, NT_MAX_PATH)) + whost = idnbuf; + else if (GetLastError () != ERROR_PROC_NOT_FOUND) + return EAI_IDN_ENCODE; + } + src = whost; + if (wcsrtombs (host, &src, hostlen, NULL) == (size_t) -1) return EAI_IDN_ENCODE; + if (src) + return EAI_OVERFLOW; + } + if (wserv) + { + src = wserv; + if (wcsrtombs (serv, &src, servlen, NULL) == (size_t) -1) + return EAI_IDN_ENCODE; + if (src) + return EAI_OVERFLOW; } - src = whost; - if (wcsrtombs (host, &src, hostlen, NULL) == (size_t) -1) - return EAI_IDN_ENCODE; - if (src) - return EAI_OVERFLOW; - } - if (wserv) - { - src = wserv; - if (wcsrtombs (serv, &src, servlen, NULL) == (size_t) -1) - return EAI_IDN_ENCODE; - if (src) - return EAI_OVERFLOW; } + else if (ret == EAI_SYSTEM) + set_winsock_errno (); } - else if (ret == EAI_SYSTEM) - set_winsock_errno (); + __except (EFAULT) + { + ret = EAI_SYSTEM; + } + __endtry return ret; } diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 89752cb46..f644b407b 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -1,7 +1,7 @@ /* ntdll.h. Contains ntdll specific stuff not defined elsewhere. Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, - 2011, 2012, 2013 Red Hat, Inc. + 2011, 2012, 2013, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -1180,8 +1180,19 @@ typedef enum _SECTION_INHERIT typedef VOID (APIENTRY *PTIMER_APC_ROUTINE)(PVOID, ULONG, ULONG); -/* Function declarations for ntdll.dll. These don't appear in any - standard Win32 header. */ +#ifdef __x86_64__ +typedef struct _SCOPE_TABLE +{ + ULONG Count; + struct + { + ULONG BeginAddress; + ULONG EndAddress; + ULONG HandlerAddress; + ULONG JumpTarget; + } ScopeRecord[1]; +} SCOPE_TABLE, *PSCOPE_TABLE; +#endif #ifdef __cplusplus /* This is the mapping of the KUSER_SHARED_DATA structure into the user @@ -1190,6 +1201,9 @@ typedef VOID (APIENTRY *PTIMER_APC_ROUTINE)(PVOID, ULONG, ULONG); static volatile KUSER_SHARED_DATA &SharedUserData = *(volatile KUSER_SHARED_DATA *) 0x7ffe0000; +/* Function declarations for ntdll.dll. These don't appear in any + standard Win32 header. */ + extern "C" { #endif diff --git a/winsup/cygwin/ntea.cc b/winsup/cygwin/ntea.cc index 2fb205a04..d0c50775e 100644 --- a/winsup/cygwin/ntea.cc +++ b/winsup/cygwin/ntea.cc @@ -60,167 +60,171 @@ read_ea (HANDLE hdl, path_conv &pc, const char *name, char *value, size_t size) EA in the file is returned twice. */ char lastname[MAX_EA_NAME_LEN]; - myfault efault; - if (efault.faulted (EFAULT)) - goto out; - - pc.get_object_attr (attr, sec_none_nih); - - debug_printf ("read_ea (%S, %s, %p, %lu)", - attr.ObjectName, name, value, size); - - /* Early open if handle is NULL. This allows to return error codes like - ENOENT before we actually check for the correctness of the EA name and - stuff like that. */ - if (!hdl) + __try { - status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io, - FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - goto out; - } - hdl = NULL; - } + pc.get_object_attr (attr, sec_none_nih); - fea = (PFILE_FULL_EA_INFORMATION) tp.w_get (); + debug_printf ("read_ea (%S, %s, %p, %lu)", + attr.ObjectName, name, value, size); - if (name) - { - size_t nlen; - - /* For compatibility with Linux, we only allow user xattrs and - return ENOTSUP otherwise. */ - if (ascii_strncasematch (name, "user.", 5)) - name += 5; - else + /* Early open if handle is NULL. This allows to return error codes like + ENOENT before we actually check for the correctness of the EA name and + stuff like that. */ + if (!hdl) { - set_errno (ENOTSUP); - goto out; - } - - if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN) - { - set_errno (EINVAL); - return -1; - } - glen = sizeof (FILE_GET_EA_INFORMATION) + nlen; - gea = (PFILE_GET_EA_INFORMATION) alloca (glen); - - gea->NextEntryOffset = 0; - gea->EaNameLength = nlen; - strcpy (gea->EaName, name); - } - - while (true) - { - if (h) - { - status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, gea, glen, - NULL, TRUE); - if (status != STATUS_ACCESS_DENIED || !hdl) - break; - } - status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io, - FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); - if (!NT_SUCCESS (status)) - break; - hdl = NULL; - } - if (!NT_SUCCESS (status)) - { - switch (status) - { - case STATUS_NO_EAS_ON_FILE: - ret = 0; - break; - case STATUS_INVALID_DEVICE_REQUEST: - set_errno (ENOTSUP); - break; - case STATUS_NOT_FOUND: - /* STATUS_NOT_FOUND is returned when calling NtQueryEaFile on NFS. - In theory this should mean that the file just has no EAs, but in - fact NFS doesn't support EAs, other than the EAs which are used - for NFS requests. We're playing safe and convert STATUS_NOT_FOUND - to ENOATTR, unless we're on NFS, where we convert it to ENOTSUP. */ - set_errno (pc.fs_is_nfs () ? ENOTSUP : ENOATTR); - break; - case STATUS_NONEXISTENT_EA_ENTRY: - /* Actually STATUS_NONEXISTENT_EA_ENTRY is either never generated, or - it was only generated in some old and long forgotton NT version. - See below. For safty reasons, we handle it here, nevertheless. */ - set_errno (ENOATTR); - break; - default: - __seterrno_from_nt_status (status); - break; - } - goto out; - } - if (name) - { - /* Another weird behaviour of NtQueryEaFile. If you ask for a - specific EA which is not present in the file's EA list, you don't - get a useful error code like STATUS_NONEXISTENT_EA_ENTRY. Rather - NtQueryEaFile returns success with the entry's EaValueLength - set to 0. */ - if (!fea->EaValueLength) - { - set_errno (ENOATTR); - goto out; - } - if (size > 0) - { - if (size < fea->EaValueLength) + status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT); + if (!NT_SUCCESS (status)) { - set_errno (ERANGE); - goto out; + __seterrno_from_nt_status (status); + __leave; } - memcpy (value, fea->EaName + fea->EaNameLength + 1, - fea->EaValueLength); + hdl = NULL; } - ret = fea->EaValueLength; - } - else - { - ret = 0; - do + + fea = (PFILE_FULL_EA_INFORMATION) tp.w_get (); + + if (name) { - fea->EaNameLength += 5; /* "user." */ + size_t nlen; + + /* For compatibility with Linux, we only allow user xattrs and + return ENOTSUP otherwise. */ + if (ascii_strncasematch (name, "user.", 5)) + name += 5; + else + { + set_errno (ENOTSUP); + __leave; + } + + if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN) + { + set_errno (EINVAL); + return -1; + } + glen = sizeof (FILE_GET_EA_INFORMATION) + nlen; + gea = (PFILE_GET_EA_INFORMATION) alloca (glen); + + gea->NextEntryOffset = 0; + gea->EaNameLength = nlen; + strcpy (gea->EaName, name); + } + + while (true) + { + if (h) + { + status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, gea, glen, + NULL, TRUE); + if (status != STATUS_ACCESS_DENIED || !hdl) + break; + } + status = NtOpenFile (&h, READ_CONTROL | FILE_READ_EA, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT); + if (!NT_SUCCESS (status)) + break; + hdl = NULL; + } + if (!NT_SUCCESS (status)) + { + switch (status) + { + case STATUS_NO_EAS_ON_FILE: + ret = 0; + break; + case STATUS_INVALID_DEVICE_REQUEST: + set_errno (ENOTSUP); + break; + case STATUS_NOT_FOUND: + /* STATUS_NOT_FOUND is returned when calling NtQueryEaFile on NFS. + In theory this should mean that the file just has no EAs, but + in fact NFS doesn't support EAs, other than the EAs which are + used for NFS requests. We're playing safe and convert + STATUS_NOT_FOUND to ENOATTR, unless we're on NFS, where we + convert it to ENOTSUP. */ + set_errno (pc.fs_is_nfs () ? ENOTSUP : ENOATTR); + break; + case STATUS_NONEXISTENT_EA_ENTRY: + /* Actually STATUS_NONEXISTENT_EA_ENTRY is either never generated, + or it was only generated in some old and long forgotton NT + version. See below. For safty reasons, we handle it here, + nevertheless. */ + set_errno (ENOATTR); + break; + default: + __seterrno_from_nt_status (status); + break; + } + __leave; + } + if (name) + { + /* Another weird behaviour of NtQueryEaFile. If you ask for a + specific EA which is not present in the file's EA list, you don't + get a useful error code like STATUS_NONEXISTENT_EA_ENTRY. Rather + NtQueryEaFile returns success with the entry's EaValueLength + set to 0. */ + if (!fea->EaValueLength) + { + set_errno (ENOATTR); + __leave; + } if (size > 0) { - if ((size_t) ret + fea->EaNameLength + 1 > size) + if (size < fea->EaValueLength) { set_errno (ERANGE); - goto out; + __leave; } - /* For compatibility with Linux, we always prepend "user." to - the attribute name, so effectively we only support user - attributes from a application point of view. */ - char tmpbuf[MAX_EA_NAME_LEN * 2]; - char *tp = stpcpy (tmpbuf, "user."); - stpcpy (tp, fea->EaName); - /* NTFS stores all EA names in uppercase unfortunately. To keep - compatibility with ext/xfs EA namespaces and accompanying - tools, which expect the namespaces to be lower case, we return - EA names in lowercase if the file is on a native NTFS. */ - if (pc.fs_is_ntfs ()) - strlwr (tp); - tp = stpcpy (value, tmpbuf) + 1; - ret += tp - value; - value = tp; + memcpy (value, fea->EaName + fea->EaNameLength + 1, + fea->EaValueLength); } - else - ret += fea->EaNameLength + 1; - strcpy (lastname, fea->EaName); - status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, NULL, 0, - NULL, FALSE); + ret = fea->EaValueLength; + } + else + { + ret = 0; + do + { + fea->EaNameLength += 5; /* "user." */ + if (size > 0) + { + if ((size_t) ret + fea->EaNameLength + 1 > size) + { + set_errno (ERANGE); + __leave; + } + /* For compatibility with Linux, we always prepend "user." to + the attribute name, so effectively we only support user + attributes from a application point of view. */ + char tmpbuf[MAX_EA_NAME_LEN * 2]; + char *tp = stpcpy (tmpbuf, "user."); + stpcpy (tp, fea->EaName); + /* NTFS stores all EA names in uppercase unfortunately. To + keep compatibility with ext/xfs EA namespaces and + accompanying tools, which expect the namespaces to be + lower case, we return EA names in lowercase if the file + is on a native NTFS. */ + if (pc.fs_is_ntfs ()) + strlwr (tp); + tp = stpcpy (value, tmpbuf) + 1; + ret += tp - value; + value = tp; + } + else + ret += fea->EaNameLength + 1; + strcpy (lastname, fea->EaName); + status = NtQueryEaFile (h, &io, fea, EA_BUFSIZ, TRUE, NULL, 0, + NULL, FALSE); + } + while (NT_SUCCESS (status) && strcmp (lastname, fea->EaName) != 0); } - while (NT_SUCCESS (status) && strcmp (lastname, fea->EaName) != 0); } - -out: + __except (EFAULT) {} + __endtry if (!hdl) CloseHandle (h); debug_printf ("%d = read_ea(%S, %s, %p, %lu)", @@ -241,120 +245,121 @@ write_ea (HANDLE hdl, path_conv &pc, const char *name, const char *value, ULONG flen; size_t nlen; - myfault efault; - if (efault.faulted (EFAULT)) - goto out; - - pc.get_object_attr (attr, sec_none_nih); - - debug_printf ("write_ea (%S, %s, %p, %lu, %d)", - attr.ObjectName, name, value, size, flags); - - /* Early open if handle is NULL. This allows to return error codes like - ENOENT before we actually check for the correctness of the EA name and - stuff like that. */ - if (!hdl) + __try { - status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io, - FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); - if (!NT_SUCCESS (status)) + pc.get_object_attr (attr, sec_none_nih); + + debug_printf ("write_ea (%S, %s, %p, %lu, %d)", + attr.ObjectName, name, value, size, flags); + + /* Early open if handle is NULL. This allows to return error codes like + ENOENT before we actually check for the correctness of the EA name and + stuff like that. */ + if (!hdl) { - __seterrno_from_nt_status (status); - goto out; + status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; + } + hdl = NULL; } - hdl = NULL; - } - /* For compatibility with Linux, we only allow user xattrs and - return ENOTSUP otherwise. */ - if (!ascii_strncasematch (name, "user.", 5)) - { - set_errno (ENOTSUP); - goto out; - } + /* For compatibility with Linux, we only allow user xattrs and + return ENOTSUP otherwise. */ + if (!ascii_strncasematch (name, "user.", 5)) + { + set_errno (ENOTSUP); + __leave; + } - /* removexattr is supposed to fail with ENOATTR if the requested EA is not - available. This is equivalent to the XATTR_REPLACE flag for setxattr. */ - if (!value) - flags = XATTR_REPLACE; + /* removexattr is supposed to fail with ENOATTR if the requested EA is + not available. This is equivalent to XATTR_REPLACE for setxattr. */ + if (!value) + flags = XATTR_REPLACE; - if (flags) - { - if (flags != XATTR_CREATE && flags != XATTR_REPLACE) + if (flags) + { + if (flags != XATTR_CREATE && flags != XATTR_REPLACE) + { + set_errno (EINVAL); + __leave; + } + ssize_t rret = read_ea (hdl, pc, name, NULL, 0); + if (flags == XATTR_CREATE && rret > 0) + { + set_errno (EEXIST); + __leave; + } + if (flags == XATTR_REPLACE && rret < 0) + __leave; + } + + /* Skip "user." prefix. */ + name += 5; + + if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN) { set_errno (EINVAL); - goto out; + __leave; } - ssize_t rret = read_ea (hdl, pc, name, NULL, 0); - if (flags == XATTR_CREATE && rret > 0) + flen = sizeof (FILE_FULL_EA_INFORMATION) + nlen + 1 + size; + fea = (PFILE_FULL_EA_INFORMATION) alloca (flen); + fea->NextEntryOffset = 0; + fea->Flags = 0; + fea->EaNameLength = nlen; + fea->EaValueLength = size; + strcpy (fea->EaName, name); + if (value) + memcpy (fea->EaName + fea->EaNameLength + 1, value, size); + + while (true) { - set_errno (EEXIST); - goto out; - } - if (flags == XATTR_REPLACE && rret < 0) - goto out; - } - - /* Skip "user." prefix. */ - name += 5; - - if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN) - { - set_errno (EINVAL); - goto out; - } - flen = sizeof (FILE_FULL_EA_INFORMATION) + nlen + 1 + size; - fea = (PFILE_FULL_EA_INFORMATION) alloca (flen); - fea->NextEntryOffset = 0; - fea->Flags = 0; - fea->EaNameLength = nlen; - fea->EaValueLength = size; - strcpy (fea->EaName, name); - if (value) - memcpy (fea->EaName + fea->EaNameLength + 1, value, size); - - while (true) - { - if (h) - { - status = NtSetEaFile (h, &io, fea, flen); - if (status != STATUS_ACCESS_DENIED || !hdl) + if (h) + { + status = NtSetEaFile (h, &io, fea, flen); + if (status != STATUS_ACCESS_DENIED || !hdl) + break; + } + status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT); + if (!NT_SUCCESS (status)) break; + hdl = NULL; } - status = NtOpenFile (&h, READ_CONTROL | FILE_WRITE_EA, &attr, &io, - FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); if (!NT_SUCCESS (status)) - break; - hdl = NULL; - } - if (!NT_SUCCESS (status)) - { - switch (status) { - case STATUS_EA_TOO_LARGE: - /* STATUS_EA_TOO_LARGE has a matching Win32 error ERROR_EA_TABLE_FULL. - For some unknown reason RtlNtStatusToDosError does not translate - STATUS_EA_TOO_LARGE to ERROR_EA_TABLE_FULL, but instead to - ERROR_EA_LIST_INCONSISTENT. This error code is also returned for - STATUS_EA_LIST_INCONSISTENT, which means the incoming EA list is... - inconsistent. For obvious reasons we translate - ERROR_EA_LIST_INCONSISTENT to EINVAL, so we have to handle - STATUS_EA_TOO_LARGE explicitely here, to get the correct mapping - to ENOSPC. */ - set_errno (ENOSPC); - break; - case STATUS_INVALID_DEVICE_REQUEST: - set_errno (ENOTSUP); - break; - default: - __seterrno_from_nt_status (status); - break; + switch (status) + { + case STATUS_EA_TOO_LARGE: + /* STATUS_EA_TOO_LARGE has a matching Win32 error code + ERROR_EA_TABLE_FULL. For some reason RtlNtStatusToDosError + does not translate STATUS_EA_TOO_LARGE to ERROR_EA_TABLE_FULL, + but instead to ERROR_EA_LIST_INCONSISTENT. This error code is + also returned for STATUS_EA_LIST_INCONSISTENT, which means the + incoming EA list is... inconsistent. For obvious reasons we + translate ERROR_EA_LIST_INCONSISTENT to EINVAL, so we have to + handle STATUS_EA_TOO_LARGE explicitely here, to get the correct + mapping to ENOSPC. */ + set_errno (ENOSPC); + break; + case STATUS_INVALID_DEVICE_REQUEST: + set_errno (ENOTSUP); + break; + default: + __seterrno_from_nt_status (status); + break; + } } + else + ret = 0; } - else - ret = 0; - -out: + __except (EFAULT) {} + __endtry if (!hdl) CloseHandle (h); debug_printf ("%d = write_ea(%S, %s, %p, %lu, %d)", diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 631b169a0..e5ce312ed 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -651,561 +651,574 @@ path_conv::check (const char *src, unsigned opt, } #endif - myfault efault; - if (efault.faulted ()) + __try { - error = EFAULT; - return; - } - int loop = 0; - path_flags = 0; - known_suffix = NULL; - fileattr = INVALID_FILE_ATTRIBUTES; - caseinsensitive = OBJ_CASE_INSENSITIVE; - if (wide_path) - cfree (wide_path); - wide_path = NULL; - if (path) - { - cfree (modifiable_path ()); - path = NULL; - } - close_conv_handle (); - memset (&dev, 0, sizeof (dev)); - fs.clear (); - if (normalized_path) - { - cfree ((void *) normalized_path); - normalized_path = NULL; - } - int component = 0; // Number of translated components - - if (!(opt & PC_NULLEMPTY)) - error = 0; - else if (!*src) - { - error = ENOENT; - return; - } - - bool is_msdos = false; - /* This loop handles symlink expansion. */ - for (;;) - { - MALLOC_CHECK; - assert (src); - - is_relpath = !isabspath (src); - error = normalize_posix_path (src, path_copy, tail); - if (error > 0) - return; - if (error < 0) + int loop = 0; + path_flags = 0; + known_suffix = NULL; + fileattr = INVALID_FILE_ATTRIBUTES; + caseinsensitive = OBJ_CASE_INSENSITIVE; + if (wide_path) + cfree (wide_path); + wide_path = NULL; + if (path) { - if (component == 0) - is_msdos = true; - error = 0; + cfree (modifiable_path ()); + path = NULL; + } + close_conv_handle (); + memset (&dev, 0, sizeof (dev)); + fs.clear (); + if (normalized_path) + { + cfree ((void *) normalized_path); + normalized_path = NULL; + } + int component = 0; // Number of translated components + + if (!(opt & PC_NULLEMPTY)) + error = 0; + else if (!*src) + { + error = ENOENT; + return; } - /* Detect if the user was looking for a directory. We have to strip the - trailing slash initially while trying to add extensions but take it - into account during processing */ - if (tail > path_copy + 2 && isslash (tail[-1])) + bool is_msdos = false; + /* This loop handles symlink expansion. */ + for (;;) { - need_directory = 1; - *--tail = '\0'; - } - path_end = tail; + MALLOC_CHECK; + assert (src); - /* Scan path_copy from right to left looking either for a symlink - or an actual existing file. If an existing file is found, just - return. If a symlink is found, exit the for loop. - Also: be careful to preserve the errno returned from - symlink.check as the caller may need it. */ - /* FIXME: Do we have to worry about multiple \'s here? */ - component = 0; // Number of translated components - sym.contents[0] = '\0'; - - int symlen = 0; - - for (unsigned pflags_or = opt & (PC_NO_ACCESS_CHECK | PC_KEEP_HANDLE); - ; - pflags_or = 0) - { - const suffix_info *suff; - char *full_path; - - /* Don't allow symlink.check to set anything in the path_conv - class if we're working on an inner component of the path */ - if (component) - { - suff = NULL; - full_path = pathbuf; - } - else - { - suff = suffixes; - full_path = THIS_path; - } - - /* Convert to native path spec sans symbolic link info. */ - error = mount_table->conv_to_win32_path (path_copy, full_path, dev, - &sym.pflags); - - if (error) + is_relpath = !isabspath (src); + error = normalize_posix_path (src, path_copy, tail); + if (error > 0) return; - - sym.pflags |= pflags_or; - - if (!dev.exists ()) + if (error < 0) { - error = ENXIO; - return; - } - - if (iscygdrive_dev (dev)) - { - if (!component) - fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY; - else - { - fileattr = getfileattr (THIS_path, - sym.pflags & MOUNT_NOPOSIX); - dev = FH_FS; - } - goto out; - } - else if (isdev_dev (dev)) - { - /* Just make sure that the path handling goes on as with FH_FS. */ - } - else if (isvirtual_dev (dev)) - { - /* FIXME: Calling build_fhandler here is not the right way to handle this. */ - fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy); - virtual_ftype_t file_type; - if (!fh) - file_type = virt_none; - else - { - file_type = fh->exists (); - if (file_type == virt_symlink) - { - fh->fill_filebuf (); - symlen = sym.set (fh->get_filebuf ()); - } - delete fh; - } - switch (file_type) - { - case virt_directory: - case virt_rootdir: - if (component == 0) - fileattr = FILE_ATTRIBUTE_DIRECTORY; - break; - case virt_file: - if (component == 0) - fileattr = 0; - break; - case virt_symlink: - goto is_virtual_symlink; - case virt_pipe: - if (component == 0) - { - fileattr = 0; - dev.parse (FH_PIPE); - } - break; - case virt_socket: - if (component == 0) - { - fileattr = 0; - dev.parse (FH_TCP); - } - break; - case virt_fsdir: - case virt_fsfile: - /* Access to real file or directory via block device - entry in /proc/sys. Convert to real file and go with - the flow. */ - dev.parse (FH_FS); - goto is_fs_via_procsys; - case virt_blk: - /* Block special device. If the trailing slash has been - requested, the target is the root directory of the - filesystem on this block device. So we convert this to - a real file and attach the backslash. */ - if (component == 0 && need_directory) - { - dev.parse (FH_FS); - strcat (full_path, "\\"); - fileattr = FILE_ATTRIBUTE_DIRECTORY - | FILE_ATTRIBUTE_DEVICE; - goto out; - } - /*FALLTHRU*/ - case virt_chr: - if (component == 0) - fileattr = FILE_ATTRIBUTE_DEVICE; - break; - default: - if (component == 0) - fileattr = INVALID_FILE_ATTRIBUTES; - goto virtual_component_retry; - } - if (component == 0 || dev != FH_NETDRIVE) - path_flags |= PATH_RO; - goto out; - } - /* devn should not be a device. If it is, then stop parsing now. */ - else if (dev != FH_FS) - { - fileattr = 0; - path_flags = sym.pflags; - if (component) - { - error = ENOTDIR; - return; - } - goto out; /* Found a device. Stop parsing. */ - } - - /* If path is only a drivename, Windows interprets it as the - current working directory on this drive instead of the root - dir which is what we want. So we need the trailing backslash - in this case. */ - if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0') - { - full_path[2] = '\\'; - full_path[3] = '\0'; - } - - /* If the incoming path was given in DOS notation, always treat - it as caseinsensitive,noacl path. This must be set before - calling sym.check, otherwise the path is potentially treated - casesensitive. */ - if (is_msdos) - sym.pflags |= PATH_NOPOSIX | PATH_NOACL; - -is_fs_via_procsys: - - symlen = sym.check (full_path, suff, fs, conv_handle); - -is_virtual_symlink: - - if (sym.isdevice) - { - if (component) - { - error = ENOTDIR; - return; - } - dev.parse (sym.major, sym.minor); - dev.setfs (1); - dev.mode = sym.mode; - fileattr = sym.fileattr; - goto out; - } - - if (sym.pflags & PATH_SOCKET) - { - if (component) - { - error = ENOTDIR; - return; - } - fileattr = sym.fileattr; - dev.parse (FH_UNIX); - dev.setfs (1); - goto out; - } - - if (!component) - { - /* Make sure that /dev always exists. */ - fileattr = isdev_dev (dev) ? FILE_ATTRIBUTE_DIRECTORY - : sym.fileattr; - path_flags = sym.pflags; - } - else if (isdev_dev (dev)) - { - /* If we're looking for a file below /dev, which doesn't exist, - make sure that the device type is converted to FH_FS, so that - subsequent code handles the file correctly. - Unless /dev itself doesn't exist on disk. In that case /dev - is handled as virtual filesystem, and virtual filesystems are - read-only. The PC_KEEP_HANDLE check allows to check for - a call from an informational system call. In that case we - just stick to ENOENT, and the device type doesn't matter - anyway. */ - if (sym.error == ENOENT && !(opt & PC_KEEP_HANDLE)) - sym.error = EROFS; - else - dev = FH_FS; - } - - /* If symlink.check found an existing non-symlink file, then - it sets the appropriate flag. It also sets any suffix found - into `ext_here'. */ - if (!sym.issymlink && sym.fileattr != INVALID_FILE_ATTRIBUTES) - { - error = sym.error; if (component == 0) - add_ext = true; - else if (!(sym.fileattr & FILE_ATTRIBUTE_DIRECTORY)) + is_msdos = true; + error = 0; + } + + /* Detect if the user was looking for a directory. We have to strip + the trailing slash initially while trying to add extensions but + take it into account during processing */ + if (tail > path_copy + 2 && isslash (tail[-1])) + { + need_directory = 1; + *--tail = '\0'; + } + path_end = tail; + + /* Scan path_copy from right to left looking either for a symlink + or an actual existing file. If an existing file is found, just + return. If a symlink is found, exit the for loop. + Also: be careful to preserve the errno returned from + symlink.check as the caller may need it. */ + /* FIXME: Do we have to worry about multiple \'s here? */ + component = 0; // Number of translated components + sym.contents[0] = '\0'; + + int symlen = 0; + + for (unsigned pflags_or = opt & (PC_NO_ACCESS_CHECK | PC_KEEP_HANDLE); + ; + pflags_or = 0) + { + const suffix_info *suff; + char *full_path; + + /* Don't allow symlink.check to set anything in the path_conv + class if we're working on an inner component of the path */ + if (component) { - error = ENOTDIR; + suff = NULL; + full_path = pathbuf; + } + else + { + suff = suffixes; + full_path = THIS_path; + } + + /* Convert to native path spec sans symbolic link info. */ + error = mount_table->conv_to_win32_path (path_copy, full_path, + dev, &sym.pflags); + + if (error) + return; + + sym.pflags |= pflags_or; + + if (!dev.exists ()) + { + error = ENXIO; + return; + } + + if (iscygdrive_dev (dev)) + { + if (!component) + fileattr = FILE_ATTRIBUTE_DIRECTORY + | FILE_ATTRIBUTE_READONLY; + else + { + fileattr = getfileattr (THIS_path, + sym.pflags & MOUNT_NOPOSIX); + dev = FH_FS; + } goto out; } - goto out; // file found - } - /* Found a symlink if symlen > 0. If component == 0, then the - src path itself was a symlink. If !follow_mode then - we're done. Otherwise we have to insert the path found - into the full path that we are building and perform all of - these operations again on the newly derived path. */ - else if (symlen > 0) - { - saw_symlinks = 1; - if (component == 0 && !need_directory - && (!(opt & PC_SYM_FOLLOW) - || (is_rep_symlink () && (opt & PC_SYM_NOFOLLOW_REP)))) + else if (isdev_dev (dev)) { - set_symlink (symlen); // last component of path is a symlink. - if (opt & PC_SYM_CONTENTS) + /* Make sure that the path handling goes on as with FH_FS. */ + } + else if (isvirtual_dev (dev)) + { + /* FIXME: Calling build_fhandler here is not the right way to + handle this. */ + fhandler_virtual *fh = (fhandler_virtual *) + build_fh_dev (dev, path_copy); + virtual_ftype_t file_type; + if (!fh) + file_type = virt_none; + else { - strcpy (THIS_path, sym.contents); + file_type = fh->exists (); + if (file_type == virt_symlink) + { + fh->fill_filebuf (); + symlen = sym.set (fh->get_filebuf ()); + } + delete fh; + } + switch (file_type) + { + case virt_directory: + case virt_rootdir: + if (component == 0) + fileattr = FILE_ATTRIBUTE_DIRECTORY; + break; + case virt_file: + if (component == 0) + fileattr = 0; + break; + case virt_symlink: + goto is_virtual_symlink; + case virt_pipe: + if (component == 0) + { + fileattr = 0; + dev.parse (FH_PIPE); + } + break; + case virt_socket: + if (component == 0) + { + fileattr = 0; + dev.parse (FH_TCP); + } + break; + case virt_fsdir: + case virt_fsfile: + /* Access to real file or directory via block device + entry in /proc/sys. Convert to real file and go with + the flow. */ + dev.parse (FH_FS); + goto is_fs_via_procsys; + case virt_blk: + /* Block special device. If the trailing slash has been + requested, the target is the root directory of the + filesystem on this block device. So we convert this + to a real file and attach the backslash. */ + if (component == 0 && need_directory) + { + dev.parse (FH_FS); + strcat (full_path, "\\"); + fileattr = FILE_ATTRIBUTE_DIRECTORY + | FILE_ATTRIBUTE_DEVICE; + goto out; + } + /*FALLTHRU*/ + case virt_chr: + if (component == 0) + fileattr = FILE_ATTRIBUTE_DEVICE; + break; + default: + if (component == 0) + fileattr = INVALID_FILE_ATTRIBUTES; + goto virtual_component_retry; + } + if (component == 0 || dev != FH_NETDRIVE) + path_flags |= PATH_RO; + goto out; + } + /* devn should not be a device. If it is, then stop parsing. */ + else if (dev != FH_FS) + { + fileattr = 0; + path_flags = sym.pflags; + if (component) + { + error = ENOTDIR; + return; + } + goto out; /* Found a device. Stop parsing. */ + } + + /* If path is only a drivename, Windows interprets it as the + current working directory on this drive instead of the root + dir which is what we want. So we need the trailing backslash + in this case. */ + if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0') + { + full_path[2] = '\\'; + full_path[3] = '\0'; + } + + /* If the incoming path was given in DOS notation, always treat + it as caseinsensitive,noacl path. This must be set before + calling sym.check, otherwise the path is potentially treated + casesensitive. */ + if (is_msdos) + sym.pflags |= PATH_NOPOSIX | PATH_NOACL; + + is_fs_via_procsys: + + symlen = sym.check (full_path, suff, fs, conv_handle); + + is_virtual_symlink: + + if (sym.isdevice) + { + if (component) + { + error = ENOTDIR; + return; + } + dev.parse (sym.major, sym.minor); + dev.setfs (1); + dev.mode = sym.mode; + fileattr = sym.fileattr; + goto out; + } + + if (sym.pflags & PATH_SOCKET) + { + if (component) + { + error = ENOTDIR; + return; + } + fileattr = sym.fileattr; + dev.parse (FH_UNIX); + dev.setfs (1); + goto out; + } + + if (!component) + { + /* Make sure that /dev always exists. */ + fileattr = isdev_dev (dev) ? FILE_ATTRIBUTE_DIRECTORY + : sym.fileattr; + path_flags = sym.pflags; + } + else if (isdev_dev (dev)) + { + /* If we're looking for a non-existing file below /dev, + make sure that the device type is converted to FH_FS, so + that subsequent code handles the file correctly. Unless + /dev itself doesn't exist on disk. In that case /dev + is handled as virtual filesystem, and virtual filesystems + are read-only. The PC_KEEP_HANDLE check allows to check + for a call from an informational system call. In that + case we just stick to ENOENT, and the device type doesn't + matter anyway. */ + if (sym.error == ENOENT && !(opt & PC_KEEP_HANDLE)) + sym.error = EROFS; + else + dev = FH_FS; + } + + /* If symlink.check found an existing non-symlink file, then + it sets the appropriate flag. It also sets any suffix found + into `ext_here'. */ + if (!sym.issymlink && sym.fileattr != INVALID_FILE_ATTRIBUTES) + { + error = sym.error; + if (component == 0) + add_ext = true; + else if (!(sym.fileattr & FILE_ATTRIBUTE_DIRECTORY)) + { + error = ENOTDIR; goto out; } - add_ext = true; + goto out; // file found + } + /* Found a symlink if symlen > 0. If component == 0, then the + src path itself was a symlink. If !follow_mode then + we're done. Otherwise we have to insert the path found + into the full path that we are building and perform all of + these operations again on the newly derived path. */ + else if (symlen > 0) + { + saw_symlinks = 1; + if (component == 0 && !need_directory + && (!(opt & PC_SYM_FOLLOW) + || (is_rep_symlink () + && (opt & PC_SYM_NOFOLLOW_REP)))) + { + /* last component of path is a symlink. */ + set_symlink (symlen); + if (opt & PC_SYM_CONTENTS) + { + strcpy (THIS_path, sym.contents); + goto out; + } + add_ext = true; + goto out; + } + /* Following a symlink we can't trust the collected + filesystem information any longer. */ + fs.clear (); + /* Close handle, if we have any. Otherwise we're collecting + handles while following symlinks. */ + conv_handle.close (); + break; + } + else if (sym.error && sym.error != ENOENT) + { + error = sym.error; goto out; } - /* Following a symlink we can't trust the collected filesystem - information any longer. */ - fs.clear (); - /* Close handle, if we have any. Otherwise we're collecting - handles while following symlinks. */ - conv_handle.close (); - break; + /* No existing file found. */ + + virtual_component_retry: + /* Find the new "tail" of the path, e.g. in '/for/bar/baz', + /baz is the tail. */ + if (tail != path_end) + *tail = '/'; + while (--tail > path_copy + 1 && *tail != '/') {} + /* Exit loop if there is no tail or we are at the + beginning of a UNC path */ + if (tail <= path_copy + 1) + goto out; // all done + + /* Haven't found an existing pathname component yet. + Pinch off the tail and try again. */ + *tail = '\0'; + component++; } - else if (sym.error && sym.error != ENOENT) + + /* Arrive here if above loop detected a symlink. */ + if (++loop > SYMLOOP_MAX) { - error = sym.error; - goto out; - } - /* No existing file found. */ - -virtual_component_retry: - /* Find the new "tail" of the path, e.g. in '/for/bar/baz', - /baz is the tail. */ - if (tail != path_end) - *tail = '/'; - while (--tail > path_copy + 1 && *tail != '/') {} - /* Exit loop if there is no tail or we are at the - beginning of a UNC path */ - if (tail <= path_copy + 1) - goto out; // all done - - /* Haven't found an existing pathname component yet. - Pinch off the tail and try again. */ - *tail = '\0'; - component++; - } - - /* Arrive here if above loop detected a symlink. */ - if (++loop > SYMLOOP_MAX) - { - error = ELOOP; // Eep. - return; - } - - MALLOC_CHECK; - - - /* Place the link content, possibly with head and/or tail, in tmp_buf */ - - char *headptr; - if (isabspath (sym.contents)) - headptr = tmp_buf; /* absolute path */ - else - { - /* Copy the first part of the path (with ending /) and point to the end. */ - char *prevtail = tail; - while (--prevtail > path_copy && *prevtail != '/') {} - int headlen = prevtail - path_copy + 1;; - memcpy (tmp_buf, path_copy, headlen); - headptr = &tmp_buf[headlen]; - } - - /* Make sure there is enough space */ - if (headptr + symlen >= tmp_buf + (2 * NT_MAX_PATH)) - { - too_long: - error = ENAMETOOLONG; - set_path ("::ENAMETOOLONG::"); - return; - } - - /* Copy the symlink contents to the end of tmp_buf. - Convert slashes. */ - for (char *p = sym.contents; *p; p++) - *headptr++ = *p == '\\' ? '/' : *p; - *headptr = '\0'; - - /* Copy any tail component (with the 0) */ - if (tail++ < path_end) - { - /* Add a slash if needed. There is space. */ - if (*(headptr - 1) != '/') - *headptr++ = '/'; - int taillen = path_end - tail + 1; - if (headptr + taillen > tmp_buf + (2 * NT_MAX_PATH)) - goto too_long; - memcpy (headptr, tail, taillen); - } - - /* Evaluate everything all over again. */ - src = tmp_buf; - } - - if (!(opt & PC_SYM_CONTENTS)) - add_ext = true; - -out: - set_path (THIS_path); - if (add_ext) - add_ext_from_sym (sym); - if (dev == FH_NETDRIVE && component) - { - /* This case indicates a non-existant resp. a non-retrievable - share. This happens for instance if the share is a printer. - In this case the path must not be treated like a FH_NETDRIVE, - but like a FH_FS instead, so the usual open call for files - is used on it. */ - dev.parse (FH_FS); - } - else if (isproc_dev (dev) && fileattr == INVALID_FILE_ATTRIBUTES) - { - /* FIXME: Usually we don't set error to ENOENT if a file doesn't - exist. This is typically indicated by the fileattr content. - So, why here? The downside is that cygwin_conv_path just gets - an error for these paths so it reports the error back to the - application. Unlike in all other cases of non-existant files, - for which check doesn't set error, so cygwin_conv_path just - returns the path, as intended. */ - error = ENOENT; - return; - } - else if (!need_directory || error) - /* nothing to do */; - else if (fileattr == INVALID_FILE_ATTRIBUTES) - strcat (modifiable_path (), "\\"); /* Reattach trailing dirsep in native path. */ - else if (fileattr & FILE_ATTRIBUTE_DIRECTORY) - path_flags &= ~PATH_SYMLINK; - else - { - debug_printf ("%s is a non-directory", path); - error = ENOTDIR; - return; - } - - if (dev.isfs ()) - { - if (strncmp (path, "\\\\.\\", 4)) - { - if (!tail || tail == path) - /* nothing */; - else if (tail[-1] != '\\') - *tail = '\0'; - else - { - error = ENOENT; + error = ELOOP; // Eep. return; } - } - /* If FS hasn't been checked already in symlink_info::check, do so now. */ - if (fs.inited ()|| fs.update (get_nt_native_path (), NULL)) - { - /* Incoming DOS paths are treated like DOS paths in native - Windows applications. No ACLs, just default settings. */ - if (is_msdos) - fs.has_acls (false); - debug_printf ("this->path(%s), has_acls(%d)", path, fs.has_acls ()); - /* CV: We could use this->has_acls() but I want to make sure that - we don't forget that the PATH_NOACL flag must be taken into - account here. */ - if (!(path_flags & PATH_NOACL) && fs.has_acls ()) - set_exec (0); /* We really don't know if this is executable or not here - but set it to not executable since it will be figured out - later by anything which cares about this. */ - } - /* If the FS has been found to have unrelibale inodes, note - that in path_flags. */ - if (!fs.hasgood_inode ()) - path_flags |= PATH_IHASH; - /* If the OS is caseinsensitive or the FS is caseinsensitive, - don't handle path casesensitive. */ - if (cygwin_shared->obcaseinsensitive || fs.caseinsensitive ()) - path_flags |= PATH_NOPOSIX; - caseinsensitive = (path_flags & PATH_NOPOSIX) - ? OBJ_CASE_INSENSITIVE : 0; - if (exec_state () != dont_know_if_executable) - /* ok */; - else if (isdir ()) - set_exec (1); - else if (issymlink () || issocket ()) - set_exec (0); - } + MALLOC_CHECK; - if (opt & PC_NOFULL) - { - if (is_relpath) - { - mkrelpath (this->modifiable_path (), !!caseinsensitive); - /* Invalidate wide_path so that wide relpath can be created - in later calls to get_nt_native_path or get_wide_win32_path. */ - if (wide_path) - cfree (wide_path); - wide_path = NULL; - } - if (need_directory) - { - size_t n = strlen (this->path); - /* Do not add trailing \ to UNC device names like \\.\a: */ - if (this->path[n - 1] != '\\' && - (strncmp (this->path, "\\\\.\\", 4) != 0)) + + /* Place the link content, possibly with head and/or tail, + in tmp_buf */ + + char *headptr; + if (isabspath (sym.contents)) + headptr = tmp_buf; /* absolute path */ + else { - this->modifiable_path ()[n] = '\\'; - this->modifiable_path ()[n + 1] = '\0'; + /* Copy the first part of the path (with ending /) and point to + the end. */ + char *prevtail = tail; + while (--prevtail > path_copy && *prevtail != '/') {} + int headlen = prevtail - path_copy + 1;; + memcpy (tmp_buf, path_copy, headlen); + headptr = &tmp_buf[headlen]; + } + + /* Make sure there is enough space */ + if (headptr + symlen >= tmp_buf + (2 * NT_MAX_PATH)) + { + too_long: + error = ENAMETOOLONG; + set_path ("::ENAMETOOLONG::"); + return; + } + + /* Copy the symlink contents to the end of tmp_buf. + Convert slashes. */ + for (char *p = sym.contents; *p; p++) + *headptr++ = *p == '\\' ? '/' : *p; + *headptr = '\0'; + + /* Copy any tail component (with the 0) */ + if (tail++ < path_end) + { + /* Add a slash if needed. There is space. */ + if (*(headptr - 1) != '/') + *headptr++ = '/'; + int taillen = path_end - tail + 1; + if (headptr + taillen > tmp_buf + (2 * NT_MAX_PATH)) + goto too_long; + memcpy (headptr, tail, taillen); + } + + /* Evaluate everything all over again. */ + src = tmp_buf; + } + + if (!(opt & PC_SYM_CONTENTS)) + add_ext = true; + + out: + set_path (THIS_path); + if (add_ext) + add_ext_from_sym (sym); + if (dev == FH_NETDRIVE && component) + { + /* This case indicates a non-existant resp. a non-retrievable + share. This happens for instance if the share is a printer. + In this case the path must not be treated like a FH_NETDRIVE, + but like a FH_FS instead, so the usual open call for files + is used on it. */ + dev.parse (FH_FS); + } + else if (isproc_dev (dev) && fileattr == INVALID_FILE_ATTRIBUTES) + { + /* FIXME: Usually we don't set error to ENOENT if a file doesn't + exist. This is typically indicated by the fileattr content. + So, why here? The downside is that cygwin_conv_path just gets + an error for these paths so it reports the error back to the + application. Unlike in all other cases of non-existant files, + for which check doesn't set error, so cygwin_conv_path just + returns the path, as intended. */ + error = ENOENT; + return; + } + else if (!need_directory || error) + /* nothing to do */; + else if (fileattr == INVALID_FILE_ATTRIBUTES) + /* Reattach trailing dirsep in native path. */ + strcat (modifiable_path (), "\\"); + else if (fileattr & FILE_ATTRIBUTE_DIRECTORY) + path_flags &= ~PATH_SYMLINK; + else + { + debug_printf ("%s is a non-directory", path); + error = ENOTDIR; + return; + } + + if (dev.isfs ()) + { + if (strncmp (path, "\\\\.\\", 4)) + { + if (!tail || tail == path) + /* nothing */; + else if (tail[-1] != '\\') + *tail = '\0'; + else + { + error = ENOENT; + return; + } + } + + /* If FS hasn't been checked already in symlink_info::check, + do so now. */ + if (fs.inited ()|| fs.update (get_nt_native_path (), NULL)) + { + /* Incoming DOS paths are treated like DOS paths in native + Windows applications. No ACLs, just default settings. */ + if (is_msdos) + fs.has_acls (false); + debug_printf ("this->path(%s), has_acls(%d)", + path, fs.has_acls ()); + /* CV: We could use this->has_acls() but I want to make sure that + we don't forget that the PATH_NOACL flag must be taken into + account here. */ + if (!(path_flags & PATH_NOACL) && fs.has_acls ()) + set_exec (0); /* We really don't know if this is executable or + not here but set it to not executable since + it will be figured out later by anything + which cares about this. */ + } + /* If the FS has been found to have unrelibale inodes, note + that in path_flags. */ + if (!fs.hasgood_inode ()) + path_flags |= PATH_IHASH; + /* If the OS is caseinsensitive or the FS is caseinsensitive, + don't handle path casesensitive. */ + if (cygwin_shared->obcaseinsensitive || fs.caseinsensitive ()) + path_flags |= PATH_NOPOSIX; + caseinsensitive = (path_flags & PATH_NOPOSIX) + ? OBJ_CASE_INSENSITIVE : 0; + if (exec_state () != dont_know_if_executable) + /* ok */; + else if (isdir ()) + set_exec (1); + else if (issymlink () || issocket ()) + set_exec (0); + } + + if (opt & PC_NOFULL) + { + if (is_relpath) + { + mkrelpath (this->modifiable_path (), !!caseinsensitive); + /* Invalidate wide_path so that wide relpath can be created + in later calls to get_nt_native_path or get_wide_win32_path. */ + if (wide_path) + cfree (wide_path); + wide_path = NULL; + } + if (need_directory) + { + size_t n = strlen (this->path); + /* Do not add trailing \ to UNC device names like \\.\a: */ + if (this->path[n - 1] != '\\' && + (strncmp (this->path, "\\\\.\\", 4) != 0)) + { + this->modifiable_path ()[n] = '\\'; + this->modifiable_path ()[n + 1] = '\0'; + } } } - } - if (saw_symlinks) - set_has_symlinks (); + if (saw_symlinks) + set_has_symlinks (); - if (opt & PC_OPEN) - path_flags |= PATH_OPEN; + if (opt & PC_OPEN) + path_flags |= PATH_OPEN; - if (opt & PC_CTTY) - path_flags |= PATH_CTTY; + if (opt & PC_CTTY) + path_flags |= PATH_CTTY; - if (opt & PC_POSIX) - { - if (tail < path_end && tail > path_copy + 1) - *tail = '/'; - set_normalized_path (path_copy); - if (is_msdos && !(opt & PC_NOWARN)) - warn_msdos (src); - } + if (opt & PC_POSIX) + { + if (tail < path_end && tail > path_copy + 1) + *tail = '/'; + set_normalized_path (path_copy); + if (is_msdos && !(opt & PC_NOWARN)) + warn_msdos (src); + } #if 0 - if (!error) - { - last_path_conv = *this; - strcpy (last_src, src); - } + if (!error) + { + last_path_conv = *this; + strcpy (last_src, src); + } #endif + } + __except (NO_ERROR) + { + error = EFAULT; + } + __endtry } path_conv::~path_conv () @@ -1688,332 +1701,342 @@ symlink_worker (const char *oldpath, const char *newpath, bool isdevice) /* POSIX says that empty 'newpath' is invalid input while empty 'oldpath' is valid -- it's symlink resolver job to verify if symlink contents point to existing filesystem object */ - myfault efault; - if (efault.faulted (EFAULT)) - goto done; - if (!*oldpath || !*newpath) + __try { - set_errno (ENOENT); - goto done; - } - - if (strlen (oldpath) > SYMLINK_MAX) - { - set_errno (ENAMETOOLONG); - goto done; - } - - /* Trailing dirsep is a no-no. */ - len = strlen (newpath); - has_trailing_dirsep = isdirsep (newpath[len - 1]); - if (has_trailing_dirsep) - { - newpath = strdup (newpath); - ((char *) newpath)[len - 1] = '\0'; - } - - check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0); - /* We need the normalized full path below. */ - win32_newpath.check (newpath, check_opt, stat_suffixes); - - /* Default symlink type is determined by global allow_winsymlinks variable. - Device files are always shortcuts. */ - wsym_type = isdevice ? WSYM_lnk : allow_winsymlinks; - /* NFS has its own, dedicated way to create symlinks. */ - if (win32_newpath.fs_is_nfs ()) - wsym_type = WSYM_nfs; - /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O - attribute. Therefore we create symlinks on MVFS always as shortcuts. */ - else if (win32_newpath.fs_is_mvfs ()) - wsym_type = WSYM_lnk; - /* AFS only supports native symlinks. */ - else if (win32_newpath.fs_is_afs ()) - { - /* Bail out if OS doesn't support native symlinks. */ - if (wincap.max_sys_priv () < SE_CREATE_SYMBOLIC_LINK_PRIVILEGE) + if (!*oldpath || !*newpath) { - set_errno (EPERM); - goto done; + set_errno (ENOENT); + __leave; } - wsym_type = WSYM_nativestrict; - } - /* Don't try native symlinks on filesystems not supporting reparse points. */ - else if ((wsym_type == WSYM_native || wsym_type == WSYM_nativestrict) - && !(win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS)) - wsym_type = WSYM_sysfile; - /* Attach .lnk suffix when shortcut is requested. */ - if (wsym_type == WSYM_lnk && !win32_newpath.exists () - && (isdevice || !win32_newpath.fs_is_nfs ())) - { - char *newplnk = tp.c_get (); - stpcpy (stpcpy (newplnk, newpath), ".lnk"); - win32_newpath.check (newplnk, check_opt); - } - - if (win32_newpath.error) - { - set_errno (win32_newpath.error); - goto done; - } - - syscall_printf ("symlink (%s, %S) wsym_type %d", oldpath, - win32_newpath.get_nt_native_path (), wsym_type); - - if ((!isdevice && win32_newpath.exists ()) - || win32_newpath.is_auto_device ()) - { - set_errno (EEXIST); - goto done; - } - if (has_trailing_dirsep && !win32_newpath.exists ()) - { - set_errno (ENOENT); - goto done; - } - - /* Handle NFS and native symlinks in their own functions. */ - switch (wsym_type) - { - case WSYM_nfs: - res = symlink_nfs (oldpath, win32_newpath); - goto done; - case WSYM_native: - case WSYM_nativestrict: - res = symlink_native (oldpath, win32_newpath); - if (!res) - goto done; - /* Strictly native? Too bad. */ - if (wsym_type == WSYM_nativestrict) + if (strlen (oldpath) > SYMLINK_MAX) { - __seterrno (); - goto done; + set_errno (ENAMETOOLONG); + __leave; } - /* Otherwise, fall back to default symlink type. */ - wsym_type = WSYM_sysfile; - break; - default: - break; - } - if (wsym_type == WSYM_lnk) - { - path_conv win32_oldpath; - ITEMIDLIST *pidl = NULL; - size_t full_len = 0; - unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0; - char desc[MAX_PATH + 1], *relpath; - - if (!isdevice) + /* Trailing dirsep is a no-no. */ + len = strlen (newpath); + has_trailing_dirsep = isdirsep (newpath[len - 1]); + if (has_trailing_dirsep) { - /* First create an IDLIST to learn how big our shortcut is - going to be. */ - IShellFolder *psl; + newpath = strdup (newpath); + ((char *) newpath)[len - 1] = '\0'; + } - /* The symlink target is relative to the directory in which - the symlink gets created, not relative to the cwd. Therefore - we have to mangle the path quite a bit before calling path_conv. */ - if (isabspath (oldpath)) - win32_oldpath.check (oldpath, - PC_SYM_NOFOLLOW, - stat_suffixes); + check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0); + /* We need the normalized full path below. */ + win32_newpath.check (newpath, check_opt, stat_suffixes); + + /* Default symlink type is determined by global allow_winsymlinks + variable. Device files are always shortcuts. */ + wsym_type = isdevice ? WSYM_lnk : allow_winsymlinks; + /* NFS has its own, dedicated way to create symlinks. */ + if (win32_newpath.fs_is_nfs ()) + wsym_type = WSYM_nfs; + /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O + attribute. Therefore we create symlinks on MVFS always as shortcuts. */ + else if (win32_newpath.fs_is_mvfs ()) + wsym_type = WSYM_lnk; + /* AFS only supports native symlinks. */ + else if (win32_newpath.fs_is_afs ()) + { + /* Bail out if OS doesn't support native symlinks. */ + if (wincap.max_sys_priv () < SE_CREATE_SYMBOLIC_LINK_PRIVILEGE) + { + set_errno (EPERM); + __leave; + } + wsym_type = WSYM_nativestrict; + } + /* Don't try native symlinks on FSes not supporting reparse points. */ + else if ((wsym_type == WSYM_native || wsym_type == WSYM_nativestrict) + && !(win32_newpath.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS)) + wsym_type = WSYM_sysfile; + + /* Attach .lnk suffix when shortcut is requested. */ + if (wsym_type == WSYM_lnk && !win32_newpath.exists () + && (isdevice || !win32_newpath.fs_is_nfs ())) + { + char *newplnk = tp.c_get (); + stpcpy (stpcpy (newplnk, newpath), ".lnk"); + win32_newpath.check (newplnk, check_opt); + } + + if (win32_newpath.error) + { + set_errno (win32_newpath.error); + __leave; + } + + syscall_printf ("symlink (%s, %S) wsym_type %d", oldpath, + win32_newpath.get_nt_native_path (), wsym_type); + + if ((!isdevice && win32_newpath.exists ()) + || win32_newpath.is_auto_device ()) + { + set_errno (EEXIST); + __leave; + } + if (has_trailing_dirsep && !win32_newpath.exists ()) + { + set_errno (ENOENT); + __leave; + } + + /* Handle NFS and native symlinks in their own functions. */ + switch (wsym_type) + { + case WSYM_nfs: + res = symlink_nfs (oldpath, win32_newpath); + __leave; + case WSYM_native: + case WSYM_nativestrict: + res = symlink_native (oldpath, win32_newpath); + if (!res) + __leave; + /* Strictly native? Too bad. */ + if (wsym_type == WSYM_nativestrict) + { + __seterrno (); + __leave; + } + /* Otherwise, fall back to default symlink type. */ + wsym_type = WSYM_sysfile; + break; + default: + break; + } + + if (wsym_type == WSYM_lnk) + { + path_conv win32_oldpath; + ITEMIDLIST *pidl = NULL; + size_t full_len = 0; + unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0; + char desc[MAX_PATH + 1], *relpath; + + if (!isdevice) + { + /* First create an IDLIST to learn how big our shortcut is + going to be. */ + IShellFolder *psl; + + /* The symlink target is relative to the directory in which the + symlink gets created, not relative to the cwd. Therefore we + have to mangle the path quite a bit before calling path_conv.*/ + if (isabspath (oldpath)) + win32_oldpath.check (oldpath, + PC_SYM_NOFOLLOW, + stat_suffixes); + else + { + len = strrchr (win32_newpath.normalized_path, '/') + - win32_newpath.normalized_path + 1; + char *absoldpath = tp.t_get (); + stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, + len), + oldpath); + win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, + stat_suffixes); + } + if (SUCCEEDED (SHGetDesktopFolder (&psl))) + { + WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1]; + win32_oldpath.get_wide_win32_path (wc_path); + /* Amazing but true: Even though the ParseDisplayName method + takes a wide char path name, it does not understand the + Win32 prefix for long pathnames! So we have to tack off + the prefix and convert the path to the "normal" syntax + for ParseDisplayName. */ + WCHAR *wc = wc_path + 4; + if (wc[1] != L':') /* native UNC path */ + *(wc += 2) = L'\\'; + HRESULT res; + if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, + NULL, &pidl, + NULL))) + { + ITEMIDLIST *p; + + for (p = pidl; p->mkid.cb > 0; + p = (ITEMIDLIST *)((char *) p + p->mkid.cb)) + ; + pidl_len = (char *) p - (char *) pidl + 2; + } + psl->Release (); + } + } + /* Compute size of shortcut file. */ + full_len = sizeof (win_shortcut_hdr); + if (pidl_len) + full_len += sizeof (unsigned short) + pidl_len; + oldpath_len = strlen (oldpath); + /* Unfortunately the length of the description is restricted to a + length of 2000 bytes. We don't want to add considerations for + the different lengths and even 2000 bytes is not enough for long + path names. So what we do here is to set the description to the + POSIX path only if the path is not longer than MAX_PATH characters. + We append the full path name after the regular shortcut data + (see below), which works fine with Windows Explorer as well + as older Cygwin versions (as long as the whole file isn't bigger + than 8K). The description field is only used for backward + compatibility to older Cygwin versions and those versions are + not capable of handling long path names anyway. */ + desc_len = stpcpy (desc, oldpath_len > MAX_PATH + ? "[path too long]" : oldpath) - desc; + full_len += sizeof (unsigned short) + desc_len; + /* Devices get the oldpath string unchanged as relative path. */ + if (isdevice) + { + relpath_len = oldpath_len; + stpcpy (relpath = tp.c_get (), oldpath); + } else { - len = strrchr (win32_newpath.normalized_path, '/') - - win32_newpath.normalized_path + 1; - char *absoldpath = tp.t_get (); - stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len), - oldpath); - win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes); + relpath_len = strlen (win32_oldpath.get_win32 ()); + stpcpy (relpath = tp.c_get (), win32_oldpath.get_win32 ()); } - if (SUCCEEDED (SHGetDesktopFolder (&psl))) + full_len += sizeof (unsigned short) + relpath_len; + full_len += sizeof (unsigned short) + oldpath_len; + /* 1 byte more for trailing 0 written by stpcpy. */ + if (full_len < NT_MAX_PATH * sizeof (WCHAR)) + buf = tp.t_get (); + else + buf = (char *) alloca (full_len + 1); + + /* Create shortcut header */ + win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf; + memset (shortcut_header, 0, sizeof *shortcut_header); + shortcut_header->size = sizeof *shortcut_header; + shortcut_header->magic = GUID_shortcut; + shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH); + if (pidl) + shortcut_header->flags |= WSH_FLAG_IDLIST; + shortcut_header->run = SW_NORMAL; + cp = buf + sizeof (win_shortcut_hdr); + + /* Create IDLIST */ + if (pidl) { - WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1]; - win32_oldpath.get_wide_win32_path (wc_path); - /* Amazing but true: Even though the ParseDisplayName method - takes a wide char path name, it does not understand the - Win32 prefix for long pathnames! So we have to tack off - the prefix and convert the path to the "normal" syntax - for ParseDisplayName. */ - WCHAR *wc = wc_path + 4; - if (wc[1] != L':') /* native UNC path */ - *(wc += 2) = L'\\'; - HRESULT res; - if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL, - &pidl, NULL))) - { - ITEMIDLIST *p; + *(unsigned short *)cp = pidl_len; + memcpy (cp += 2, pidl, pidl_len); + cp += pidl_len; + CoTaskMemFree (pidl); + } - for (p = pidl; p->mkid.cb > 0; - p = (ITEMIDLIST *)((char *) p + p->mkid.cb)) - ; - pidl_len = (char *) p - (char *) pidl + 2; - } - psl->Release (); + /* Create description */ + *(unsigned short *)cp = desc_len; + cp = stpcpy (cp += 2, desc); + + /* Create relpath */ + *(unsigned short *)cp = relpath_len; + cp = stpcpy (cp += 2, relpath); + + /* Append the POSIX path after the regular shortcut data for + the long path support. */ + unsigned short *plen = (unsigned short *) cp; + cp += 2; + *(PWCHAR) cp = 0xfeff; /* BOM */ + cp += 2; + *plen = sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) + * sizeof (WCHAR); + cp += *plen; + } + else + { + /* Default technique creating a symlink. */ + buf = tp.t_get (); + cp = stpcpy (buf, SYMLINK_COOKIE); + *(PWCHAR) cp = 0xfeff; /* BOM */ + cp += 2; + /* Note that the terminating nul is written. */ + cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) + * sizeof (WCHAR); + } + + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + NTSTATUS status; + ULONG access; + HANDLE fh; + + access = DELETE | FILE_GENERIC_WRITE; + if (isdevice && win32_newpath.exists ()) + { + status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES, + win32_newpath.get_object_attr (attr, + sec_none_nih), + &io, 0, FILE_OPEN_FOR_BACKUP_INTENT); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; + } + status = NtSetAttributesFile (fh, FILE_ATTRIBUTE_NORMAL); + NtClose (fh); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; } } - /* Compute size of shortcut file. */ - full_len = sizeof (win_shortcut_hdr); - if (pidl_len) - full_len += sizeof (unsigned short) + pidl_len; - oldpath_len = strlen (oldpath); - /* Unfortunately the length of the description is restricted to a - length of 2000 bytes. We don't want to add considerations for - the different lengths and even 2000 bytes is not enough for long - path names. So what we do here is to set the description to the - POSIX path only if the path is not longer than MAX_PATH characters. - We append the full path name after the regular shortcut data - (see below), which works fine with Windows Explorer as well - as older Cygwin versions (as long as the whole file isn't bigger - than 8K). The description field is only used for backward - compatibility to older Cygwin versions and those versions are - not capable of handling long path names anyway. */ - desc_len = stpcpy (desc, oldpath_len > MAX_PATH - ? "[path too long]" : oldpath) - desc; - full_len += sizeof (unsigned short) + desc_len; - /* Devices get the oldpath string unchanged as relative path. */ - if (isdevice) - { - relpath_len = oldpath_len; - stpcpy (relpath = tp.c_get (), oldpath); - } - else - { - relpath_len = strlen (win32_oldpath.get_win32 ()); - stpcpy (relpath = tp.c_get (), win32_oldpath.get_win32 ()); - } - full_len += sizeof (unsigned short) + relpath_len; - full_len += sizeof (unsigned short) + oldpath_len; - /* 1 byte more for trailing 0 written by stpcpy. */ - if (full_len < NT_MAX_PATH * sizeof (WCHAR)) - buf = tp.t_get (); - else - buf = (char *) alloca (full_len + 1); + else if (!isdevice && win32_newpath.has_acls () + && !win32_newpath.isremote ()) + /* If the filesystem supports ACLs, we will overwrite the DACL after the + call to NtCreateFile. This requires a handle with READ_CONTROL and + WRITE_DAC access, otherwise get_file_sd and set_file_sd both have to + open the file again. + FIXME: On remote NTFS shares open sometimes fails because even the + creator of the file doesn't have the right to change the DACL. + I don't know what setting that is or how to recognize such a share, + so for now we don't request WRITE_DAC on remote drives. */ + access |= READ_CONTROL | WRITE_DAC; - /* Create shortcut header */ - win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf; - memset (shortcut_header, 0, sizeof *shortcut_header); - shortcut_header->size = sizeof *shortcut_header; - shortcut_header->magic = GUID_shortcut; - shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH); - if (pidl) - shortcut_header->flags |= WSH_FLAG_IDLIST; - shortcut_header->run = SW_NORMAL; - cp = buf + sizeof (win_shortcut_hdr); - - /* Create IDLIST */ - if (pidl) - { - *(unsigned short *)cp = pidl_len; - memcpy (cp += 2, pidl, pidl_len); - cp += pidl_len; - CoTaskMemFree (pidl); - } - - /* Create description */ - *(unsigned short *)cp = desc_len; - cp = stpcpy (cp += 2, desc); - - /* Create relpath */ - *(unsigned short *)cp = relpath_len; - cp = stpcpy (cp += 2, relpath); - - /* Append the POSIX path after the regular shortcut data for - the long path support. */ - unsigned short *plen = (unsigned short *) cp; - cp += 2; - *(PWCHAR) cp = 0xfeff; /* BOM */ - cp += 2; - *plen = sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR); - cp += *plen; - } - else - { - /* Default technique creating a symlink. */ - buf = tp.t_get (); - cp = stpcpy (buf, SYMLINK_COOKIE); - *(PWCHAR) cp = 0xfeff; /* BOM */ - cp += 2; - /* Note that the terminating nul is written. */ - cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR); - } - - OBJECT_ATTRIBUTES attr; - IO_STATUS_BLOCK io; - NTSTATUS status; - ULONG access; - HANDLE fh; - - access = DELETE | FILE_GENERIC_WRITE; - if (isdevice && win32_newpath.exists ()) - { - status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES, - win32_newpath.get_object_attr (attr, sec_none_nih), - &io, 0, FILE_OPEN_FOR_BACKUP_INTENT); + status = NtCreateFile (&fh, access, + win32_newpath.get_object_attr (attr, sec_none_nih), + &io, NULL, FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_VALID_FLAGS, + isdevice ? FILE_OVERWRITE_IF : FILE_CREATE, + FILE_SYNCHRONOUS_IO_NONALERT + | FILE_NON_DIRECTORY_FILE + | FILE_OPEN_FOR_BACKUP_INTENT, + NULL, 0); if (!NT_SUCCESS (status)) { __seterrno_from_nt_status (status); - goto done; + __leave; + } + if (win32_newpath.has_acls ()) + set_file_attribute (fh, win32_newpath, ILLEGAL_UID, ILLEGAL_GID, + (io.Information == FILE_CREATED ? S_JUSTCREATED : 0) + | S_IFLNK | STD_RBITS | STD_WBITS); + status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, + NULL, NULL); + if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf)) + { + status = NtSetAttributesFile (fh, wsym_type == WSYM_lnk + ? FILE_ATTRIBUTE_READONLY + : FILE_ATTRIBUTE_SYSTEM); + if (!NT_SUCCESS (status)) + debug_printf ("Setting attributes failed, status = %y", status); + res = 0; + } + else + { + __seterrno_from_nt_status (status); + FILE_DISPOSITION_INFORMATION fdi = { TRUE }; + status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi, + FileDispositionInformation); + if (!NT_SUCCESS (status)) + debug_printf ("Setting delete dispostion failed, status = %y", + status); } - status = NtSetAttributesFile (fh, FILE_ATTRIBUTE_NORMAL); NtClose (fh); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - goto done; - } - } - else if (!isdevice && win32_newpath.has_acls () && !win32_newpath.isremote ()) - /* If the filesystem supports ACLs, we will overwrite the DACL after the - call to NtCreateFile. This requires a handle with READ_CONTROL and - WRITE_DAC access, otherwise get_file_sd and set_file_sd both have to - open the file again. - FIXME: On remote NTFS shares open sometimes fails because even the - creator of the file doesn't have the right to change the DACL. - I don't know what setting that is or how to recognize such a share, - so for now we don't request WRITE_DAC on remote drives. */ - access |= READ_CONTROL | WRITE_DAC; - status = NtCreateFile (&fh, access, - win32_newpath.get_object_attr (attr, sec_none_nih), - &io, NULL, FILE_ATTRIBUTE_NORMAL, - FILE_SHARE_VALID_FLAGS, - isdevice ? FILE_OVERWRITE_IF : FILE_CREATE, - FILE_SYNCHRONOUS_IO_NONALERT - | FILE_NON_DIRECTORY_FILE - | FILE_OPEN_FOR_BACKUP_INTENT, - NULL, 0); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - goto done; } - if (win32_newpath.has_acls ()) - set_file_attribute (fh, win32_newpath, ILLEGAL_UID, ILLEGAL_GID, - (io.Information == FILE_CREATED ? S_JUSTCREATED : 0) - | S_IFLNK | STD_RBITS | STD_WBITS); - status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL); - if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf)) - { - status = NtSetAttributesFile (fh, wsym_type == WSYM_lnk - ? FILE_ATTRIBUTE_READONLY - : FILE_ATTRIBUTE_SYSTEM); - if (!NT_SUCCESS (status)) - debug_printf ("Setting attributes failed, status = %y", status); - res = 0; - } - else - { - __seterrno_from_nt_status (status); - FILE_DISPOSITION_INFORMATION fdi = { TRUE }; - status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi, - FileDispositionInformation); - if (!NT_SUCCESS (status)) - debug_printf ("Setting delete dispostion failed, status = %y", status); - } - NtClose (fh); - -done: + __except (EFAULT) {} + __endtry syscall_printf ("%d = symlink_worker(%s, %s, %d)", res, oldpath, newpath, isdevice); if (has_trailing_dirsep) @@ -3109,13 +3132,16 @@ extern "C" char * getcwd (char *buf, size_t ulen) { char* res = NULL; - myfault efault; - if (efault.faulted (EFAULT)) - /* errno set */; - else if (ulen == 0 && buf) - set_errno (EINVAL); - else - res = cygheap->cwd.get (buf, 1, 1, ulen); + + __try + { + if (ulen == 0 && buf) + set_errno (EINVAL); + else + res = cygheap->cwd.get (buf, 1, 1, ulen); + } + __except (EFAULT) {} + __endtry return res; } @@ -3150,58 +3176,64 @@ get_current_dir_name (void) extern "C" int chdir (const char *in_dir) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (!*in_dir) - { - set_errno (ENOENT); - return -1; - } - - syscall_printf ("dir '%s'", in_dir); - - /* Convert path. First argument ensures that we don't check for NULL/empty/invalid - again. */ - path_conv path (PC_NONULLEMPTY, in_dir, PC_SYM_FOLLOW | PC_POSIX); - if (path.error) - { - set_errno (path.error); - syscall_printf ("-1 = chdir (%s)", in_dir); - return -1; - } - int res = -1; - const char *posix_cwd = NULL; - dev_t devn = path.get_device (); - if (!path.exists ()) - set_errno (ENOENT); - else if (!path.isdir ()) - set_errno (ENOTDIR); - else if (!isvirtual_dev (devn)) + + __try { - /* The sequence chdir("xx"); chdir(".."); must be a noop if xx - is not a symlink. This is exploited by find.exe. - The posix_cwd is just path.normalized_path. - In other cases we let cwd.set obtain the Posix path through - the mount table. */ - if (!isdrive(path.normalized_path)) - posix_cwd = path.normalized_path; - res = 0; + if (!*in_dir) + { + set_errno (ENOENT); + __leave; + } + + syscall_printf ("dir '%s'", in_dir); + + /* Convert path. First argument ensures that we don't check for + NULL/empty/invalid again. */ + path_conv path (PC_NONULLEMPTY, in_dir, PC_SYM_FOLLOW | PC_POSIX); + if (path.error) + { + set_errno (path.error); + syscall_printf ("-1 = chdir (%s)", in_dir); + __leave; + } + + const char *posix_cwd = NULL; + dev_t devn = path.get_device (); + if (!path.exists ()) + set_errno (ENOENT); + else if (!path.isdir ()) + set_errno (ENOTDIR); + else if (!isvirtual_dev (devn)) + { + /* The sequence chdir("xx"); chdir(".."); must be a noop if xx + is not a symlink. This is exploited by find.exe. + The posix_cwd is just path.normalized_path. + In other cases we let cwd.set obtain the Posix path through + the mount table. */ + if (!isdrive(path.normalized_path)) + posix_cwd = path.normalized_path; + res = 0; + } + else + { + posix_cwd = path.normalized_path; + res = 0; + } + + if (!res) + res = cygheap->cwd.set (&path, posix_cwd); + + /* Note that we're accessing cwd.posix without a lock here. + I didn't think it was worth locking just for strace. */ + syscall_printf ("%R = chdir() cygheap->cwd.posix '%s' native '%S'", res, + cygheap->cwd.get_posix (), path.get_nt_native_path ()); } - else - { - posix_cwd = path.normalized_path; - res = 0; - } - - if (!res) - res = cygheap->cwd.set (&path, posix_cwd); - - /* Note that we're accessing cwd.posix without a lock here. I didn't think - it was worth locking just for strace. */ - syscall_printf ("%R = chdir() cygheap->cwd.posix '%s' native '%S'", res, - cygheap->cwd.get_posix (), path.get_nt_native_path ()); + __except (EFAULT) + { + res = -1; + } + __endtry MALLOC_CHECK; return res; } @@ -3239,10 +3271,6 @@ cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, size_t size) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - path_conv p; size_t lsiz = 0; char *buf = NULL; @@ -3250,152 +3278,177 @@ cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, int error = 0; bool relative = !!(what & CCP_RELATIVE); what &= CCP_CONVTYPE_MASK; + int ret = -1; - if (!from) + __try { - set_errno (EINVAL); - return -1; - } - - switch (what) - { - case CCP_POSIX_TO_WIN_A: - { - p.check ((const char *) from, - PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP - | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0)); - if (p.error) - return_with_errno (p.error); - PUNICODE_STRING up = p.get_nt_native_path (); - buf = tp.c_get (); - sys_wcstombs (buf, NT_MAX_PATH, - up->Buffer, up->Length / sizeof (WCHAR)); - /* Convert native path to standard DOS path. */ - if (!strncmp (buf, "\\??\\", 4)) - { - buf += 4; - if (buf[1] != ':') /* native UNC path */ - *(buf += 2) = '\\'; - } - else if (*buf == '\\') - { - /* Device name points to somewhere else in the NT namespace. - Use GLOBALROOT prefix to convert to Win32 path. */ - char *p = buf + sys_wcstombs (buf, NT_MAX_PATH, - ro_u_globalroot.Buffer, - ro_u_globalroot.Length - / sizeof (WCHAR)); - sys_wcstombs (p, NT_MAX_PATH - (p - buf), - up->Buffer, up->Length / sizeof (WCHAR)); - } - lsiz = strlen (buf) + 1; - /* TODO: Incoming "." is a special case which leads to a trailing - backslash ".\\" in the Win32 path. That's a result of the - conversion in normalize_posix_path. This should not occur - so the below code is just a band-aid. */ - if (relative && !strcmp ((const char *) from, ".") - && !strcmp (buf, ".\\")) - { - lsiz = 2; - buf[1] = '\0'; - } - } - break; - case CCP_POSIX_TO_WIN_W: - p.check ((const char *) from, - PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP - | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0)); - if (p.error) - return_with_errno (p.error); - /* Relative Windows paths are always restricted to MAX_PATH chars. */ - if (relative && !isabspath (p.get_win32 ()) - && sys_mbstowcs (NULL, 0, p.get_win32 ()) > MAX_PATH) + if (!from) { - /* Recreate as absolute path. */ - p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW - | PC_NO_ACCESS_CHECK | PC_NOWARN); - if (p.error) - return_with_errno (p.error); + set_errno (EINVAL); + __leave; } - lsiz = p.get_wide_win32_path_len () + 1; - path = p.get_nt_native_path ()->Buffer; - /* Convert native path to standard DOS path. */ - if (!wcsncmp (path, L"\\??\\", 4)) + switch (what) { - path[1] = L'\\'; - - /* Drop long path prefix for short pathnames. Unfortunately there's - quite a bunch of Win32 functions, especially in user32.dll, - apparently, which don't grok long path names at all, not even - in the UNICODE API. */ - if ((path[5] == L':' && lsiz <= MAX_PATH + 4) - || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6)) + case CCP_POSIX_TO_WIN_A: + { + p.check ((const char *) from, + PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP + | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0)); + if (p.error) + { + set_errno (p.error); + __leave; + } + PUNICODE_STRING up = p.get_nt_native_path (); + buf = tp.c_get (); + sys_wcstombs (buf, NT_MAX_PATH, + up->Buffer, up->Length / sizeof (WCHAR)); + /* Convert native path to standard DOS path. */ + if (!strncmp (buf, "\\??\\", 4)) + { + buf += 4; + if (buf[1] != ':') /* native UNC path */ + *(buf += 2) = '\\'; + } + else if (*buf == '\\') + { + /* Device name points to somewhere else in the NT namespace. + Use GLOBALROOT prefix to convert to Win32 path. */ + char *p = buf + sys_wcstombs (buf, NT_MAX_PATH, + ro_u_globalroot.Buffer, + ro_u_globalroot.Length + / sizeof (WCHAR)); + sys_wcstombs (p, NT_MAX_PATH - (p - buf), + up->Buffer, up->Length / sizeof (WCHAR)); + } + lsiz = strlen (buf) + 1; + /* TODO: Incoming "." is a special case which leads to a trailing + backslash ".\\" in the Win32 path. That's a result of the + conversion in normalize_posix_path. This should not occur + so the below code is just a band-aid. */ + if (relative && !strcmp ((const char *) from, ".") + && !strcmp (buf, ".\\")) + { + lsiz = 2; + buf[1] = '\0'; + } + } + break; + case CCP_POSIX_TO_WIN_W: + p.check ((const char *) from, + PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP + | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0)); + if (p.error) { - path += 4; - lsiz -= 4; - if (path[1] != L':') + set_errno (p.error); + __leave; + } + /* Relative Windows paths are always restricted to MAX_PATH chars. */ + if (relative && !isabspath (p.get_win32 ()) + && sys_mbstowcs (NULL, 0, p.get_win32 ()) > MAX_PATH) + { + /* Recreate as absolute path. */ + p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW + | PC_NO_ACCESS_CHECK | PC_NOWARN); + if (p.error) { - *(path += 2) = '\\'; - lsiz -= 2; + set_errno (p.error); + __leave; } } + lsiz = p.get_wide_win32_path_len () + 1; + path = p.get_nt_native_path ()->Buffer; + + /* Convert native path to standard DOS path. */ + if (!wcsncmp (path, L"\\??\\", 4)) + { + path[1] = L'\\'; + + /* Drop long path prefix for short pathnames. Unfortunately there's + quite a bunch of Win32 functions, especially in user32.dll, + apparently, which don't grok long path names at all, not even + in the UNICODE API. */ + if ((path[5] == L':' && lsiz <= MAX_PATH + 4) + || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6)) + { + path += 4; + lsiz -= 4; + if (path[1] != L':') + { + *(path += 2) = '\\'; + lsiz -= 2; + } + } + } + else if (*path == L'\\') + { + /* Device name points to somewhere else in the NT namespace. + Use GLOBALROOT prefix to convert to Win32 path. */ + to = (void *) wcpcpy ((wchar_t *) to, ro_u_globalroot.Buffer); + lsiz += ro_u_globalroot.Length / sizeof (WCHAR); + } + /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */ + if (relative && !strcmp ((const char *) from, ".") + && !wcscmp (path, L".\\")) + { + lsiz = 2; + path[1] = L'\0'; + } + lsiz *= sizeof (WCHAR); + break; + case CCP_WIN_A_TO_POSIX: + buf = tp.c_get (); + error = mount_table->conv_to_posix_path ((const char *) from, buf, + relative); + if (error) + { + set_errno (p.error); + __leave; + } + lsiz = strlen (buf) + 1; + break; + case CCP_WIN_W_TO_POSIX: + buf = tp.c_get (); + error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf, + relative); + if (error) + { + set_errno (error); + __leave; + } + lsiz = strlen (buf) + 1; + break; + default: + set_errno (EINVAL); + __leave; } - else if (*path == L'\\') + if (!size) { - /* Device name points to somewhere else in the NT namespace. - Use GLOBALROOT prefix to convert to Win32 path. */ - to = (void *) wcpcpy ((wchar_t *) to, ro_u_globalroot.Buffer); - lsiz += ro_u_globalroot.Length / sizeof (WCHAR); + ret = lsiz; + __leave; } - /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */ - if (relative && !strcmp ((const char *) from, ".") - && !wcscmp (path, L".\\")) + if (size < lsiz) { - lsiz = 2; - path[1] = L'\0'; + set_errno (ENOSPC); + __leave; } - lsiz *= sizeof (WCHAR); - break; - case CCP_WIN_A_TO_POSIX: - buf = tp.c_get (); - error = mount_table->conv_to_posix_path ((const char *) from, buf, - relative); - if (error) - return_with_errno (error); - lsiz = strlen (buf) + 1; - break; - case CCP_WIN_W_TO_POSIX: - buf = tp.c_get (); - error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf, - relative); - if (error) - return_with_errno (error); - lsiz = strlen (buf) + 1; - break; - default: - set_errno (EINVAL); - return -1; + switch (what) + { + case CCP_POSIX_TO_WIN_A: + case CCP_WIN_A_TO_POSIX: + case CCP_WIN_W_TO_POSIX: + stpcpy ((char *) to, buf); + break; + case CCP_POSIX_TO_WIN_W: + wcpcpy ((PWCHAR) to, path); + break; + } + ret = 0; } - if (!size) - return lsiz; - if (size < lsiz) - { - set_errno (ENOSPC); - return -1; - } - switch (what) - { - case CCP_POSIX_TO_WIN_A: - case CCP_WIN_A_TO_POSIX: - case CCP_WIN_W_TO_POSIX: - stpcpy ((char *) to, buf); - break; - case CCP_POSIX_TO_WIN_W: - wcpcpy ((PWCHAR) to, path); - break; - } - return 0; + __except (EFAULT) {} + __endtry + return ret; } extern "C" void * @@ -3454,6 +3507,9 @@ cygwin_conv_to_full_posix_path (const char *path, char *posix_path) extern "C" char * realpath (const char *__restrict path, char *__restrict resolved) { + tmp_pathbuf tp; + char *tpath; + /* Make sure the right errno is returned if path is NULL. */ if (!path) { @@ -3463,48 +3519,48 @@ realpath (const char *__restrict path, char *__restrict resolved) /* Guard reading from a potentially invalid path and writing to a potentially invalid resolved. */ - tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - - /* Win32 drive letter paths have to be converted to a POSIX path first, - because path_conv leaves the incoming path untouched except for - converting backslashes to forward slashes. */ - char *tpath; - if (isdrive (path)) + __try { - tpath = tp.c_get (); - mount_table->conv_to_posix_path (path, tpath, 0); - } - else - tpath = (char *) path; - - path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); - - - /* POSIX 2008 requires malloc'ing if resolved is NULL, and states - that using non-NULL resolved is asking for portability - problems. */ - - if (!real_path.error && real_path.exists ()) - { - if (!resolved) + /* Win32 drive letter paths have to be converted to a POSIX path first, + because path_conv leaves the incoming path untouched except for + converting backslashes to forward slashes. */ + if (isdrive (path)) { - resolved = (char *) malloc (strlen (real_path.normalized_path) + 1); - if (!resolved) - return NULL; + tpath = tp.c_get (); + mount_table->conv_to_posix_path (path, tpath, 0); } - strcpy (resolved, real_path.normalized_path); - return resolved; - } + else + tpath = (char *) path; - /* FIXME: on error, Linux puts the name of the path - component which could not be resolved into RESOLVED, but POSIX - does not require this. */ - if (resolved) - resolved[0] = '\0'; - set_errno (real_path.error ?: ENOENT); + path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); + + + /* POSIX 2008 requires malloc'ing if resolved is NULL, and states + that using non-NULL resolved is asking for portability + problems. */ + + if (!real_path.error && real_path.exists ()) + { + if (!resolved) + { + resolved = (char *) + malloc (strlen (real_path.normalized_path) + 1); + if (!resolved) + return NULL; + } + strcpy (resolved, real_path.normalized_path); + return resolved; + } + + /* FIXME: on error, Linux puts the name of the path + component which could not be resolved into RESOLVED, but POSIX + does not require this. */ + if (resolved) + resolved[0] = '\0'; + set_errno (real_path.error ?: ENOENT); + } + __except (EFAULT) {} + __endtry return NULL; } diff --git a/winsup/cygwin/poll.cc b/winsup/cygwin/poll.cc index 8ce4a28be..17411a098 100644 --- a/winsup/cygwin/poll.cc +++ b/winsup/cygwin/poll.cc @@ -1,7 +1,7 @@ /* poll.cc. Implements poll(2) via usage of select(2) call. Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011, - 2012 Red Hat, Inc. + 2012, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -143,16 +143,19 @@ ppoll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, int timeout; sigset_t oldset = _my_tls.sigmask; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - timeout = (timeout_ts == NULL) - ? -1 - : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000); - if (sigmask) - set_signal_mask (_my_tls.sigmask, *sigmask); - int ret = poll (fds, nfds, timeout); - if (sigmask) - set_signal_mask (_my_tls.sigmask, oldset); - return ret; + __try + { + timeout = (timeout_ts == NULL) + ? -1 + : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000); + if (sigmask) + set_signal_mask (_my_tls.sigmask, *sigmask); + int ret = poll (fds, nfds, timeout); + if (sigmask) + set_signal_mask (_my_tls.sigmask, oldset); + return ret; + } + __except (EFAULT) {} + __endtry + return -1; } diff --git a/winsup/cygwin/posix_ipc.cc b/winsup/cygwin/posix_ipc.cc index be4a973a9..067fa5bb0 100644 --- a/winsup/cygwin/posix_ipc.cc +++ b/winsup/cygwin/posix_ipc.cc @@ -1,6 +1,6 @@ /* posix_ipc.cc: POSIX IPC API for Cygwin. - Copyright 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. + Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -414,17 +414,17 @@ extern "C" void *mmap64 (void *, size_t, int, int, int, off_t); extern "C" mqd_t mq_open (const char *name, int oflag, ...) { - int i, fd = -1, nonblock, created; + int i, fd = -1, nonblock, created = 0; long msgsize, index; off_t filesize = 0; va_list ap; mode_t mode; - int8_t *mptr; + int8_t *mptr = (int8_t *) MAP_FAILED; struct stat statbuff; struct mq_hdr *mqhdr; struct msg_hdr *msghdr; struct mq_attr *attr; - struct mq_info *mqinfo; + struct mq_info *mqinfo = NULL; LUID luid; size_t len = strlen (name); @@ -433,190 +433,198 @@ mq_open (const char *name, int oflag, ...) if (!check_path (mqname, mqueue, name, len)) return (mqd_t) -1; - myfault efault; - if (efault.faulted (EFAULT)) - return (mqd_t) -1; - - oflag &= (O_CREAT | O_EXCL | O_NONBLOCK); - created = 0; - nonblock = oflag & O_NONBLOCK; - oflag &= ~O_NONBLOCK; - mptr = (int8_t *) MAP_FAILED; - mqinfo = NULL; - -again: - if (oflag & O_CREAT) + __try { - va_start (ap, oflag); /* init ap to final named argument */ - mode = va_arg (ap, mode_t) & ~S_IXUSR; - attr = va_arg (ap, struct mq_attr *); - va_end (ap); + oflag &= (O_CREAT | O_EXCL | O_NONBLOCK); + nonblock = oflag & O_NONBLOCK; + oflag &= ~O_NONBLOCK; - /* Open and specify O_EXCL and user-execute */ - fd = open (mqname, oflag | O_EXCL | O_RDWR | O_CLOEXEC, mode | S_IXUSR); - if (fd < 0) + again: + if (oflag & O_CREAT) { - if (errno == EEXIST && (oflag & O_EXCL) == 0) - goto exists; /* already exists, OK */ - return (mqd_t) -1; - } - created = 1; - /* First one to create the file initializes it */ - if (attr == NULL) - attr = &defattr; - /* Check minimum and maximum values. The max values are pretty much - arbitrary, taken from the linux mq_overview man page. However, - these max values make sure that the internal mq_fattr structure - can use 32 bit types. */ - else if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > 32768 - || attr->mq_msgsize <= 0 || attr->mq_msgsize > 1048576) - { - set_errno (EINVAL); - goto err; - } - /* Calculate and set the file size */ - msgsize = MSGSIZE (attr->mq_msgsize); - filesize = sizeof (struct mq_hdr) - + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize)); - if (lseek64 (fd, filesize - 1, SEEK_SET) == -1) - goto err; - if (write (fd, "", 1) == -1) - goto err; + va_start (ap, oflag); /* init ap to final named argument */ + mode = va_arg (ap, mode_t) & ~S_IXUSR; + attr = va_arg (ap, struct mq_attr *); + va_end (ap); - /* Memory map the file */ + /* Open and specify O_EXCL and user-execute */ + fd = open (mqname, oflag | O_EXCL | O_RDWR | O_CLOEXEC, + mode | S_IXUSR); + if (fd < 0) + { + if (errno == EEXIST && (oflag & O_EXCL) == 0) + goto exists; /* already exists, OK */ + return (mqd_t) -1; + } + created = 1; + /* First one to create the file initializes it */ + if (attr == NULL) + attr = &defattr; + /* Check minimum and maximum values. The max values are pretty much + arbitrary, taken from the linux mq_overview man page. However, + these max values make sure that the internal mq_fattr structure + can use 32 bit types. */ + else if (attr->mq_maxmsg <= 0 || attr->mq_maxmsg > 32768 + || attr->mq_msgsize <= 0 || attr->mq_msgsize > 1048576) + { + set_errno (EINVAL); + __leave; + } + /* Calculate and set the file size */ + msgsize = MSGSIZE (attr->mq_msgsize); + filesize = sizeof (struct mq_hdr) + + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize)); + if (lseek64 (fd, filesize - 1, SEEK_SET) == -1) + __leave; + if (write (fd, "", 1) == -1) + __leave; + + /* Memory map the file */ + mptr = (int8_t *) mmap64 (NULL, (size_t) filesize, + PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (mptr == (int8_t *) MAP_FAILED) + __leave; + + /* Allocate one mq_info{} for the queue */ + if (!(mqinfo = (struct mq_info *) + calloc (1, sizeof (struct mq_info)))) + __leave; + mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr; + mqinfo->mqi_magic = MQI_MAGIC; + mqinfo->mqi_flags = nonblock; + + /* Initialize header at beginning of file */ + /* Create free list with all messages on it */ + mqhdr->mqh_attr.mq_flags = 0; + mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg; + mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize; + mqhdr->mqh_attr.mq_curmsgs = 0; + mqhdr->mqh_nwait = 0; + mqhdr->mqh_pid = 0; + NtAllocateLocallyUniqueId (&luid); + __small_sprintf (mqhdr->mqh_uname, "%016X%08x%08x", + hash_path_name (0,mqname), + luid.HighPart, luid.LowPart); + mqhdr->mqh_head = 0; + mqhdr->mqh_magic = MQI_MAGIC; + index = sizeof (struct mq_hdr); + mqhdr->mqh_free = index; + for (i = 0; i < attr->mq_maxmsg - 1; i++) + { + msghdr = (struct msg_hdr *) &mptr[index]; + index += sizeof (struct msg_hdr) + msgsize; + msghdr->msg_next = index; + } + msghdr = (struct msg_hdr *) &mptr[index]; + msghdr->msg_next = 0; /* end of free list */ + + /* Initialize mutex & condition variables */ + i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname); + if (i != 0) + { + set_errno (i); + __leave; + } + i = ipc_cond_init (&mqinfo->mqi_waitsend, mqhdr->mqh_uname, 'S'); + if (i != 0) + { + set_errno (i); + __leave; + } + i = ipc_cond_init (&mqinfo->mqi_waitrecv, mqhdr->mqh_uname, 'R'); + if (i != 0) + { + set_errno (i); + __leave; + } + /* Initialization complete, turn off user-execute bit */ + if (fchmod (fd, mode) == -1) + __leave; + close (fd); + return ((mqd_t) mqinfo); + } + + exists: + /* Open the file then memory map */ + if ((fd = open (mqname, O_RDWR | O_CLOEXEC)) < 0) + { + if (errno == ENOENT && (oflag & O_CREAT)) + goto again; + __leave; + } + /* Make certain initialization is complete */ + for (i = 0; i < MAX_TRIES; i++) + { + if (stat64 (mqname, &statbuff) == -1) + { + if (errno == ENOENT && (oflag & O_CREAT)) + { + close (fd); + fd = -1; + goto again; + } + __leave; + } + if ((statbuff.st_mode & S_IXUSR) == 0) + break; + sleep (1); + } + if (i == MAX_TRIES) + { + set_errno (ETIMEDOUT); + __leave; + } + + filesize = statbuff.st_size; mptr = (int8_t *) mmap64 (NULL, (size_t) filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mptr == (int8_t *) MAP_FAILED) - goto err; + __leave; + close (fd); + fd = -1; - /* Allocate one mq_info{} for the queue */ + /* Allocate one mq_info{} for each open */ if (!(mqinfo = (struct mq_info *) calloc (1, sizeof (struct mq_info)))) - goto err; + __leave; mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr; + if (mqhdr->mqh_magic != MQI_MAGIC) + { + system_printf ( + "Old message queue \"%s\" detected!\n" + "This file is not usable as message queue anymore due to changes in the " + "internal file layout. Please remove the file and try again.", mqname); + set_errno (EACCES); + __leave; + } mqinfo->mqi_magic = MQI_MAGIC; mqinfo->mqi_flags = nonblock; - /* Initialize header at beginning of file */ - /* Create free list with all messages on it */ - mqhdr->mqh_attr.mq_flags = 0; - mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg; - mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize; - mqhdr->mqh_attr.mq_curmsgs = 0; - mqhdr->mqh_nwait = 0; - mqhdr->mqh_pid = 0; - NtAllocateLocallyUniqueId (&luid); - __small_sprintf (mqhdr->mqh_uname, "%016X%08x%08x", - hash_path_name (0,mqname), - luid.HighPart, luid.LowPart); - mqhdr->mqh_head = 0; - mqhdr->mqh_magic = MQI_MAGIC; - index = sizeof (struct mq_hdr); - mqhdr->mqh_free = index; - for (i = 0; i < attr->mq_maxmsg - 1; i++) - { - msghdr = (struct msg_hdr *) &mptr[index]; - index += sizeof (struct msg_hdr) + msgsize; - msghdr->msg_next = index; - } - msghdr = (struct msg_hdr *) &mptr[index]; - msghdr->msg_next = 0; /* end of free list */ - - /* Initialize mutex & condition variables */ + /* Initialize mutex & condition variable */ i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname); if (i != 0) - goto pthreaderr; - + { + set_errno (i); + __leave; + } i = ipc_cond_init (&mqinfo->mqi_waitsend, mqhdr->mqh_uname, 'S'); if (i != 0) - goto pthreaderr; - + { + set_errno (i); + __leave; + } i = ipc_cond_init (&mqinfo->mqi_waitrecv, mqhdr->mqh_uname, 'R'); if (i != 0) - goto pthreaderr; - - /* Initialization complete, turn off user-execute bit */ - if (fchmod (fd, mode) == -1) - goto err; - close (fd); - return ((mqd_t) mqinfo); - } - -exists: - /* Open the file then memory map */ - if ((fd = open (mqname, O_RDWR | O_CLOEXEC)) < 0) - { - if (errno == ENOENT && (oflag & O_CREAT)) - goto again; - goto err; - } - /* Make certain initialization is complete */ - for (i = 0; i < MAX_TRIES; i++) - { - if (stat64 (mqname, &statbuff) == -1) { - if (errno == ENOENT && (oflag & O_CREAT)) - { - close (fd); - fd = -1; - goto again; - } - goto err; + set_errno (i); + __leave; } - if ((statbuff.st_mode & S_IXUSR) == 0) - break; - sleep (1); + return (mqd_t) mqinfo; } - if (i == MAX_TRIES) - { - set_errno (ETIMEDOUT); - goto err; - } - - filesize = statbuff.st_size; - mptr = (int8_t *) mmap64 (NULL, (size_t) filesize, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, 0); - if (mptr == (int8_t *) MAP_FAILED) - goto err; - close (fd); - fd = -1; - - /* Allocate one mq_info{} for each open */ - if (!(mqinfo = (struct mq_info *) calloc (1, sizeof (struct mq_info)))) - goto err; - mqinfo->mqi_hdr = mqhdr = (struct mq_hdr *) mptr; - if (mqhdr->mqh_magic != MQI_MAGIC) - { - system_printf ( -"Old message queue \"%s\" detected!\n" -"This file is not usable as message queue anymore due to changes in the " -"internal file layout. Please remove the file and try again.", mqname); - set_errno (EACCES); - goto err; - } - mqinfo->mqi_magic = MQI_MAGIC; - mqinfo->mqi_flags = nonblock; - - /* Initialize mutex & condition variable */ - i = ipc_mutex_init (&mqinfo->mqi_lock, mqhdr->mqh_uname); - if (i != 0) - goto pthreaderr; - - i = ipc_cond_init (&mqinfo->mqi_waitsend, mqhdr->mqh_uname, 'S'); - if (i != 0) - goto pthreaderr; - - i = ipc_cond_init (&mqinfo->mqi_waitrecv, mqhdr->mqh_uname, 'R'); - if (i != 0) - goto pthreaderr; - - return (mqd_t) mqinfo; - -pthreaderr: - errno = i; -err: + __except (EFAULT) {} + __endtry /* Don't let following function calls change errno */ save_errno save; - if (created) unlink (mqname); if (mptr != (int8_t *) MAP_FAILED) @@ -644,30 +652,32 @@ mq_getattr (mqd_t mqd, struct mq_attr *mqstat) struct mq_fattr *attr; struct mq_info *mqinfo; - myfault efault; - if (efault.faulted (EBADF)) - return -1; - - mqinfo = (struct mq_info *) mqd; - if (mqinfo->mqi_magic != MQI_MAGIC) + __try { - set_errno (EBADF); - return -1; - } - mqhdr = mqinfo->mqi_hdr; - attr = &mqhdr->mqh_attr; - if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) - { - errno = n; - return -1; - } - mqstat->mq_flags = mqinfo->mqi_flags; /* per-open */ - mqstat->mq_maxmsg = attr->mq_maxmsg; /* remaining three per-queue */ - mqstat->mq_msgsize = attr->mq_msgsize; - mqstat->mq_curmsgs = attr->mq_curmsgs; + mqinfo = (struct mq_info *) mqd; + if (mqinfo->mqi_magic != MQI_MAGIC) + { + set_errno (EBADF); + __leave; + } + mqhdr = mqinfo->mqi_hdr; + attr = &mqhdr->mqh_attr; + if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) + { + errno = n; + __leave; + } + mqstat->mq_flags = mqinfo->mqi_flags; /* per-open */ + mqstat->mq_maxmsg = attr->mq_maxmsg; /* remaining three per-queue */ + mqstat->mq_msgsize = attr->mq_msgsize; + mqstat->mq_curmsgs = attr->mq_curmsgs; - ipc_mutex_unlock (mqinfo->mqi_lock); - return 0; + ipc_mutex_unlock (mqinfo->mqi_lock); + return 0; + } + __except (EBADF) {} + __endtry + return -1; } extern "C" int @@ -678,39 +688,41 @@ mq_setattr (mqd_t mqd, const struct mq_attr *mqstat, struct mq_attr *omqstat) struct mq_fattr *attr; struct mq_info *mqinfo; - myfault efault; - if (efault.faulted (EBADF)) - return -1; - - mqinfo = (struct mq_info *) mqd; - if (mqinfo->mqi_magic != MQI_MAGIC) + __try { - set_errno (EBADF); - return -1; - } - mqhdr = mqinfo->mqi_hdr; - attr = &mqhdr->mqh_attr; - if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) - { - errno = n; - return -1; - } + mqinfo = (struct mq_info *) mqd; + if (mqinfo->mqi_magic != MQI_MAGIC) + { + set_errno (EBADF); + __leave; + } + mqhdr = mqinfo->mqi_hdr; + attr = &mqhdr->mqh_attr; + if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) + { + errno = n; + __leave; + } - if (omqstat != NULL) - { - omqstat->mq_flags = mqinfo->mqi_flags; /* previous attributes */ - omqstat->mq_maxmsg = attr->mq_maxmsg; - omqstat->mq_msgsize = attr->mq_msgsize; - omqstat->mq_curmsgs = attr->mq_curmsgs; /* and current status */ + if (omqstat != NULL) + { + omqstat->mq_flags = mqinfo->mqi_flags; /* previous attributes */ + omqstat->mq_maxmsg = attr->mq_maxmsg; + omqstat->mq_msgsize = attr->mq_msgsize; + omqstat->mq_curmsgs = attr->mq_curmsgs; /* and current status */ + } + + if (mqstat->mq_flags & O_NONBLOCK) + mqinfo->mqi_flags |= O_NONBLOCK; + else + mqinfo->mqi_flags &= ~O_NONBLOCK; + + ipc_mutex_unlock (mqinfo->mqi_lock); + return 0; } - - if (mqstat->mq_flags & O_NONBLOCK) - mqinfo->mqi_flags |= O_NONBLOCK; - else - mqinfo->mqi_flags &= ~O_NONBLOCK; - - ipc_mutex_unlock (mqinfo->mqi_lock); - return 0; + __except (EBADF) {} + __endtry + return -1; } extern "C" int @@ -721,45 +733,47 @@ mq_notify (mqd_t mqd, const struct sigevent *notification) struct mq_hdr *mqhdr; struct mq_info *mqinfo; - myfault efault; - if (efault.faulted (EBADF)) - return -1; - - mqinfo = (struct mq_info *) mqd; - if (mqinfo->mqi_magic != MQI_MAGIC) + __try { - set_errno (EBADF); - return -1; - } - mqhdr = mqinfo->mqi_hdr; - if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) - { - errno = n; - return -1; - } - - pid = getpid (); - if (!notification) - { - if (mqhdr->mqh_pid == pid) - mqhdr->mqh_pid = 0; /* unregister calling process */ - } - else - { - if (mqhdr->mqh_pid != 0) + mqinfo = (struct mq_info *) mqd; + if (mqinfo->mqi_magic != MQI_MAGIC) { - if (kill (mqhdr->mqh_pid, 0) != -1 || errno != ESRCH) - { - set_errno (EBUSY); - ipc_mutex_unlock (mqinfo->mqi_lock); - return -1; - } + set_errno (EBADF); + __leave; } - mqhdr->mqh_pid = pid; - mqhdr->mqh_event = *notification; + mqhdr = mqinfo->mqi_hdr; + if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) + { + errno = n; + __leave; + } + + pid = getpid (); + if (!notification) + { + if (mqhdr->mqh_pid == pid) + mqhdr->mqh_pid = 0; /* unregister calling process */ + } + else + { + if (mqhdr->mqh_pid != 0) + { + if (kill (mqhdr->mqh_pid, 0) != -1 || errno != ESRCH) + { + set_errno (EBUSY); + ipc_mutex_unlock (mqinfo->mqi_lock); + __leave; + } + } + mqhdr->mqh_pid = pid; + mqhdr->mqh_event = *notification; + } + ipc_mutex_unlock (mqinfo->mqi_lock); + return 0; } - ipc_mutex_unlock (mqinfo->mqi_lock); - return 0; + __except (EBADF) {} + __endtry + return -1; } static int @@ -773,113 +787,116 @@ _mq_send (mqd_t mqd, const char *ptr, size_t len, unsigned int prio, struct mq_hdr *mqhdr; struct mq_fattr *attr; struct msg_hdr *msghdr, *nmsghdr, *pmsghdr; - struct mq_info *mqinfo; + struct mq_info *mqinfo = NULL; + bool ipc_mutex_locked = false; + int ret = -1; pthread_testcancel (); - myfault efault; - if (efault.faulted (EBADF)) - return -1; - - mqinfo = (struct mq_info *) mqd; - if (mqinfo->mqi_magic != MQI_MAGIC) + __try { - set_errno (EBADF); - return -1; - } - if (prio > MQ_PRIO_MAX) - { - set_errno (EINVAL); - return -1; - } - - mqhdr = mqinfo->mqi_hdr; /* struct pointer */ - mptr = (int8_t *) mqhdr; /* byte pointer */ - attr = &mqhdr->mqh_attr; - if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) - { - errno = n; - return -1; - } - - if (len > (size_t) attr->mq_msgsize) - { - set_errno (EMSGSIZE); - goto err; - } - if (attr->mq_curmsgs == 0) - { - if (mqhdr->mqh_pid != 0 && mqhdr->mqh_nwait == 0) + mqinfo = (struct mq_info *) mqd; + if (mqinfo->mqi_magic != MQI_MAGIC) { - sigev = &mqhdr->mqh_event; - if (sigev->sigev_notify == SIGEV_SIGNAL) - sigqueue (mqhdr->mqh_pid, sigev->sigev_signo, sigev->sigev_value); - mqhdr->mqh_pid = 0; /* unregister */ + set_errno (EBADF); + __leave; } - } - else if (attr->mq_curmsgs >= attr->mq_maxmsg) - { - /* Queue is full */ - if (mqinfo->mqi_flags & O_NONBLOCK) + if (prio > MQ_PRIO_MAX) { - set_errno (EAGAIN); - goto err; + set_errno (EINVAL); + __leave; } - /* Wait for room for one message on the queue */ - while (attr->mq_curmsgs >= attr->mq_maxmsg) + + mqhdr = mqinfo->mqi_hdr; /* struct pointer */ + mptr = (int8_t *) mqhdr; /* byte pointer */ + attr = &mqhdr->mqh_attr; + if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) { - int ret = ipc_cond_timedwait (mqinfo->mqi_waitsend, mqinfo->mqi_lock, - abstime); - if (ret != 0) + errno = n; + __leave; + } + ipc_mutex_locked = true; + if (len > (size_t) attr->mq_msgsize) + { + set_errno (EMSGSIZE); + __leave; + } + if (attr->mq_curmsgs == 0) + { + if (mqhdr->mqh_pid != 0 && mqhdr->mqh_nwait == 0) { - set_errno (ret); - return -1; + sigev = &mqhdr->mqh_event; + if (sigev->sigev_notify == SIGEV_SIGNAL) + sigqueue (mqhdr->mqh_pid, sigev->sigev_signo, + sigev->sigev_value); + mqhdr->mqh_pid = 0; /* unregister */ } } - } - - /* nmsghdr will point to new message */ - if ((freeindex = mqhdr->mqh_free) == 0) - api_fatal ("mq_send: curmsgs = %ld; free = 0", attr->mq_curmsgs); - - nmsghdr = (struct msg_hdr *) &mptr[freeindex]; - nmsghdr->msg_prio = prio; - nmsghdr->msg_len = len; - memcpy (nmsghdr + 1, ptr, len); /* copy message from caller */ - mqhdr->mqh_free = nmsghdr->msg_next; /* new freelist head */ - - /* Find right place for message in linked list */ - index = mqhdr->mqh_head; - pmsghdr = (struct msg_hdr *) &(mqhdr->mqh_head); - while (index) - { - msghdr = (struct msg_hdr *) &mptr[index]; - if (prio > msghdr->msg_prio) + else if (attr->mq_curmsgs >= attr->mq_maxmsg) { - nmsghdr->msg_next = index; - pmsghdr->msg_next = freeindex; - break; + /* Queue is full */ + if (mqinfo->mqi_flags & O_NONBLOCK) + { + set_errno (EAGAIN); + __leave; + } + /* Wait for room for one message on the queue */ + while (attr->mq_curmsgs >= attr->mq_maxmsg) + { + int ret = ipc_cond_timedwait (mqinfo->mqi_waitsend, + mqinfo->mqi_lock, abstime); + if (ret != 0) + { + set_errno (ret); + __leave; + } + } } - index = msghdr->msg_next; - pmsghdr = msghdr; - } - if (index == 0) - { - /* Queue was empty or new goes at end of list */ - pmsghdr->msg_next = freeindex; - nmsghdr->msg_next = 0; - } - /* Wake up anyone blocked in mq_receive waiting for a message */ - if (attr->mq_curmsgs == 0) - ipc_cond_signal (mqinfo->mqi_waitrecv); - attr->mq_curmsgs++; - ipc_mutex_unlock (mqinfo->mqi_lock); - return 0; + /* nmsghdr will point to new message */ + if ((freeindex = mqhdr->mqh_free) == 0) + api_fatal ("mq_send: curmsgs = %ld; free = 0", attr->mq_curmsgs); -err: - ipc_mutex_unlock (mqinfo->mqi_lock); - return -1; + nmsghdr = (struct msg_hdr *) &mptr[freeindex]; + nmsghdr->msg_prio = prio; + nmsghdr->msg_len = len; + memcpy (nmsghdr + 1, ptr, len); /* copy message from caller */ + mqhdr->mqh_free = nmsghdr->msg_next; /* new freelist head */ + + /* Find right place for message in linked list */ + index = mqhdr->mqh_head; + pmsghdr = (struct msg_hdr *) &(mqhdr->mqh_head); + while (index) + { + msghdr = (struct msg_hdr *) &mptr[index]; + if (prio > msghdr->msg_prio) + { + nmsghdr->msg_next = index; + pmsghdr->msg_next = freeindex; + break; + } + index = msghdr->msg_next; + pmsghdr = msghdr; + } + if (index == 0) + { + /* Queue was empty or new goes at end of list */ + pmsghdr->msg_next = freeindex; + nmsghdr->msg_next = 0; + } + /* Wake up anyone blocked in mq_receive waiting for a message */ + if (attr->mq_curmsgs == 0) + ipc_cond_signal (mqinfo->mqi_waitrecv); + attr->mq_curmsgs++; + + ipc_mutex_unlock (mqinfo->mqi_lock); + ret = 0; + } + __except (EBADF) {} + __endtry + if (ipc_mutex_locked) + ipc_mutex_unlock (mqinfo->mqi_lock); + return ret; } extern "C" int @@ -902,85 +919,84 @@ _mq_receive (mqd_t mqd, char *ptr, size_t maxlen, unsigned int *priop, int n; long index; int8_t *mptr; - ssize_t len; + ssize_t len = -1; struct mq_hdr *mqhdr; struct mq_fattr *attr; struct msg_hdr *msghdr; - struct mq_info *mqinfo; + struct mq_info *mqinfo = (struct mq_info *) mqd; + bool ipc_mutex_locked = false; pthread_testcancel (); - myfault efault; - if (efault.faulted (EBADF)) - return -1; - - mqinfo = (struct mq_info *) mqd; - if (mqinfo->mqi_magic != MQI_MAGIC) + __try { - set_errno (EBADF); - return -1; - } - mqhdr = mqinfo->mqi_hdr; /* struct pointer */ - mptr = (int8_t *) mqhdr; /* byte pointer */ - attr = &mqhdr->mqh_attr; - if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) - { - errno = n; - return -1; - } - - if (maxlen < (size_t) attr->mq_msgsize) - { - set_errno (EMSGSIZE); - goto err; - } - if (attr->mq_curmsgs == 0) /* queue is empty */ - { - if (mqinfo->mqi_flags & O_NONBLOCK) + if (mqinfo->mqi_magic != MQI_MAGIC) { - set_errno (EAGAIN); - goto err; + set_errno (EBADF); + __leave; } - /* Wait for a message to be placed onto queue */ - mqhdr->mqh_nwait++; - while (attr->mq_curmsgs == 0) + mqhdr = mqinfo->mqi_hdr; /* struct pointer */ + mptr = (int8_t *) mqhdr; /* byte pointer */ + attr = &mqhdr->mqh_attr; + if ((n = ipc_mutex_lock (mqinfo->mqi_lock)) != 0) { - int ret = ipc_cond_timedwait (mqinfo->mqi_waitrecv, mqinfo->mqi_lock, - abstime); - if (ret != 0) + errno = n; + __leave; + } + ipc_mutex_locked = true; + if (maxlen < (size_t) attr->mq_msgsize) + { + set_errno (EMSGSIZE); + __leave; + } + if (attr->mq_curmsgs == 0) /* queue is empty */ + { + if (mqinfo->mqi_flags & O_NONBLOCK) { - set_errno (ret); - return -1; + set_errno (EAGAIN); + __leave; } + /* Wait for a message to be placed onto queue */ + mqhdr->mqh_nwait++; + while (attr->mq_curmsgs == 0) + { + int ret = ipc_cond_timedwait (mqinfo->mqi_waitrecv, + mqinfo->mqi_lock, abstime); + if (ret != 0) + { + set_errno (ret); + __leave; + } + } + mqhdr->mqh_nwait--; } - mqhdr->mqh_nwait--; + + if ((index = mqhdr->mqh_head) == 0) + api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr->mq_curmsgs); + + msghdr = (struct msg_hdr *) &mptr[index]; + mqhdr->mqh_head = msghdr->msg_next; /* new head of list */ + len = msghdr->msg_len; + memcpy(ptr, msghdr + 1, len); /* copy the message itself */ + if (priop != NULL) + *priop = msghdr->msg_prio; + + /* Just-read message goes to front of free list */ + msghdr->msg_next = mqhdr->mqh_free; + mqhdr->mqh_free = index; + + /* Wake up anyone blocked in mq_send waiting for room */ + if (attr->mq_curmsgs == attr->mq_maxmsg) + ipc_cond_signal (mqinfo->mqi_waitsend); + attr->mq_curmsgs--; + + ipc_mutex_unlock (mqinfo->mqi_lock); } - - if ((index = mqhdr->mqh_head) == 0) - api_fatal ("mq_receive: curmsgs = %ld; head = 0", attr->mq_curmsgs); - - msghdr = (struct msg_hdr *) &mptr[index]; - mqhdr->mqh_head = msghdr->msg_next; /* new head of list */ - len = msghdr->msg_len; - memcpy(ptr, msghdr + 1, len); /* copy the message itself */ - if (priop != NULL) - *priop = msghdr->msg_prio; - - /* Just-read message goes to front of free list */ - msghdr->msg_next = mqhdr->mqh_free; - mqhdr->mqh_free = index; - - /* Wake up anyone blocked in mq_send waiting for room */ - if (attr->mq_curmsgs == attr->mq_maxmsg) - ipc_cond_signal (mqinfo->mqi_waitsend); - attr->mq_curmsgs--; - - ipc_mutex_unlock (mqinfo->mqi_lock); + __except (EBADF) {} + __endtry + if (ipc_mutex_locked) + ipc_mutex_unlock (mqinfo->mqi_lock); return len; - -err: - ipc_mutex_unlock (mqinfo->mqi_lock); - return -1; } extern "C" ssize_t @@ -1004,34 +1020,36 @@ mq_close (mqd_t mqd) struct mq_fattr *attr; struct mq_info *mqinfo; - myfault efault; - if (efault.faulted (EBADF)) - return -1; - - mqinfo = (struct mq_info *) mqd; - if (mqinfo->mqi_magic != MQI_MAGIC) + __try { - set_errno (EBADF); - return -1; + mqinfo = (struct mq_info *) mqd; + if (mqinfo->mqi_magic != MQI_MAGIC) + { + set_errno (EBADF); + __leave; + } + mqhdr = mqinfo->mqi_hdr; + attr = &mqhdr->mqh_attr; + + if (mq_notify (mqd, NULL)) /* unregister calling process */ + __leave; + + msgsize = MSGSIZE (attr->mq_msgsize); + filesize = sizeof (struct mq_hdr) + + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize)); + if (munmap (mqinfo->mqi_hdr, filesize) == -1) + __leave; + + mqinfo->mqi_magic = 0; /* just in case */ + ipc_cond_close (mqinfo->mqi_waitsend); + ipc_cond_close (mqinfo->mqi_waitrecv); + ipc_mutex_close (mqinfo->mqi_lock); + free (mqinfo); + return 0; } - mqhdr = mqinfo->mqi_hdr; - attr = &mqhdr->mqh_attr; - - if (mq_notify (mqd, NULL)) /* unregister calling process */ - return -1; - - msgsize = MSGSIZE (attr->mq_msgsize); - filesize = sizeof (struct mq_hdr) - + (attr->mq_maxmsg * (sizeof (struct msg_hdr) + msgsize)); - if (munmap (mqinfo->mqi_hdr, filesize) == -1) - return -1; - - mqinfo->mqi_magic = 0; /* just in case */ - ipc_cond_close (mqinfo->mqi_waitsend); - ipc_cond_close (mqinfo->mqi_waitrecv); - ipc_mutex_close (mqinfo->mqi_lock); - free (mqinfo); - return 0; + __except (EBADF) {} + __endtry + return -1; } extern "C" int @@ -1062,7 +1080,7 @@ struct sem_finfo extern "C" sem_t * sem_open (const char *name, int oflag, ...) { - int i, fd = -1, created; + int i, fd = -1, created = 0; va_list ap; mode_t mode = 0; unsigned int value = 0; @@ -1078,97 +1096,99 @@ sem_open (const char *name, int oflag, ...) if (!check_path (semname, semaphore, name, len)) return SEM_FAILED; - myfault efault; - if (efault.faulted (EFAULT)) - return SEM_FAILED; - - created = 0; - oflag &= (O_CREAT | O_EXCL); - -again: - if (oflag & O_CREAT) + __try { - va_start (ap, oflag); /* init ap to final named argument */ - mode = va_arg (ap, mode_t) & ~S_IXUSR; - value = va_arg (ap, unsigned int); - va_end (ap); + oflag &= (O_CREAT | O_EXCL); - /* Open and specify O_EXCL and user-execute */ - fd = open (semname, oflag | O_EXCL | O_RDWR | O_CLOEXEC, mode | S_IXUSR); - if (fd < 0) + again: + if (oflag & O_CREAT) { - if (errno == EEXIST && (oflag & O_EXCL) == 0) - goto exists; /* already exists, OK */ - return SEM_FAILED; - } - created = 1; - /* First one to create the file initializes it. */ - NtAllocateLocallyUniqueId (&sf.luid); - sf.value = value; - sf.hash = hash_path_name (0, semname); - if (write (fd, &sf, sizeof sf) != sizeof sf) - goto err; - sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, value, wasopen); - if (sem == SEM_FAILED) - goto err; - /* Initialization complete, turn off user-execute bit */ - if (fchmod (fd, mode) == -1) - goto err; - /* Don't close (fd); */ - return sem; - } + va_start (ap, oflag); /* init ap to final named argument */ + mode = va_arg (ap, mode_t) & ~S_IXUSR; + value = va_arg (ap, unsigned int); + va_end (ap); -exists: - /* Open the file and fetch the semaphore name. */ - if ((fd = open (semname, O_RDWR | O_CLOEXEC)) < 0) - { - if (errno == ENOENT && (oflag & O_CREAT)) - goto again; - goto err; - } - /* Make certain initialization is complete */ - for (i = 0; i < MAX_TRIES; i++) - { - if (stat64 (semname, &statbuff) == -1) + /* Open and specify O_EXCL and user-execute */ + fd = open (semname, oflag | O_EXCL | O_RDWR | O_CLOEXEC, + mode | S_IXUSR); + if (fd < 0) + { + if (errno == EEXIST && (oflag & O_EXCL) == 0) + goto exists; /* already exists, OK */ + return SEM_FAILED; + } + created = 1; + /* First one to create the file initializes it. */ + NtAllocateLocallyUniqueId (&sf.luid); + sf.value = value; + sf.hash = hash_path_name (0, semname); + if (write (fd, &sf, sizeof sf) != sizeof sf) + __leave; + sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, value, + wasopen); + if (sem == SEM_FAILED) + __leave; + /* Initialization complete, turn off user-execute bit */ + if (fchmod (fd, mode) == -1) + __leave; + /* Don't close (fd); */ + return sem; + } + + exists: + /* Open the file and fetch the semaphore name. */ + if ((fd = open (semname, O_RDWR | O_CLOEXEC)) < 0) { if (errno == ENOENT && (oflag & O_CREAT)) - { - close (fd); - fd = -1; - goto again; - } - goto err; + goto again; + __leave; } - if ((statbuff.st_mode & S_IXUSR) == 0) - break; - sleep (1); + /* Make certain initialization is complete */ + for (i = 0; i < MAX_TRIES; i++) + { + if (stat64 (semname, &statbuff) == -1) + { + if (errno == ENOENT && (oflag & O_CREAT)) + { + close (fd); + fd = -1; + goto again; + } + __leave; + } + if ((statbuff.st_mode & S_IXUSR) == 0) + break; + sleep (1); + } + if (i == MAX_TRIES) + { + set_errno (ETIMEDOUT); + __leave; + } + if (file.lock (fd, sizeof sf)) + __leave; + if (read (fd, &sf, sizeof sf) != sizeof sf) + __leave; + sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, sf.value, + wasopen); + file.unlock (fd); + if (sem == SEM_FAILED) + __leave; + /* If wasopen is set, the semaphore was already opened and we already have + an open file descriptor pointing to the file. This means, we have to + close the file descriptor created in this call. It won't be stored + anywhere anyway. */ + if (wasopen) + close (fd); + return sem; } - if (i == MAX_TRIES) - { - set_errno (ETIMEDOUT); - goto err; - } - if (file.lock (fd, sizeof sf)) - goto err; - if (read (fd, &sf, sizeof sf) != sizeof sf) - goto err; - sem = semaphore::open (sf.hash, sf.luid, fd, oflag, mode, sf.value, wasopen); - file.unlock (fd); - if (sem == SEM_FAILED) - goto err; - /* If wasopen is set, the semaphore was already opened and we already have - an open file descriptor pointing to the file. This means, we have to - close the file descriptor created in this call. It won't be stored - anywhere anyway. */ - if (wasopen) - close (fd); - return sem; - -err: + __except (EFAULT) {} + __endtry /* Don't let following function calls change errno */ save_errno save; - file.unlock (fd); + if (fd >= 0) + file.unlock (fd); if (created) unlink (semname); if (sem != SEM_FAILED) diff --git a/winsup/cygwin/resource.cc b/winsup/cygwin/resource.cc index 25e87e6e0..27ba4d4be 100644 --- a/winsup/cygwin/resource.cc +++ b/winsup/cygwin/resource.cc @@ -1,7 +1,7 @@ /* resource.cc: getrusage () and friends. Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2008, 2009, 2010, - 2011, 2012, 2013 Red Hat, Inc. + 2011, 2012, 2013, 2014 Red Hat, Inc. Written by Steve Chamberlain (sac@cygnus.com), Doug Evans (dje@cygnus.com), Geoffrey Noer (noer@cygnus.com) of Cygnus Support. @@ -116,53 +116,51 @@ getrlimit (int resource, struct rlimit *rlp) { MEMORY_BASIC_INFORMATION m; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - rlp->rlim_cur = RLIM_INFINITY; - rlp->rlim_max = RLIM_INFINITY; - - switch (resource) + __try { - case RLIMIT_CPU: - case RLIMIT_FSIZE: - case RLIMIT_DATA: - case RLIMIT_AS: - break; - case RLIMIT_STACK: - if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m)) - debug_printf ("couldn't get stack info, returning def.values. %E"); - else + rlp->rlim_cur = RLIM_INFINITY; + rlp->rlim_max = RLIM_INFINITY; + + switch (resource) { - rlp->rlim_cur = (rlim_t) &m - (rlim_t) m.AllocationBase; - rlp->rlim_max = (rlim_t) m.BaseAddress + m.RegionSize - - (rlim_t) m.AllocationBase; + case RLIMIT_CPU: + case RLIMIT_FSIZE: + case RLIMIT_DATA: + case RLIMIT_AS: + break; + case RLIMIT_STACK: + if (!VirtualQuery ((LPCVOID) &m, &m, sizeof m)) + debug_printf ("couldn't get stack info, returning def.values. %E"); + else + { + rlp->rlim_cur = (rlim_t) &m - (rlim_t) m.AllocationBase; + rlp->rlim_max = (rlim_t) m.BaseAddress + m.RegionSize + - (rlim_t) m.AllocationBase; + } + break; + case RLIMIT_NOFILE: + rlp->rlim_cur = getdtablesize (); + if (rlp->rlim_cur < OPEN_MAX) + rlp->rlim_cur = OPEN_MAX; + rlp->rlim_max = OPEN_MAX_MAX; + break; + case RLIMIT_CORE: + rlp->rlim_cur = cygheap->rlim_core; + break; + default: + set_errno (EINVAL); + __leave; } - break; - case RLIMIT_NOFILE: - rlp->rlim_cur = getdtablesize (); - if (rlp->rlim_cur < OPEN_MAX) - rlp->rlim_cur = OPEN_MAX; - rlp->rlim_max = OPEN_MAX_MAX; - break; - case RLIMIT_CORE: - rlp->rlim_cur = cygheap->rlim_core; - break; - default: - set_errno (EINVAL); - return -1; + return 0; } - return 0; + __except (EFAULT) {} + __endtry + return -1; } extern "C" int setrlimit (int resource, const struct rlimit *rlp) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - struct rlimit oldlimits; /* Check if the request is to actually change the resource settings. @@ -170,29 +168,35 @@ setrlimit (int resource, const struct rlimit *rlp) if (getrlimit (resource, &oldlimits) < 0) return -1; - if (oldlimits.rlim_cur == rlp->rlim_cur && - oldlimits.rlim_max == rlp->rlim_max) - /* No change in resource requirements, succeed immediately */ - return 0; - - if (rlp->rlim_cur > rlp->rlim_max) + __try { - set_errno (EINVAL); - return -1; - } + if (oldlimits.rlim_cur == rlp->rlim_cur && + oldlimits.rlim_max == rlp->rlim_max) + /* No change in resource requirements, succeed immediately */ + return 0; - switch (resource) - { - case RLIMIT_CORE: - cygheap->rlim_core = rlp->rlim_cur; - break; - case RLIMIT_NOFILE: - if (rlp->rlim_cur != RLIM_INFINITY) - return setdtablesize (rlp->rlim_cur); - break; - default: - set_errno (EINVAL); - return -1; + if (rlp->rlim_cur > rlp->rlim_max) + { + set_errno (EINVAL); + __leave; + } + + switch (resource) + { + case RLIMIT_CORE: + cygheap->rlim_core = rlp->rlim_cur; + break; + case RLIMIT_NOFILE: + if (rlp->rlim_cur != RLIM_INFINITY) + return setdtablesize (rlp->rlim_cur); + break; + default: + set_errno (EINVAL); + __leave; + } + return 0; } - return 0; + __except (EFAULT) + __endtry + return -1; } diff --git a/winsup/cygwin/select.cc b/winsup/cygwin/select.cc index e83d9a024..6a396852a 100644 --- a/winsup/cygwin/select.cc +++ b/winsup/cygwin/select.cc @@ -1,7 +1,7 @@ /* select.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc. + 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -230,21 +230,24 @@ pselect(int maxfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval tv; sigset_t oldset = _my_tls.sigmask; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (ts) + __try { - tv.tv_sec = ts->tv_sec; - tv.tv_usec = ts->tv_nsec / 1000; + if (ts) + { + tv.tv_sec = ts->tv_sec; + tv.tv_usec = ts->tv_nsec / 1000; + } + if (set) + set_signal_mask (_my_tls.sigmask, *set); + int ret = cygwin_select (maxfds, readfds, writefds, exceptfds, + ts ? &tv : NULL); + if (set) + set_signal_mask (_my_tls.sigmask, oldset); + return ret; } - if (set) - set_signal_mask (_my_tls.sigmask, *set); - int ret = cygwin_select (maxfds, readfds, writefds, exceptfds, - ts ? &tv : NULL); - if (set) - set_signal_mask (_my_tls.sigmask, oldset); - return ret; + __except (EFAULT) {} + __endtry + return -1; } /* Call cleanup functions for all inspected fds. Gets rid of any diff --git a/winsup/cygwin/sem.cc b/winsup/cygwin/sem.cc index 2c172990a..f7a5db674 100644 --- a/winsup/cygwin/sem.cc +++ b/winsup/cygwin/sem.cc @@ -1,6 +1,6 @@ /* sem.cc: XSI IPC interface for Cygwin. - Copyright 2002, 2003, 2004, 2005, 2008, 2009, 2012 Red Hat, Inc. + Copyright 2002, 2003, 2004, 2005, 2008, 2009, 2012, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -85,19 +85,22 @@ semctl (int semid, int semnum, int cmd, ...) } syscall_printf ("semctl (semid = %d, semnum = %d, cmd = %d, arg = %p)", semid, semnum, cmd, arg.buf); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - client_request_sem request (semid, semnum, cmd, &arg); - if (request.make_request () == -1 || request.retval () == -1) + __try { - syscall_printf ("-1 [%d] = semctl ()", request.error_code ()); - set_errno (request.error_code ()); - if (request.error_code () == ENOSYS) - raise (SIGSYS); - return -1; + client_request_sem request (semid, semnum, cmd, &arg); + if (request.make_request () == -1 || request.retval () == -1) + { + syscall_printf ("-1 [%d] = semctl ()", request.error_code ()); + set_errno (request.error_code ()); + if (request.error_code () == ENOSYS) + raise (SIGSYS); + __leave; + } + return request.retval (); } - return request.retval (); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -122,17 +125,20 @@ semop (int semid, struct sembuf *sops, size_t nsops) { syscall_printf ("semop (semid = %d, sops = %p, nsops = %ld)", semid, sops, nsops); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - client_request_sem request (semid, sops, nsops); - if (request.make_request () == -1 || request.retval () == -1) + __try { - syscall_printf ("-1 [%d] = semop ()", request.error_code ()); - set_errno (request.error_code ()); - if (request.error_code () == ENOSYS) - raise (SIGSYS); - return -1; + client_request_sem request (semid, sops, nsops); + if (request.make_request () == -1 || request.retval () == -1) + { + syscall_printf ("-1 [%d] = semop ()", request.error_code ()); + set_errno (request.error_code ()); + if (request.error_code () == ENOSYS) + raise (SIGSYS); + __leave; + } + return request.retval (); } - return request.retval (); + __except (EFAULT) {} + __endtry + return -1; } diff --git a/winsup/cygwin/shm.cc b/winsup/cygwin/shm.cc index 03213781a..868545e3b 100644 --- a/winsup/cygwin/shm.cc +++ b/winsup/cygwin/shm.cc @@ -260,41 +260,45 @@ shmctl (int shmid, int cmd, struct shmid_ds *buf) { syscall_printf ("shmctl (shmid = %d, cmd = %d, buf = %p)", shmid, cmd, buf); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - client_request_shm request (shmid, cmd, buf); - if (request.make_request () == -1 || request.retval () == -1) + __try { - syscall_printf ("-1 [%d] = shmctl ()", request.error_code ()); - set_errno (request.error_code ()); - if (request.error_code () == ENOSYS) - raise (SIGSYS); - return -1; - } - if (cmd == IPC_RMID) - { - /* Cleanup */ - shm_shmid_list *ssh_entry, *ssh_next_entry; - SLIST_LOCK (); - SLIST_FOREACH_SAFE (ssh_entry, &ssh_list, ssh_next, ssh_next_entry) + client_request_shm request (shmid, cmd, buf); + if (request.make_request () == -1 || request.retval () == -1) { - if (ssh_entry->shmid == shmid) - { - /* Remove this entry from the list and close the handle - only if it's not in use anymore. */ - if (ssh_entry->ref_count <= 0) - { - SLIST_REMOVE (&ssh_list, ssh_entry, shm_shmid_list, ssh_next); - CloseHandle (ssh_entry->hdl); - delete ssh_entry; - } - break; - } + syscall_printf ("-1 [%d] = shmctl ()", request.error_code ()); + set_errno (request.error_code ()); + if (request.error_code () == ENOSYS) + raise (SIGSYS); + __leave; } - SLIST_UNLOCK (); + if (cmd == IPC_RMID) + { + /* Cleanup */ + shm_shmid_list *ssh_entry, *ssh_next_entry; + SLIST_LOCK (); + SLIST_FOREACH_SAFE (ssh_entry, &ssh_list, ssh_next, ssh_next_entry) + { + if (ssh_entry->shmid == shmid) + { + /* Remove this entry from the list and close the handle + only if it's not in use anymore. */ + if (ssh_entry->ref_count <= 0) + { + SLIST_REMOVE (&ssh_list, ssh_entry, shm_shmid_list, + ssh_next); + CloseHandle (ssh_entry->hdl); + delete ssh_entry; + } + break; + } + } + SLIST_UNLOCK (); + } + return request.retval (); } - return request.retval (); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index 3ea8af502..d2ca81e00 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -1,7 +1,7 @@ /* signal.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc. + 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com Significant changes by Sergey Okhapkin @@ -197,33 +197,37 @@ handle_sigprocmask (int how, const sigset_t *set, sigset_t *oldset, sigset_t& op return EINVAL; } - myfault efault; - if (efault.faulted (EFAULT)) - return EFAULT; - - if (oldset) - *oldset = opmask; - - if (set) - { - sigset_t newmask = opmask; - switch (how) + __try { - case SIG_BLOCK: - /* add set to current mask */ - newmask |= *set; - break; - case SIG_UNBLOCK: - /* remove set from current mask */ - newmask &= ~*set; - break; - case SIG_SETMASK: - /* just set it */ - newmask = *set; - break; + if (oldset) + *oldset = opmask; + + if (set) + { + sigset_t newmask = opmask; + switch (how) + { + case SIG_BLOCK: + /* add set to current mask */ + newmask |= *set; + break; + case SIG_UNBLOCK: + /* remove set from current mask */ + newmask &= ~*set; + break; + case SIG_SETMASK: + /* just set it */ + newmask = *set; + break; + } + set_signal_mask (opmask, newmask); } - set_signal_mask (opmask, newmask); } + __except (EFAULT) + { + return EFAULT; + } + __endtry return 0; } @@ -382,8 +386,7 @@ sigaction_worker (int sig, const struct sigaction *newact, struct sigaction *oldact, bool isinternal) { int res = -1; - myfault efault; - if (!efault.faulted (EFAULT)) + __try { sig_dispatch_pending (); /* check that sig is in right range */ @@ -394,14 +397,17 @@ sigaction_worker (int sig, const struct sigaction *newact, struct sigaction oa = global_sigs[sig]; if (!newact) - sigproc_printf ("signal %d, newact %p, oa %p", sig, newact, oa, oa.sa_handler); + sigproc_printf ("signal %d, newact %p, oa %p", + sig, newact, oa, oa.sa_handler); else { - sigproc_printf ("signal %d, newact %p (handler %p), oa %p", sig, newact, newact->sa_handler, oa, oa.sa_handler); + sigproc_printf ("signal %d, newact %p (handler %p), oa %p", + sig, newact, newact->sa_handler, oa, + oa.sa_handler); if (sig == SIGKILL || sig == SIGSTOP) { set_errno (EINVAL); - goto out; + __leave; } struct sigaction na = *newact; struct sigaction& gs = global_sigs[sig]; @@ -430,8 +436,8 @@ sigaction_worker (int sig, const struct sigaction *newact, res = 0; } } - -out: + __except (EFAULT) {} + __endtry return res; } @@ -560,41 +566,41 @@ sigwait (const sigset_t *set, int *sig_ptr) extern "C" int sigwaitinfo (const sigset_t *set, siginfo_t *info) { + int res = -1; + pthread_testcancel (); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - set_signal_mask (_my_tls.sigwait_mask, *set); - sig_dispatch_pending (true); - - int res; - switch (cygwait (NULL, cw_infinite, cw_sig_eintr | cw_cancel | cw_cancel_self)) + __try { - case WAIT_SIGNALED: - if (!sigismember (set, _my_tls.infodata.si_signo)) - { - set_errno (EINTR); - res = -1; - } - else - { - _my_tls.lock (); - if (info) - *info = _my_tls.infodata; - res = _my_tls.infodata.si_signo; - _my_tls.sig = 0; - if (_my_tls.retaddr () == (__stack_t) sigdelayed) - _my_tls.pop (); - _my_tls.unlock (); - } - break; - default: - __seterrno (); - res = -1; - } + set_signal_mask (_my_tls.sigwait_mask, *set); + sig_dispatch_pending (true); + switch (cygwait (NULL, cw_infinite, cw_sig_eintr | cw_cancel | cw_cancel_self)) + { + case WAIT_SIGNALED: + if (!sigismember (set, _my_tls.infodata.si_signo)) + set_errno (EINTR); + else + { + _my_tls.lock (); + if (info) + *info = _my_tls.infodata; + res = _my_tls.infodata.si_signo; + _my_tls.sig = 0; + if (_my_tls.retaddr () == (__stack_t) sigdelayed) + _my_tls.pop (); + _my_tls.unlock (); + } + break; + default: + __seterrno (); + break; + } + } + __except (EFAULT) { + res = -1; + } + __endtry sigproc_printf ("returning signal %d", res); return res; } diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index d1b1fbad6..56f36a3e6 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -1,7 +1,7 @@ /* spawn.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc. + 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -330,552 +330,552 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv, STARTUPINFOW si = {}; int looped = 0; - myfault efault; system_call_handle system_call (mode == _P_SYSTEM); - if (efault.faulted ()) + + __try + { + child_info_types chtype; + if (mode == _P_OVERLAY) + chtype = _CH_EXEC; + else + chtype = _CH_SPAWN; + + moreinfo = cygheap_exec_info::alloc (); + + /* CreateProcess takes one long string that is the command line (sigh). + We need to quote any argument that has whitespace or embedded "'s. */ + + int ac; + for (ac = 0; argv[ac]; ac++) + /* nothing */; + + int err; + const char *ext; + if ((ext = perhaps_suffix (prog_arg, real_path, err, FE_NADA)) == NULL) + { + set_errno (err); + res = -1; + __leave; + } + + res = newargv.setup (prog_arg, real_path, ext, ac, argv, p_type_exec); + + if (res) + __leave; + + if (!real_path.iscygexec () && ::cygheap->cwd.get_error ()) + { + small_printf ("Error: Current working directory %s.\n" + "Can't start native Windows application from here.\n\n", + ::cygheap->cwd.get_error_desc ()); + set_errno (::cygheap->cwd.get_error ()); + res = -1; + __leave; + } + + if (ac == 3 && argv[1][0] == '/' && tolower (argv[1][1]) == 'c' && + (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe"))) + { + real_path.check (prog_arg); + cmd.add ("\""); + if (!real_path.error) + cmd.add (real_path.get_win32 ()); + else + cmd.add (argv[0]); + cmd.add ("\""); + cmd.add (" "); + cmd.add (argv[1]); + cmd.add (" "); + cmd.add (argv[2]); + real_path.set_path (argv[0]); + null_app_name = true; + } + else + { + if (real_path.iscygexec ()) + { + moreinfo->argc = newargv.argc; + moreinfo->argv = newargv; + } + if ((wincmdln || !real_path.iscygexec ()) + && !cmd.fromargv (newargv, real_path.get_win32 (), + real_path.iscygexec ())) + { + res = -1; + __leave; + } + + + if (mode != _P_OVERLAY || !real_path.iscygexec () + || !DuplicateHandle (GetCurrentProcess (), myself.shared_handle (), + GetCurrentProcess (), &moreinfo->myself_pinfo, + 0, TRUE, DUPLICATE_SAME_ACCESS)) + moreinfo->myself_pinfo = NULL; + else + VerifyHandle (moreinfo->myself_pinfo); + } + + PROCESS_INFORMATION pi; + pi.hProcess = pi.hThread = NULL; + pi.dwProcessId = pi.dwThreadId = 0; + + /* Set up needed handles for stdio */ + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false); + si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true); + si.hStdError = handle (2, true); + + si.cb = sizeof (si); + + c_flags = GetPriorityClass (GetCurrentProcess ()); + sigproc_printf ("priority class %d", c_flags); + + c_flags |= CREATE_SEPARATE_WOW_VDM | CREATE_UNICODE_ENVIRONMENT; + + if (wincap.has_program_compatibility_assistant ()) + { + /* We're adding the CREATE_BREAKAWAY_FROM_JOB flag here to workaround + issues with the "Program Compatibility Assistant (PCA) Service" + starting with Windows Vista. For some reason, when starting long + running sessions from mintty(*), the affected svchost.exe process + takes more and more memory and at one point takes over the CPU. At + this point the machine becomes unresponsive. The only way to get + back to normal is to stop the entire mintty session, or to stop the + PCA service. However, a process which is controlled by PCA is part + of a compatibility job, which allows child processes to break away + from the job. This helps to avoid this issue. + + First we call IsProcessInJob. It fetches the information whether or + not we're part of a job 20 times faster than QueryInformationJobObject. + + (*) Note that this is not mintty's fault. It has just been observed + with mintty in the first place. See the archives for more info: + http://cygwin.com/ml/cygwin-developers/2012-02/msg00018.html */ + + JOBOBJECT_BASIC_LIMIT_INFORMATION jobinfo; + BOOL is_in_job; + + if (IsProcessInJob (GetCurrentProcess (), NULL, &is_in_job) + && is_in_job + && QueryInformationJobObject (NULL, JobObjectBasicLimitInformation, + &jobinfo, sizeof jobinfo, NULL) + && (jobinfo.LimitFlags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK + | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))) + { + debug_printf ("Add CREATE_BREAKAWAY_FROM_JOB"); + c_flags |= CREATE_BREAKAWAY_FROM_JOB; + } + } + + if (mode == _P_DETACH) + c_flags |= DETACHED_PROCESS; + else + fhandler_console::need_invisible (); + + if (mode != _P_OVERLAY) + myself->exec_sendsig = NULL; + else + { + /* Reset sendsig so that any process which wants to send a signal + to this pid will wait for the new process to become active. + Save the old value in case the exec fails. */ + if (!myself->exec_sendsig) + { + myself->exec_sendsig = myself->sendsig; + myself->exec_dwProcessId = myself->dwProcessId; + myself->sendsig = NULL; + reset_sendsig = true; + } + } + + if (null_app_name) + runpath = NULL; + else + { + USHORT len = real_path.get_nt_native_path ()->Length / sizeof (WCHAR); + if (RtlEqualUnicodePathPrefix (real_path.get_nt_native_path (), + &ro_u_natp, FALSE)) + { + runpath = real_path.get_wide_win32_path (runpath); + /* If the executable path length is < MAX_PATH, make sure the long + path win32 prefix is removed from the path to make subsequent + not long path aware native Win32 child processes happy. */ + if (len < MAX_PATH + 4) + { + if (runpath[5] == ':') + runpath += 4; + else if (len < MAX_PATH + 6) + *(runpath += 6) = L'\\'; + } + } + else if (len < NT_MAX_PATH - ro_u_globalroot.Length / sizeof (WCHAR)) + { + UNICODE_STRING rpath; + + RtlInitEmptyUnicodeString (&rpath, runpath, + (NT_MAX_PATH - 1) * sizeof (WCHAR)); + RtlCopyUnicodeString (&rpath, &ro_u_globalroot); + RtlAppendUnicodeStringToString (&rpath, + real_path.get_nt_native_path ()); + } + else + { + set_errno (ENAMETOOLONG); + res = -1; + __leave; + } + } + + cygbench ("spawn-worker"); + + if (!real_path.iscygexec()) + ::cygheap->fdtab.set_file_pointers_for_exec (); + + moreinfo->envp = build_env (envp, envblock, moreinfo->envc, + real_path.iscygexec ()); + if (!moreinfo->envp || !envblock) + { + set_errno (E2BIG); + res = -1; + __leave; + } + set (chtype, real_path.iscygexec ()); + __stdin = in__stdin; + __stdout = in__stdout; + record_children (); + + si.lpReserved2 = (LPBYTE) this; + si.cbReserved2 = sizeof (*this); + + /* Depends on set call above. + Some file types might need extra effort in the parent after CreateProcess + and before copying the datastructures to the child. So we have to start + the child in suspend state, unfortunately, to avoid a race condition. */ + if (!newargv.win16_exe + && (!iscygwin () || mode != _P_OVERLAY + || ::cygheap->fdtab.need_fixup_before ())) + c_flags |= CREATE_SUSPENDED; + /* If a native application should be spawned, we test here if the spawning + process is running in a console and, if so, if it's a foreground or + background process. If it's a background process, we start the native + process with the CREATE_NEW_PROCESS_GROUP flag set. This lets the native + process ignore Ctrl-C by default. If we don't do that, pressing Ctrl-C + in a console will break native processes running in the background, + because the Ctrl-C event is sent to all processes in the console, unless + they ignore it explicitely. CREATE_NEW_PROCESS_GROUP does that for us. */ + if (!iscygwin () && fhandler_console::exists () + && fhandler_console::tc_getpgid () != myself->pgid) + c_flags |= CREATE_NEW_PROCESS_GROUP; + refresh_cygheap (); + + if (mode == _P_DETACH) + /* all set */; + else if (mode != _P_OVERLAY || !my_wr_proc_pipe) + prefork (); + else + wr_proc_pipe = my_wr_proc_pipe; + + /* Don't allow child to inherit these handles if it's not a Cygwin program. + wr_proc_pipe will be injected later. parent won't be used by the child + so there is no reason for the child to have it open as it can confuse + ps into thinking that children of windows processes are all part of + the same "execed" process. + FIXME: Someday, make it so that parent is never created when starting + non-Cygwin processes. */ + if (!iscygwin ()) + { + SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, 0); + SetHandleInformation (parent, HANDLE_FLAG_INHERIT, 0); + } + /* FIXME: racy */ + if (mode != _P_OVERLAY) + SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT, 0); + parent_winpid = GetCurrentProcessId (); + + loop: + /* When ruid != euid we create the new process under the current original + account and impersonate in child, this way maintaining the different + effective vs. real ids. + FIXME: If ruid != euid and ruid != saved_uid we currently give + up on ruid. The new process will have ruid == euid. */ + ::cygheap->user.deimpersonate (); + + if (!real_path.iscygexec () && mode == _P_OVERLAY) + myself->process_state |= PID_NOTCYGWIN; + + wchar_t wcmd[(size_t) cmd]; + if (!::cygheap->user.issetuid () + || (::cygheap->user.saved_uid == ::cygheap->user.real_uid + && ::cygheap->user.saved_gid == ::cygheap->user.real_gid + && !::cygheap->user.groups.issetgroups () + && !::cygheap->user.setuid_to_restricted)) + { + rc = CreateProcessW (runpath, /* image name - with full path */ + cmd.wcs (wcmd),/* what was passed to exec */ + &sec_none_nih, /* process security attrs */ + &sec_none_nih, /* thread security attrs */ + TRUE, /* inherit handles from parent */ + c_flags, + envblock, /* environment */ + NULL, + &si, + &pi); + } + else + { + /* Give access to myself */ + if (mode == _P_OVERLAY) + myself.set_acl(); + + WCHAR wstname[1024] = { L'\0' }; + HWINSTA hwst_orig = NULL, hwst = NULL; + HDESK hdsk_orig = NULL, hdsk = NULL; + PSECURITY_ATTRIBUTES sa; + DWORD n; + + hwst_orig = GetProcessWindowStation (); + hdsk_orig = GetThreadDesktop (GetCurrentThreadId ()); + GetUserObjectInformationW (hwst_orig, UOI_NAME, wstname, 1024, &n); + /* Prior to Vista it was possible to start a service with the + "Interact with desktop" flag. This started the service in the + interactive window station of the console. A big security + risk, but we don't want to disable this behaviour for older + OSes because it's still heavily used by some users. They have + been warned. */ + if (!::cygheap->user.setuid_to_restricted + && wcscasecmp (wstname, L"WinSta0") != 0) + { + WCHAR sid[128]; + + sa = sec_user ((PSECURITY_ATTRIBUTES) alloca (1024), + ::cygheap->user.sid ()); + /* We're creating a window station per user, not per logon session. + First of all we might not have a valid logon session for + the user (logon by create_token), and second, it doesn't + make sense in terms of security to create a new window + station for every logon of the same user. It just fills up + the system with window stations for no good reason. */ + hwst = CreateWindowStationW (::cygheap->user.get_windows_id (sid), 0, + GENERIC_READ | GENERIC_WRITE, sa); + if (!hwst) + system_printf ("CreateWindowStation failed, %E"); + else if (!SetProcessWindowStation (hwst)) + system_printf ("SetProcessWindowStation failed, %E"); + else if (!(hdsk = CreateDesktopW (L"Default", NULL, NULL, 0, + GENERIC_ALL, sa))) + system_printf ("CreateDesktop failed, %E"); + else + { + wcpcpy (wcpcpy (wstname, sid), L"\\Default"); + si.lpDesktop = wstname; + debug_printf ("Desktop: %W", si.lpDesktop); + } + } + + rc = CreateProcessAsUserW (::cygheap->user.primary_token (), + runpath, /* image name - with full path */ + cmd.wcs (wcmd),/* what was passed to exec */ + &sec_none_nih, /* process security attrs */ + &sec_none_nih, /* thread security attrs */ + TRUE, /* inherit handles from parent */ + c_flags, + envblock, /* environment */ + NULL, + &si, + &pi); + if (hwst) + { + SetProcessWindowStation (hwst_orig); + CloseWindowStation (hwst); + } + if (hdsk) + { + SetThreadDesktop (hdsk_orig); + CloseDesktop (hdsk); + } + } + + if (mode != _P_OVERLAY) + SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); + + /* Set errno now so that debugging messages from it appear before our + final debugging message [this is a general rule for debugging + messages]. */ + if (!rc) + { + __seterrno (); + syscall_printf ("CreateProcess failed, %E"); + /* If this was a failed exec, restore the saved sendsig. */ + if (reset_sendsig) + { + myself->sendsig = myself->exec_sendsig; + myself->exec_sendsig = NULL; + } + myself->process_state &= ~PID_NOTCYGWIN; + /* Reset handle inheritance to default when the execution of a non-Cygwin + process fails. Only need to do this for _P_OVERLAY since the handle will + be closed otherwise. Don't need to do this for 'parent' since it will + be closed in every case. See FIXME above. */ + if (!iscygwin () && mode == _P_OVERLAY) + SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, + HANDLE_FLAG_INHERIT); + if (wr_proc_pipe == my_wr_proc_pipe) + wr_proc_pipe = NULL; /* We still own it: don't nuke in destructor */ + + /* Restore impersonation. In case of _P_OVERLAY this isn't + allowed since it would overwrite child data. */ + if (mode != _P_OVERLAY) + ::cygheap->user.reimpersonate (); + + res = -1; + __leave; + } + + /* The CREATE_SUSPENDED case is handled below */ + if (iscygwin () && !(c_flags & CREATE_SUSPENDED)) + strace.write_childpid (pi.dwProcessId); + + /* Fixup the parent data structures if needed and resume the child's + main thread. */ + if (::cygheap->fdtab.need_fixup_before ()) + ::cygheap->fdtab.fixup_before_exec (pi.dwProcessId); + + if (mode != _P_OVERLAY) + cygpid = cygwin_pid (pi.dwProcessId); + else + cygpid = myself->pid; + + /* We print the original program name here so the user can see that too. */ + syscall_printf ("pid %d, prog_arg %s, cmd line %.9500s)", + rc ? cygpid : (unsigned int) -1, prog_arg, (const char *) cmd); + + /* Name the handle similarly to proc_subproc. */ + ProtectHandle1 (pi.hProcess, childhProc); + + if (mode == _P_OVERLAY) + { + myself->dwProcessId = pi.dwProcessId; + strace.execing = 1; + myself.hProcess = hExeced = pi.hProcess; + real_path.get_wide_win32_path (myself->progname); // FIXME: race? + sigproc_printf ("new process name %W", myself->progname); + if (!iscygwin ()) + close_all_files (); + } + else + { + myself->set_has_pgid_children (); + ProtectHandle (pi.hThread); + pinfo child (cygpid, + PID_IN_USE | (real_path.iscygexec () ? 0 : PID_NOTCYGWIN)); + if (!child) + { + syscall_printf ("pinfo failed"); + if (get_errno () != ENOMEM) + set_errno (EAGAIN); + res = -1; + __leave; + } + child->dwProcessId = pi.dwProcessId; + child.hProcess = pi.hProcess; + + real_path.get_wide_win32_path (child->progname); + /* FIXME: This introduces an unreferenced, open handle into the child. + The purpose is to keep the pid shared memory open so that all of + the fields filled out by child.remember do not disappear and so there + is not a brief period during which the pid is not available. + However, we should try to find another way to do this eventually. */ + DuplicateHandle (GetCurrentProcess (), child.shared_handle (), + pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS); + child->start_time = time (NULL); /* Register child's starting time. */ + child->nice = myself->nice; + postfork (child); + if (!child.remember (mode == _P_DETACH)) + { + /* FIXME: Child in strange state now */ + CloseHandle (pi.hProcess); + ForceCloseHandle (pi.hThread); + res = -1; + __leave; + } + } + + /* Start the child running */ + if (c_flags & CREATE_SUSPENDED) + { + /* Inject a non-inheritable wr_proc_pipe handle into child so that we + can accurately track when the child exits without keeping this + process waiting around for it to exit. */ + if (!iscygwin ()) + DuplicateHandle (GetCurrentProcess (), wr_proc_pipe, pi.hProcess, NULL, + 0, false, DUPLICATE_SAME_ACCESS); + ResumeThread (pi.hThread); + if (iscygwin ()) + strace.write_childpid (pi.dwProcessId); + } + ForceCloseHandle (pi.hThread); + + sigproc_printf ("spawned windows pid %d", pi.dwProcessId); + + bool synced; + if ((mode == _P_DETACH || mode == _P_NOWAIT) && !iscygwin ()) + synced = false; + else + /* Just mark a non-cygwin process as 'synced'. We will still eventually + wait for it to exit in maybe_set_exit_code_from_windows(). */ + synced = iscygwin () ? sync (pi.dwProcessId, pi.hProcess, INFINITE) : true; + + switch (mode) + { + case _P_OVERLAY: + myself.hProcess = pi.hProcess; + if (!synced) + { + if (!proc_retry (pi.hProcess)) + { + looped++; + goto loop; + } + close_all_files (true); + } + else + { + if (iscygwin ()) + close_all_files (true); + if (!my_wr_proc_pipe + && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT) + wait_for_myself (); + } + myself.exit (EXITCODE_NOSET); + break; + case _P_WAIT: + case _P_SYSTEM: + system_call.arm (); + if (waitpid (cygpid, &res, 0) != cygpid) + res = -1; + break; + case _P_DETACH: + res = 0; /* Lost all memory of this child. */ + break; + case _P_NOWAIT: + case _P_NOWAITO: + case _P_VFORK: + res = cygpid; + break; + default: + break; + } + } + __except (NO_ERROR) { if (get_errno () == ENOMEM) set_errno (E2BIG); else set_errno (EFAULT); res = -1; - goto out; } - - child_info_types chtype; - if (mode == _P_OVERLAY) - chtype = _CH_EXEC; - else - chtype = _CH_SPAWN; - - moreinfo = cygheap_exec_info::alloc (); - - /* CreateProcess takes one long string that is the command line (sigh). - We need to quote any argument that has whitespace or embedded "'s. */ - - int ac; - for (ac = 0; argv[ac]; ac++) - /* nothing */; - - int err; - const char *ext; - if ((ext = perhaps_suffix (prog_arg, real_path, err, FE_NADA)) == NULL) - { - set_errno (err); - res = -1; - goto out; - } - - res = newargv.setup (prog_arg, real_path, ext, ac, argv, p_type_exec); - - if (res) - goto out; - - if (!real_path.iscygexec () && ::cygheap->cwd.get_error ()) - { - small_printf ("Error: Current working directory %s.\n" - "Can't start native Windows application from here.\n\n", - ::cygheap->cwd.get_error_desc ()); - set_errno (::cygheap->cwd.get_error ()); - res = -1; - goto out; - } - - if (ac == 3 && argv[1][0] == '/' && tolower (argv[1][1]) == 'c' && - (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe"))) - { - real_path.check (prog_arg); - cmd.add ("\""); - if (!real_path.error) - cmd.add (real_path.get_win32 ()); - else - cmd.add (argv[0]); - cmd.add ("\""); - cmd.add (" "); - cmd.add (argv[1]); - cmd.add (" "); - cmd.add (argv[2]); - real_path.set_path (argv[0]); - null_app_name = true; - } - else - { - if (real_path.iscygexec ()) - { - moreinfo->argc = newargv.argc; - moreinfo->argv = newargv; - } - if ((wincmdln || !real_path.iscygexec ()) - && !cmd.fromargv (newargv, real_path.get_win32 (), - real_path.iscygexec ())) - { - res = -1; - goto out; - } - - - if (mode != _P_OVERLAY || !real_path.iscygexec () - || !DuplicateHandle (GetCurrentProcess (), myself.shared_handle (), - GetCurrentProcess (), &moreinfo->myself_pinfo, - 0, TRUE, DUPLICATE_SAME_ACCESS)) - moreinfo->myself_pinfo = NULL; - else - VerifyHandle (moreinfo->myself_pinfo); - } - - PROCESS_INFORMATION pi; - pi.hProcess = pi.hThread = NULL; - pi.dwProcessId = pi.dwThreadId = 0; - - /* Set up needed handles for stdio */ - si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false); - si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true); - si.hStdError = handle (2, true); - - si.cb = sizeof (si); - - c_flags = GetPriorityClass (GetCurrentProcess ()); - sigproc_printf ("priority class %d", c_flags); - - c_flags |= CREATE_SEPARATE_WOW_VDM | CREATE_UNICODE_ENVIRONMENT; - - if (wincap.has_program_compatibility_assistant ()) - { - /* We're adding the CREATE_BREAKAWAY_FROM_JOB flag here to workaround - issues with the "Program Compatibility Assistant (PCA) Service" - starting with Windows Vista. For some reason, when starting long - running sessions from mintty(*), the affected svchost.exe process - takes more and more memory and at one point takes over the CPU. At - this point the machine becomes unresponsive. The only way to get - back to normal is to stop the entire mintty session, or to stop the - PCA service. However, a process which is controlled by PCA is part - of a compatibility job, which allows child processes to break away - from the job. This helps to avoid this issue. - - First we call IsProcessInJob. It fetches the information whether or - not we're part of a job 20 times faster than QueryInformationJobObject. - - (*) Note that this is not mintty's fault. It has just been observed - with mintty in the first place. See the archives for more info: - http://cygwin.com/ml/cygwin-developers/2012-02/msg00018.html */ - - JOBOBJECT_BASIC_LIMIT_INFORMATION jobinfo; - BOOL is_in_job; - - if (IsProcessInJob (GetCurrentProcess (), NULL, &is_in_job) - && is_in_job - && QueryInformationJobObject (NULL, JobObjectBasicLimitInformation, - &jobinfo, sizeof jobinfo, NULL) - && (jobinfo.LimitFlags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK - | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))) - { - debug_printf ("Add CREATE_BREAKAWAY_FROM_JOB"); - c_flags |= CREATE_BREAKAWAY_FROM_JOB; - } - } - - if (mode == _P_DETACH) - c_flags |= DETACHED_PROCESS; - else - fhandler_console::need_invisible (); - - if (mode != _P_OVERLAY) - myself->exec_sendsig = NULL; - else - { - /* Reset sendsig so that any process which wants to send a signal - to this pid will wait for the new process to become active. - Save the old value in case the exec fails. */ - if (!myself->exec_sendsig) - { - myself->exec_sendsig = myself->sendsig; - myself->exec_dwProcessId = myself->dwProcessId; - myself->sendsig = NULL; - reset_sendsig = true; - } - } - - if (null_app_name) - runpath = NULL; - else - { - USHORT len = real_path.get_nt_native_path ()->Length / sizeof (WCHAR); - if (RtlEqualUnicodePathPrefix (real_path.get_nt_native_path (), - &ro_u_natp, FALSE)) - { - runpath = real_path.get_wide_win32_path (runpath); - /* If the executable path length is < MAX_PATH, make sure the long - path win32 prefix is removed from the path to make subsequent - not long path aware native Win32 child processes happy. */ - if (len < MAX_PATH + 4) - { - if (runpath[5] == ':') - runpath += 4; - else if (len < MAX_PATH + 6) - *(runpath += 6) = L'\\'; - } - } - else if (len < NT_MAX_PATH - ro_u_globalroot.Length / sizeof (WCHAR)) - { - UNICODE_STRING rpath; - - RtlInitEmptyUnicodeString (&rpath, runpath, - (NT_MAX_PATH - 1) * sizeof (WCHAR)); - RtlCopyUnicodeString (&rpath, &ro_u_globalroot); - RtlAppendUnicodeStringToString (&rpath, - real_path.get_nt_native_path ()); - } - else - { - set_errno (ENAMETOOLONG); - res = -1; - goto out; - } - } - - cygbench ("spawn-worker"); - - if (!real_path.iscygexec()) - ::cygheap->fdtab.set_file_pointers_for_exec (); - - moreinfo->envp = build_env (envp, envblock, moreinfo->envc, - real_path.iscygexec ()); - if (!moreinfo->envp || !envblock) - { - set_errno (E2BIG); - res = -1; - goto out; - } - set (chtype, real_path.iscygexec ()); - __stdin = in__stdin; - __stdout = in__stdout; - record_children (); - - si.lpReserved2 = (LPBYTE) this; - si.cbReserved2 = sizeof (*this); - - /* Depends on set call above. - Some file types might need extra effort in the parent after CreateProcess - and before copying the datastructures to the child. So we have to start - the child in suspend state, unfortunately, to avoid a race condition. */ - if (!newargv.win16_exe - && (!iscygwin () || mode != _P_OVERLAY - || ::cygheap->fdtab.need_fixup_before ())) - c_flags |= CREATE_SUSPENDED; - /* If a native application should be spawned, we test here if the spawning - process is running in a console and, if so, if it's a foreground or - background process. If it's a background process, we start the native - process with the CREATE_NEW_PROCESS_GROUP flag set. This lets the native - process ignore Ctrl-C by default. If we don't do that, pressing Ctrl-C - in a console will break native processes running in the background, - because the Ctrl-C event is sent to all processes in the console, unless - they ignore it explicitely. CREATE_NEW_PROCESS_GROUP does that for us. */ - if (!iscygwin () && fhandler_console::exists () - && fhandler_console::tc_getpgid () != myself->pgid) - c_flags |= CREATE_NEW_PROCESS_GROUP; - refresh_cygheap (); - - if (mode == _P_DETACH) - /* all set */; - else if (mode != _P_OVERLAY || !my_wr_proc_pipe) - prefork (); - else - wr_proc_pipe = my_wr_proc_pipe; - - /* Don't allow child to inherit these handles if it's not a Cygwin program. - wr_proc_pipe will be injected later. parent won't be used by the child - so there is no reason for the child to have it open as it can confuse - ps into thinking that children of windows processes are all part of - the same "execed" process. - FIXME: Someday, make it so that parent is never created when starting - non-Cygwin processes. */ - if (!iscygwin ()) - { - SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, 0); - SetHandleInformation (parent, HANDLE_FLAG_INHERIT, 0); - } - /* FIXME: racy */ - if (mode != _P_OVERLAY) - SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT, 0); - parent_winpid = GetCurrentProcessId (); - -loop: - /* When ruid != euid we create the new process under the current original - account and impersonate in child, this way maintaining the different - effective vs. real ids. - FIXME: If ruid != euid and ruid != saved_uid we currently give - up on ruid. The new process will have ruid == euid. */ - ::cygheap->user.deimpersonate (); - - if (!real_path.iscygexec () && mode == _P_OVERLAY) - myself->process_state |= PID_NOTCYGWIN; - - wchar_t wcmd[(size_t) cmd]; - if (!::cygheap->user.issetuid () - || (::cygheap->user.saved_uid == ::cygheap->user.real_uid - && ::cygheap->user.saved_gid == ::cygheap->user.real_gid - && !::cygheap->user.groups.issetgroups () - && !::cygheap->user.setuid_to_restricted)) - { - rc = CreateProcessW (runpath, /* image name - with full path */ - cmd.wcs (wcmd),/* what was passed to exec */ - &sec_none_nih, /* process security attrs */ - &sec_none_nih, /* thread security attrs */ - TRUE, /* inherit handles from parent */ - c_flags, - envblock, /* environment */ - NULL, - &si, - &pi); - } - else - { - /* Give access to myself */ - if (mode == _P_OVERLAY) - myself.set_acl(); - - WCHAR wstname[1024] = { L'\0' }; - HWINSTA hwst_orig = NULL, hwst = NULL; - HDESK hdsk_orig = NULL, hdsk = NULL; - PSECURITY_ATTRIBUTES sa; - DWORD n; - - hwst_orig = GetProcessWindowStation (); - hdsk_orig = GetThreadDesktop (GetCurrentThreadId ()); - GetUserObjectInformationW (hwst_orig, UOI_NAME, wstname, 1024, &n); - /* Prior to Vista it was possible to start a service with the - "Interact with desktop" flag. This started the service in the - interactive window station of the console. A big security - risk, but we don't want to disable this behaviour for older - OSes because it's still heavily used by some users. They have - been warned. */ - if (!::cygheap->user.setuid_to_restricted - && wcscasecmp (wstname, L"WinSta0") != 0) - { - WCHAR sid[128]; - - sa = sec_user ((PSECURITY_ATTRIBUTES) alloca (1024), - ::cygheap->user.sid ()); - /* We're creating a window station per user, not per logon session. - First of all we might not have a valid logon session for - the user (logon by create_token), and second, it doesn't - make sense in terms of security to create a new window - station for every logon of the same user. It just fills up - the system with window stations for no good reason. */ - hwst = CreateWindowStationW (::cygheap->user.get_windows_id (sid), 0, - GENERIC_READ | GENERIC_WRITE, sa); - if (!hwst) - system_printf ("CreateWindowStation failed, %E"); - else if (!SetProcessWindowStation (hwst)) - system_printf ("SetProcessWindowStation failed, %E"); - else if (!(hdsk = CreateDesktopW (L"Default", NULL, NULL, 0, - GENERIC_ALL, sa))) - system_printf ("CreateDesktop failed, %E"); - else - { - wcpcpy (wcpcpy (wstname, sid), L"\\Default"); - si.lpDesktop = wstname; - debug_printf ("Desktop: %W", si.lpDesktop); - } - } - - rc = CreateProcessAsUserW (::cygheap->user.primary_token (), - runpath, /* image name - with full path */ - cmd.wcs (wcmd),/* what was passed to exec */ - &sec_none_nih, /* process security attrs */ - &sec_none_nih, /* thread security attrs */ - TRUE, /* inherit handles from parent */ - c_flags, - envblock, /* environment */ - NULL, - &si, - &pi); - if (hwst) - { - SetProcessWindowStation (hwst_orig); - CloseWindowStation (hwst); - } - if (hdsk) - { - SetThreadDesktop (hdsk_orig); - CloseDesktop (hdsk); - } - } - - if (mode != _P_OVERLAY) - SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT); - - /* Set errno now so that debugging messages from it appear before our - final debugging message [this is a general rule for debugging - messages]. */ - if (!rc) - { - __seterrno (); - syscall_printf ("CreateProcess failed, %E"); - /* If this was a failed exec, restore the saved sendsig. */ - if (reset_sendsig) - { - myself->sendsig = myself->exec_sendsig; - myself->exec_sendsig = NULL; - } - myself->process_state &= ~PID_NOTCYGWIN; - /* Reset handle inheritance to default when the execution of a non-Cygwin - process fails. Only need to do this for _P_OVERLAY since the handle will - be closed otherwise. Don't need to do this for 'parent' since it will - be closed in every case. See FIXME above. */ - if (!iscygwin () && mode == _P_OVERLAY) - SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT); - if (wr_proc_pipe == my_wr_proc_pipe) - wr_proc_pipe = NULL; /* We still own it: don't nuke in destructor */ - - /* Restore impersonation. In case of _P_OVERLAY this isn't - allowed since it would overwrite child data. */ - if (mode != _P_OVERLAY) - ::cygheap->user.reimpersonate (); - - res = -1; - goto out; - } - - /* The CREATE_SUSPENDED case is handled below */ - if (iscygwin () && !(c_flags & CREATE_SUSPENDED)) - strace.write_childpid (pi.dwProcessId); - - /* Fixup the parent data structures if needed and resume the child's - main thread. */ - if (::cygheap->fdtab.need_fixup_before ()) - ::cygheap->fdtab.fixup_before_exec (pi.dwProcessId); - - if (mode != _P_OVERLAY) - cygpid = cygwin_pid (pi.dwProcessId); - else - cygpid = myself->pid; - - /* We print the original program name here so the user can see that too. */ - syscall_printf ("pid %d, prog_arg %s, cmd line %.9500s)", - rc ? cygpid : (unsigned int) -1, prog_arg, (const char *) cmd); - - /* Name the handle similarly to proc_subproc. */ - ProtectHandle1 (pi.hProcess, childhProc); - - if (mode == _P_OVERLAY) - { - myself->dwProcessId = pi.dwProcessId; - strace.execing = 1; - myself.hProcess = hExeced = pi.hProcess; - real_path.get_wide_win32_path (myself->progname); // FIXME: race? - sigproc_printf ("new process name %W", myself->progname); - if (!iscygwin ()) - close_all_files (); - } - else - { - myself->set_has_pgid_children (); - ProtectHandle (pi.hThread); - pinfo child (cygpid, - PID_IN_USE | (real_path.iscygexec () ? 0 : PID_NOTCYGWIN)); - if (!child) - { - syscall_printf ("pinfo failed"); - if (get_errno () != ENOMEM) - set_errno (EAGAIN); - res = -1; - goto out; - } - child->dwProcessId = pi.dwProcessId; - child.hProcess = pi.hProcess; - - real_path.get_wide_win32_path (child->progname); - /* FIXME: This introduces an unreferenced, open handle into the child. - The purpose is to keep the pid shared memory open so that all of - the fields filled out by child.remember do not disappear and so there - is not a brief period during which the pid is not available. - However, we should try to find another way to do this eventually. */ - DuplicateHandle (GetCurrentProcess (), child.shared_handle (), - pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS); - child->start_time = time (NULL); /* Register child's starting time. */ - child->nice = myself->nice; - postfork (child); - if (!child.remember (mode == _P_DETACH)) - { - /* FIXME: Child in strange state now */ - CloseHandle (pi.hProcess); - ForceCloseHandle (pi.hThread); - res = -1; - goto out; - } - } - - /* Start the child running */ - if (c_flags & CREATE_SUSPENDED) - { - /* Inject a non-inheritable wr_proc_pipe handle into child so that we - can accurately track when the child exits without keeping this - process waiting around for it to exit. */ - if (!iscygwin ()) - DuplicateHandle (GetCurrentProcess (), wr_proc_pipe, pi.hProcess, NULL, - 0, false, DUPLICATE_SAME_ACCESS); - ResumeThread (pi.hThread); - if (iscygwin ()) - strace.write_childpid (pi.dwProcessId); - } - ForceCloseHandle (pi.hThread); - - sigproc_printf ("spawned windows pid %d", pi.dwProcessId); - - bool synced; - if ((mode == _P_DETACH || mode == _P_NOWAIT) && !iscygwin ()) - synced = false; - else - /* Just mark a non-cygwin process as 'synced'. We will still eventually - wait for it to exit in maybe_set_exit_code_from_windows(). */ - synced = iscygwin () ? sync (pi.dwProcessId, pi.hProcess, INFINITE) : true; - - switch (mode) - { - case _P_OVERLAY: - myself.hProcess = pi.hProcess; - if (!synced) - { - if (!proc_retry (pi.hProcess)) - { - looped++; - goto loop; - } - close_all_files (true); - } - else - { - if (iscygwin ()) - close_all_files (true); - if (!my_wr_proc_pipe - && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT) - wait_for_myself (); - } - myself.exit (EXITCODE_NOSET); - break; - case _P_WAIT: - case _P_SYSTEM: - system_call.arm (); - if (waitpid (cygpid, &res, 0) != cygpid) - res = -1; - break; - case _P_DETACH: - res = 0; /* Lost all memory of this child. */ - break; - case _P_NOWAIT: - case _P_NOWAITO: - case _P_VFORK: - res = cygpid; - break; - default: - break; - } - -out: + __endtry this->cleanup (); if (envblock) free (envblock); @@ -1137,28 +1137,31 @@ av::setup (const char *prog_arg, path_conv& real_path, const char *ext, } { - myfault efault; - if (efault.faulted ()) + __try + { + if (buf[0] == 'M' && buf[1] == 'Z') + { + WORD subsys; + unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8); + win16_exe = off < sizeof (IMAGE_DOS_HEADER); + if (!win16_exe) + real_path.set_cygexec (hook_or_detect_cygwin (buf, NULL, + subsys, hm)); + else + real_path.set_cygexec (false); + UnmapViewOfFile (buf); + CloseHandle (hm); + break; + } + } + __except (NO_ERROR) { UnmapViewOfFile (buf); CloseHandle (hm); real_path.set_cygexec (false); break; } - if (buf[0] == 'M' && buf[1] == 'Z') - { - WORD subsys; - unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8); - win16_exe = off < sizeof (IMAGE_DOS_HEADER); - if (!win16_exe) - real_path.set_cygexec (hook_or_detect_cygwin (buf, NULL, - subsys, hm)); - else - real_path.set_cygexec (false); - UnmapViewOfFile (buf); - CloseHandle (hm); - break; - } + __endtry } CloseHandle (hm); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index d53bf347b..fe3a88da3 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1163,31 +1163,31 @@ getsid (pid_t pid) extern "C" ssize_t read (int fd, void *ptr, size_t len) { - pthread_testcancel (); - - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - size_t res = (size_t) -1; - cygheap_fdget cfd (fd); - if (cfd < 0) - goto done; + pthread_testcancel (); - if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) + __try { - set_errno (EBADF); - goto done; + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; + + if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) + { + set_errno (EBADF); + __leave; + } + + /* Could block, so let user know we at least got here. */ + syscall_printf ("read(%d, %p, %d) %sblocking", + fd, ptr, len, cfd->is_nonblocking () ? "non" : ""); + + cfd->read (ptr, len); + res = len; } - - /* Could block, so let user know we at least got here. */ - syscall_printf ("read(%d, %p, %d) %sblocking", - fd, ptr, len, cfd->is_nonblocking () ? "non" : ""); - - cfd->read (ptr, res = len); - -done: + __except (EFAULT) {} + __endtry syscall_printf ("%lR = read(%d, %p, %d)", res, fd, ptr, len); MALLOC_CHECK; return (ssize_t) res; @@ -1198,38 +1198,38 @@ EXPORT_ALIAS (read, _read) extern "C" ssize_t readv (int fd, const struct iovec *const iov, const int iovcnt) { + ssize_t res = -1; + pthread_testcancel (); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - ssize_t res = -1; - const ssize_t tot = check_iovec_for_read (iov, iovcnt); - - cygheap_fdget cfd (fd); - if (cfd < 0) - goto done; - - if (tot <= 0) + __try { - res = tot; - goto done; + const ssize_t tot = check_iovec_for_read (iov, iovcnt); + + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; + + if (tot <= 0) + { + res = tot; + __leave; + } + + if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) + { + set_errno (EBADF); + __leave; + } + + /* Could block, so let user know we at least got here. */ + syscall_printf ("readv(%d, %p, %d) %sblocking", + fd, iov, iovcnt, cfd->is_nonblocking () ? "non" : ""); + + res = cfd->readv (iov, iovcnt, tot); } - - if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) - { - set_errno (EBADF); - goto done; - } - - /* Could block, so let user know we at least got here. */ - syscall_printf ("readv(%d, %p, %d) %sblocking", - fd, iov, iovcnt, cfd->is_nonblocking () ? "non" : ""); - - res = cfd->readv (iov, iovcnt, tot); - -done: + __except (EFAULT) {} + __endtry syscall_printf ("%lR = readv(%d, %p, %d)", res, fd, iov, iovcnt); MALLOC_CHECK; return res; @@ -1238,9 +1238,10 @@ done: extern "C" ssize_t pread (int fd, void *ptr, size_t len, off_t off) { + ssize_t res; + pthread_testcancel (); - ssize_t res; cygheap_fdget cfd (fd); if (cfd < 0) res = -1; @@ -1254,35 +1255,33 @@ pread (int fd, void *ptr, size_t len, off_t off) extern "C" ssize_t write (int fd, const void *ptr, size_t len) { - pthread_testcancel (); - - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - ssize_t res = -1; - cygheap_fdget cfd (fd); - if (cfd < 0) - goto done; + pthread_testcancel (); - if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) + __try { - set_errno (EBADF); - goto done; + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; + + if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) + { + set_errno (EBADF); + __leave; + } + + /* Could block, so let user know we at least got here. */ + if (fd == 1 || fd == 2) + paranoid_printf ("write(%d, %p, %d)", fd, ptr, len); + else + syscall_printf ("write(%d, %p, %d)", fd, ptr, len); + + res = cfd->write (ptr, len); } - - /* Could block, so let user know we at least got here. */ - if (fd == 1 || fd == 2) - paranoid_printf ("write(%d, %p, %d)", fd, ptr, len); - else - syscall_printf ("write(%d, %p, %d)", fd, ptr, len); - - res = cfd->write (ptr, len); - -done: + __except (EFAULT) {} + __endtry syscall_printf ("%lR = write(%d, %p, %d)", res, fd, ptr, len); - MALLOC_CHECK; return res; } @@ -1292,45 +1291,44 @@ EXPORT_ALIAS (write, _write) extern "C" ssize_t writev (const int fd, const struct iovec *const iov, const int iovcnt) { + ssize_t res = -1; + pthread_testcancel (); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - ssize_t res = -1; - const ssize_t tot = check_iovec_for_write (iov, iovcnt); - - cygheap_fdget cfd (fd); - if (cfd < 0) - goto done; - - if (tot <= 0) + __try { - res = tot; - goto done; + const ssize_t tot = check_iovec_for_write (iov, iovcnt); + + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; + + if (tot <= 0) + { + res = tot; + __leave; + } + + if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) + { + set_errno (EBADF); + __leave; + } + + /* Could block, so let user know we at least got here. */ + if (fd == 1 || fd == 2) + paranoid_printf ("writev(%d, %p, %d)", fd, iov, iovcnt); + else + syscall_printf ("writev(%d, %p, %d)", fd, iov, iovcnt); + + res = cfd->writev (iov, iovcnt, tot); } - - if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) - { - set_errno (EBADF); - goto done; - } - - /* Could block, so let user know we at least got here. */ - if (fd == 1 || fd == 2) - paranoid_printf ("writev(%d, %p, %d)", fd, iov, iovcnt); - else - syscall_printf ("writev(%d, %p, %d)", fd, iov, iovcnt); - - res = cfd->writev (iov, iovcnt, tot); - -done: + __except (EFAULT) {} + __endtry if (fd == 1 || fd == 2) paranoid_printf ("%lR = writev(%d, %p, %d)", res, fd, iov, iovcnt); else syscall_printf ("%lR = writev(%d, %p, %d)", res, fd, iov, iovcnt); - MALLOC_CHECK; return res; } @@ -1361,75 +1359,76 @@ open (const char *unix_path, int flags, ...) va_list ap; mode_t mode = 0; - syscall_printf ("open(%s, %y)", unix_path, flags); pthread_testcancel (); - myfault efault; - if (efault.faulted (EFAULT)) - /* errno already set */; - else if (!*unix_path) - set_errno (ENOENT); - else + + __try { - /* check for optional mode argument */ - va_start (ap, flags); - mode = va_arg (ap, mode_t); - va_end (ap); - - fhandler_base *fh; - cygheap_fdnew fd; - - if (fd >= 0) + syscall_printf ("open(%s, %y)", unix_path, flags); + if (!*unix_path) + set_errno (ENOENT); + else { - /* This is a temporary kludge until all utilities can catch up with - a change in behavior that implements linux functionality: opening - a tty should not automatically cause it to become the controlling - tty for the process. */ - int opt = PC_OPEN | ((flags & (O_NOFOLLOW | O_EXCL)) - ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW); - if (!(flags & O_NOCTTY) && fd > 2 && myself->ctty != -2) + /* check for optional mode argument */ + va_start (ap, flags); + mode = va_arg (ap, mode_t); + va_end (ap); + + fhandler_base *fh; + cygheap_fdnew fd; + + if (fd >= 0) { - flags |= O_NOCTTY; - opt |= PC_CTTY; /* flag that, if opened, this fhandler could - later be capable of being a controlling - terminal if /dev/tty is opened. */ - } - if (!(fh = build_fh_name (unix_path, opt, stat_suffixes))) - res = -1; // errno already set - else if ((flags & O_NOFOLLOW) && fh->issymlink ()) - { - delete fh; - res = -1; - set_errno (ELOOP); - } - else if ((flags & O_DIRECTORY) && fh->exists () && !fh->pc.isdir ()) - { - delete fh; - res = -1; - set_errno (ENOTDIR); - } - else if (((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) && fh->exists ()) - { - delete fh; - res = -1; - set_errno (EEXIST); - } - else if ((fh->is_fs_special () && fh->device_access_denied (flags)) - || !fh->open_with_arch (flags, (mode & 07777) & ~cygheap->umask)) - { - delete fh; - res = -1; - } - else - { - fd = fh; - if (fd <= 2) - set_std_handle (fd); - res = fd; + /* This is a temporary kludge until all utilities can catch up + with a change in behavior that implements linux functionality: + opening a tty should not automatically cause it to become the + controlling tty for the process. */ + int opt = PC_OPEN | ((flags & (O_NOFOLLOW | O_EXCL)) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW); + if (!(flags & O_NOCTTY) && fd > 2 && myself->ctty != -2) + { + flags |= O_NOCTTY; + /* flag that, if opened, this fhandler could later be capable + of being a controlling terminal if /dev/tty is opened. */ + opt |= PC_CTTY; + } + if (!(fh = build_fh_name (unix_path, opt, stat_suffixes))) + ; // errno already set + else if ((flags & O_NOFOLLOW) && fh->issymlink ()) + { + delete fh; + set_errno (ELOOP); + } + else if ((flags & O_DIRECTORY) && fh->exists () + && !fh->pc.isdir ()) + { + delete fh; + set_errno (ENOTDIR); + } + else if (((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) + && fh->exists ()) + { + delete fh; + set_errno (EEXIST); + } + else if ((fh->is_fs_special () + && fh->device_access_denied (flags)) + || !fh->open_with_arch (flags, (mode & 07777) + & ~cygheap->umask)) + delete fh; + else + { + fd = fh; + if (fd <= 2) + set_std_handle (fd); + res = fd; + } } } - } - syscall_printf ("%R = open(%s, %y)", res, unix_path, flags); + syscall_printf ("%R = open(%s, %y)", res, unix_path, flags); + } + __except (EFAULT) {} + __endtry return res; } @@ -1893,34 +1892,33 @@ stat_worker (path_conv &pc, struct stat *buf) { int res = -1; - myfault efault; - if (efault.faulted (EFAULT)) - goto error; - - if (pc.error) + __try { - debug_printf ("got %d error from path_conv", pc.error); - set_errno (pc.error); + if (pc.error) + { + debug_printf ("got %d error from path_conv", pc.error); + set_errno (pc.error); + } + else if (pc.exists ()) + { + fhandler_base *fh; + + if (!(fh = build_fh_pc (pc))) + __leave; + + debug_printf ("(%S, %p, %p), file_attributes %d", + pc.get_nt_native_path (), buf, fh, (DWORD) *fh); + memset (buf, 0, sizeof (*buf)); + res = fh->fstat (buf); + if (!res) + fh->stat_fixup (buf); + delete fh; + } + else + set_errno (ENOENT); } - else if (pc.exists ()) - { - fhandler_base *fh; - - if (!(fh = build_fh_pc (pc))) - goto error; - - debug_printf ("(%S, %p, %p), file_attributes %d", - pc.get_nt_native_path (), buf, fh, (DWORD) *fh); - memset (buf, 0, sizeof (*buf)); - res = fh->fstat (buf); - if (!res) - fh->stat_fixup (buf); - delete fh; - } - else - set_errno (ENOENT); - - error: + __except (EFAULT) {} + __endtry MALLOC_CHECK; syscall_printf ("%d = (%S,%p)", res, pc.get_nt_native_path (), buf); return res; @@ -2112,497 +2110,511 @@ rename (const char *oldpath, const char *newpath) FILE_STANDARD_INFORMATION ofsi; PFILE_RENAME_INFORMATION pfri; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - if (!*oldpath || !*newpath) + __try { - /* Reject rename("","x"), rename("x",""). */ - set_errno (ENOENT); - goto out; - } - if (has_dot_last_component (oldpath, true)) - { - /* Reject rename("dir/.","x"). */ - oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); - set_errno (oldpc.isdir () ? EINVAL : ENOTDIR); - goto out; - } - if (has_dot_last_component (newpath, true)) - { - /* Reject rename("dir","x/."). */ - newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); - set_errno (!newpc.exists () ? ENOENT : newpc.isdir () ? EINVAL : ENOTDIR); - goto out; - } - - /* A trailing slash requires that the pathname points to an existing - directory. If it's not, it's a ENOTDIR condition. The same goes - for newpath a bit further down this function. */ - olen = strlen (oldpath); - if (isdirsep (oldpath[olen - 1])) - { - char *buf; - char *p = stpcpy (buf = tp.c_get (), oldpath) - 1; - oldpath = buf; - while (p >= oldpath && isdirsep (*p)) - *p-- = '\0'; - olen = p + 1 - oldpath; - if (!olen) + if (!*oldpath || !*newpath) { - /* The root directory cannot be renamed. This also rejects - the corner case of rename("/","/"), even though it is the - same file. */ - set_errno (EINVAL); - goto out; + /* Reject rename("","x"), rename("x",""). */ + set_errno (ENOENT); + __leave; } - old_dir_requested = true; - } - oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); - if (oldpc.error) - { - set_errno (oldpc.error); - goto out; - } - if (!oldpc.exists ()) - { - set_errno (ENOENT); - goto out; - } - if (oldpc.isspecial () && !oldpc.issocket () && !oldpc.is_fs_special ()) - { - /* No renames from virtual FS */ - set_errno (EROFS); - goto out; - } - if (oldpc.has_attribute (FILE_ATTRIBUTE_REPARSE_POINT) && !oldpc.issymlink ()) - { - /* Volume mount point. If we try to rename a volume mount point, NT - returns STATUS_NOT_SAME_DEVICE ==> Win32 ERROR_NOT_SAME_DEVICE ==> - errno EXDEV. That's bad since mv(1) will now perform a cross-device - move. So what we do here is to treat the volume mount point just - like Linux treats a mount point. */ - set_errno (EBUSY); - goto out; - } - if (old_dir_requested && !oldpc.isdir ()) - { - /* Reject rename("file/","x"). */ - set_errno (ENOTDIR); - goto out; - } - if (oldpc.known_suffix - && (ascii_strcasematch (oldpath + olen - 4, ".lnk") - || ascii_strcasematch (oldpath + olen - 4, ".exe"))) - old_explicit_suffix = true; - - nlen = strlen (newpath); - if (isdirsep (newpath[nlen - 1])) - { - char *buf; - char *p = stpcpy (buf = tp.c_get (), newpath) - 1; - newpath = buf; - while (p >= newpath && isdirsep (*p)) - *p-- = '\0'; - nlen = p + 1 - newpath; - if (!nlen) /* The root directory is never empty. */ + if (has_dot_last_component (oldpath, true)) { - set_errno (ENOTEMPTY); - goto out; + /* Reject rename("dir/.","x"). */ + oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); + set_errno (oldpc.isdir () ? EINVAL : ENOTDIR); + __leave; } - new_dir_requested = true; - } - newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); - if (newpc.error) - { - set_errno (newpc.error); - goto out; - } - if (newpc.isspecial () && !newpc.issocket ()) /* No renames to virtual FSes */ - { - set_errno (EROFS); - goto out; - } - if (new_dir_requested && !(newpc.exists () - ? newpc.isdir () : oldpc.isdir ())) - { - /* Reject rename("file1","file2/"), but allow rename("dir","d/"). */ - set_errno (newpc.exists () ? ENOTDIR : ENOENT); - goto out; - } - if (newpc.exists () && (oldpc.isdir () ? !newpc.isdir () : newpc.isdir ())) - { - /* Reject rename("file","dir") and rename("dir","file"). */ - set_errno (newpc.isdir () ? EISDIR : ENOTDIR); - goto out; - } - if (newpc.known_suffix - && (ascii_strcasematch (newpath + nlen - 4, ".lnk") - || ascii_strcasematch (newpath + nlen - 4, ".exe"))) - new_explicit_suffix = true; - - /* This test is necessary in almost every case, so just do it once here. */ - equal_path = RtlEqualUnicodeString (oldpc.get_nt_native_path (), - newpc.get_nt_native_path (), - oldpc.objcaseinsensitive ()); - - /* First check if oldpath and newpath only differ by case. If so, it's - just a request to change the case of the filename. By simply setting - the file attributes to INVALID_FILE_ATTRIBUTES (which translates to - "file doesn't exist"), all later tests are skipped. */ - if (oldpc.objcaseinsensitive () && newpc.exists () && equal_path - && old_explicit_suffix == new_explicit_suffix) - { - if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), - newpc.get_nt_native_path (), - FALSE)) + if (has_dot_last_component (newpath, true)) { - res = 0; - goto out; + /* Reject rename("dir","x/."). */ + newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); + set_errno (!newpc.exists () ? ENOENT + : newpc.isdir () ? EINVAL : ENOTDIR); + __leave; } - newpc.file_attributes (INVALID_FILE_ATTRIBUTES); - } - else if (oldpc.isdir ()) - { - /* Check for newpath being identical or a subdir of oldpath. */ - if (RtlPrefixUnicodeString (oldpc.get_nt_native_path (), - newpc.get_nt_native_path (), - TRUE)) + + /* A trailing slash requires that the pathname points to an existing + directory. If it's not, it's a ENOTDIR condition. The same goes + for newpath a bit further down this function. */ + olen = strlen (oldpath); + if (isdirsep (oldpath[olen - 1])) { - if (newpc.get_nt_native_path ()->Length - == oldpc.get_nt_native_path ()->Length) - { - res = 0; - goto out; - } - if (*(PWCHAR) ((PBYTE) newpc.get_nt_native_path ()->Buffer - + oldpc.get_nt_native_path ()->Length) == L'\\') + char *buf; + char *p = stpcpy (buf = tp.c_get (), oldpath) - 1; + oldpath = buf; + while (p >= oldpath && isdirsep (*p)) + *p-- = '\0'; + olen = p + 1 - oldpath; + if (!olen) { + /* The root directory cannot be renamed. This also rejects + the corner case of rename("/","/"), even though it is the + same file. */ set_errno (EINVAL); - goto out; + __leave; } + old_dir_requested = true; } - } - else if (!newpc.exists ()) - { - if (equal_path && old_explicit_suffix != new_explicit_suffix) + oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes); + if (oldpc.error) + { + set_errno (oldpc.error); + __leave; + } + if (!oldpc.exists ()) + { + set_errno (ENOENT); + __leave; + } + if (oldpc.isspecial () && !oldpc.issocket () && !oldpc.is_fs_special ()) + { + /* No renames from virtual FS */ + set_errno (EROFS); + __leave; + } + if (oldpc.has_attribute (FILE_ATTRIBUTE_REPARSE_POINT) + && !oldpc.issymlink ()) + { + /* Volume mount point. If we try to rename a volume mount point, NT + returns STATUS_NOT_SAME_DEVICE ==> Win32 ERROR_NOT_SAME_DEVICE ==> + errno EXDEV. That's bad since mv(1) will now perform a + cross-device move. So what we do here is to treat the volume + mount point just like Linux treats a mount point. */ + set_errno (EBUSY); + __leave; + } + if (old_dir_requested && !oldpc.isdir ()) + { + /* Reject rename("file/","x"). */ + set_errno (ENOTDIR); + __leave; + } + if (oldpc.known_suffix + && (ascii_strcasematch (oldpath + olen - 4, ".lnk") + || ascii_strcasematch (oldpath + olen - 4, ".exe"))) + old_explicit_suffix = true; + + nlen = strlen (newpath); + if (isdirsep (newpath[nlen - 1])) + { + char *buf; + char *p = stpcpy (buf = tp.c_get (), newpath) - 1; + newpath = buf; + while (p >= newpath && isdirsep (*p)) + *p-- = '\0'; + nlen = p + 1 - newpath; + if (!nlen) /* The root directory is never empty. */ + { + set_errno (ENOTEMPTY); + __leave; + } + new_dir_requested = true; + } + newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); + if (newpc.error) + { + set_errno (newpc.error); + __leave; + } + if (newpc.isspecial () && !newpc.issocket ()) + { + /* No renames to virtual FSes */ + set_errno (EROFS); + __leave; + } + if (new_dir_requested && !(newpc.exists () + ? newpc.isdir () : oldpc.isdir ())) + { + /* Reject rename("file1","file2/"), but allow rename("dir","d/"). */ + set_errno (newpc.exists () ? ENOTDIR : ENOENT); + __leave; + } + if (newpc.exists () + && (oldpc.isdir () ? !newpc.isdir () : newpc.isdir ())) + { + /* Reject rename("file","dir") and rename("dir","file"). */ + set_errno (newpc.isdir () ? EISDIR : ENOTDIR); + __leave; + } + if (newpc.known_suffix + && (ascii_strcasematch (newpath + nlen - 4, ".lnk") + || ascii_strcasematch (newpath + nlen - 4, ".exe"))) + new_explicit_suffix = true; + + /* This test is necessary in almost every case, so do it once here. */ + equal_path = RtlEqualUnicodeString (oldpc.get_nt_native_path (), + newpc.get_nt_native_path (), + oldpc.objcaseinsensitive ()); + + /* First check if oldpath and newpath only differ by case. If so, it's + just a request to change the case of the filename. By simply setting + the file attributes to INVALID_FILE_ATTRIBUTES (which translates to + "file doesn't exist"), all later tests are skipped. */ + if (oldpc.objcaseinsensitive () && newpc.exists () && equal_path + && old_explicit_suffix == new_explicit_suffix) { - newpc.check (newpath, PC_SYM_NOFOLLOW); if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), newpc.get_nt_native_path (), - oldpc.objcaseinsensitive ())) + FALSE)) { res = 0; - goto out; + __leave; + } + newpc.file_attributes (INVALID_FILE_ATTRIBUTES); + } + else if (oldpc.isdir ()) + { + /* Check for newpath being identical or a subdir of oldpath. */ + if (RtlPrefixUnicodeString (oldpc.get_nt_native_path (), + newpc.get_nt_native_path (), + TRUE)) + { + if (newpc.get_nt_native_path ()->Length + == oldpc.get_nt_native_path ()->Length) + { + res = 0; + __leave; + } + if (*(PWCHAR) ((PBYTE) newpc.get_nt_native_path ()->Buffer + + oldpc.get_nt_native_path ()->Length) == L'\\') + { + set_errno (EINVAL); + __leave; + } } } - else if (oldpc.is_lnk_special () - && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), - &ro_u_lnk, TRUE)) - rename_append_suffix (newpc, newpath, nlen, ".lnk"); - else if (oldpc.is_binary () && !old_explicit_suffix - && oldpc.known_suffix - && !nt_path_has_executable_suffix (newpc.get_nt_native_path ())) - /* Never append .exe suffix if oldpath had .exe suffix given - explicitely, or if oldpath wasn't already a .exe file, or - if the destination filename has one of the blessed executable - suffixes. - Note: To rename an executable foo.exe to bar-without-suffix, - the .exe suffix must be given explicitly in oldpath. */ - rename_append_suffix (newpc, newpath, nlen, ".exe"); - } - else - { - if (equal_path && old_explicit_suffix != new_explicit_suffix) + else if (!newpc.exists ()) { - newpc.check (newpath, PC_SYM_NOFOLLOW); - if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), - newpc.get_nt_native_path (), - oldpc.objcaseinsensitive ())) + if (equal_path && old_explicit_suffix != new_explicit_suffix) { - res = 0; - goto out; - } - } - else if (oldpc.is_lnk_special ()) - { - if (!newpc.is_lnk_special () - && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), - &ro_u_lnk, TRUE)) - { - rename_append_suffix (new2pc, newpath, nlen, ".lnk"); - removepc = &newpc; - } - } - else if (oldpc.is_binary ()) - { - /* Never append .exe suffix if oldpath had .exe suffix given - explicitely, or if newfile is a binary (in which case the given - name probably makes sense as it is), or if the destination - filename has one of the blessed executable suffixes. */ - if (!old_explicit_suffix && oldpc.known_suffix - && !newpc.is_binary () - && !nt_path_has_executable_suffix (newpc.get_nt_native_path ())) - { - rename_append_suffix (new2pc, newpath, nlen, ".exe"); - removepc = &newpc; + newpc.check (newpath, PC_SYM_NOFOLLOW); + if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), + newpc.get_nt_native_path (), + oldpc.objcaseinsensitive ())) + { + res = 0; + __leave; + } } + else if (oldpc.is_lnk_special () + && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), + &ro_u_lnk, TRUE)) + rename_append_suffix (newpc, newpath, nlen, ".lnk"); + else if (oldpc.is_binary () && !old_explicit_suffix + && oldpc.known_suffix + && !nt_path_has_executable_suffix + (newpc.get_nt_native_path ())) + /* Never append .exe suffix if oldpath had .exe suffix given + explicitely, or if oldpath wasn't already a .exe file, or + if the destination filename has one of the blessed executable + suffixes. + Note: To rename an executable foo.exe to bar-without-suffix, + the .exe suffix must be given explicitly in oldpath. */ + rename_append_suffix (newpc, newpath, nlen, ".exe"); } else { - /* If the new path is an existing .lnk symlink or a .exe file, - but the new path has not been specified with explicit suffix, - rename to the new name without suffix, as expected, but also - remove the clashing symlink or executable. Did I ever mention - how I hate the file suffix idea? */ - if ((newpc.is_lnk_special () - || RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), - &ro_u_exe, TRUE)) - && !new_explicit_suffix) + if (equal_path && old_explicit_suffix != new_explicit_suffix) { - new2pc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); - newpc.get_nt_native_path ()->Length -= 4 * sizeof (WCHAR); - if (new2pc.is_binary () || new2pc.is_lnk_special ()) - removepc = &new2pc; + newpc.check (newpath, PC_SYM_NOFOLLOW); + if (RtlEqualUnicodeString (oldpc.get_nt_native_path (), + newpc.get_nt_native_path (), + oldpc.objcaseinsensitive ())) + { + res = 0; + __leave; + } + } + else if (oldpc.is_lnk_special ()) + { + if (!newpc.is_lnk_special () + && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), + &ro_u_lnk, TRUE)) + { + rename_append_suffix (new2pc, newpath, nlen, ".lnk"); + removepc = &newpc; + } + } + else if (oldpc.is_binary ()) + { + /* Never append .exe suffix if oldpath had .exe suffix given + explicitely, or if newfile is a binary (in which case the given + name probably makes sense as it is), or if the destination + filename has one of the blessed executable suffixes. */ + if (!old_explicit_suffix && oldpc.known_suffix + && !newpc.is_binary () + && !nt_path_has_executable_suffix + (newpc.get_nt_native_path ())) + { + rename_append_suffix (new2pc, newpath, nlen, ".exe"); + removepc = &newpc; + } + } + else + { + /* If the new path is an existing .lnk symlink or a .exe file, + but the new path has not been specified with explicit suffix, + rename to the new name without suffix, as expected, but also + remove the clashing symlink or executable. Did I ever mention + how I hate the file suffix idea? */ + if ((newpc.is_lnk_special () + || RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (), + &ro_u_exe, TRUE)) + && !new_explicit_suffix) + { + new2pc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes); + newpc.get_nt_native_path ()->Length -= 4 * sizeof (WCHAR); + if (new2pc.is_binary () || new2pc.is_lnk_special ()) + removepc = &new2pc; + } } } - } - dstpc = (removepc == &newpc) ? &new2pc : &newpc; + dstpc = (removepc == &newpc) ? &new2pc : &newpc; - /* Check cross-device before touching anything. Otherwise we might end - up with an unlinked target dir even if the actual rename didn't work. */ - if (oldpc.fs_type () != dstpc->fs_type () - || oldpc.fs_serial_number () != dstpc->fs_serial_number ()) - { - set_errno (EXDEV); - goto out; - } - - /* Opening the file must be part of the transaction. It's not sufficient - to call only NtSetInformationFile under the transaction. Therefore we - have to start the transaction here, if necessary. */ - if (wincap.has_transactions () - && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) - && (dstpc->isdir () - || (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY)))) - start_transaction (old_trans, trans); - - int retry_count; - retry_count = 0; -retry: - /* Talking about inconsistent behaviour... - - DELETE is required to rename a file. So far, so good. - - At least one cifs FS (Tru64) needs FILE_READ_ATTRIBUTE, otherwise the - FileRenameInformation call fails with STATUS_ACCESS_DENIED. However, - on NFS we get a STATUS_ACCESS_DENIED if FILE_READ_ATTRIBUTE is used - and the file we try to rename is a symlink. Urgh. - - Samba (only some versions?) doesn't like the FILE_SHARE_DELETE mode if - the file has the R/O attribute set and returns STATUS_ACCESS_DENIED in - that case. */ - { - ULONG access = DELETE | (oldpc.fs_is_cifs () ? FILE_READ_ATTRIBUTES : 0); - ULONG sharing = FILE_SHARE_READ | FILE_SHARE_WRITE - | (oldpc.fs_is_samba () ? 0 : FILE_SHARE_DELETE); - ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT - | (oldpc.is_rep_symlink () ? FILE_OPEN_REPARSE_POINT : 0); - status = NtOpenFile (&fh, access, - oldpc.get_object_attr (attr, sec_none_nih), - &io, sharing, flags); - } - if (!NT_SUCCESS (status)) - { - debug_printf ("status %y", status); - if (status == STATUS_SHARING_VIOLATION - && cygwait (10L) != WAIT_SIGNALED) + /* Check cross-device before touching anything. Otherwise we might end + up with an unlinked target dir even if the actual rename didn't work.*/ + if (oldpc.fs_type () != dstpc->fs_type () + || oldpc.fs_serial_number () != dstpc->fs_serial_number ()) { - /* Typical BLODA problem. Some virus scanners check newly generated - files and while doing that disallow DELETE access. That's really - bad because it breaks applications which copy files by creating - a temporary filename and then rename the temp filename to the - target filename. This renaming fails due to the jealous virus - scanner and the application fails to create the target file. + set_errno (EXDEV); + __leave; + } - This kludge tries to work around that by yielding until the - sharing violation goes away, or a signal arrived, or after - about a second, give or take. */ - if (++retry_count < 40) + /* Opening the file must be part of the transaction. It's not sufficient + to call only NtSetInformationFile under the transaction. Therefore we + have to start the transaction here, if necessary. */ + if (wincap.has_transactions () + && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) + && (dstpc->isdir () + || (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY)))) + start_transaction (old_trans, trans); + + int retry_count; + retry_count = 0; + retry: + /* Talking about inconsistent behaviour... + - DELETE is required to rename a file. So far, so good. + - At least one cifs FS (Tru64) needs FILE_READ_ATTRIBUTE, otherwise the + FileRenameInformation call fails with STATUS_ACCESS_DENIED. However, + on NFS we get a STATUS_ACCESS_DENIED if FILE_READ_ATTRIBUTE is used + and the file we try to rename is a symlink. Urgh. + - Samba (only some versions?) doesn't like the FILE_SHARE_DELETE + mode if the file has the R/O attribute set and returns + STATUS_ACCESS_DENIED in that case. */ + { + ULONG access = DELETE + | (oldpc.fs_is_cifs () ? FILE_READ_ATTRIBUTES : 0); + ULONG sharing = FILE_SHARE_READ | FILE_SHARE_WRITE + | (oldpc.fs_is_samba () ? 0 : FILE_SHARE_DELETE); + ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT + | (oldpc.is_rep_symlink () ? FILE_OPEN_REPARSE_POINT : 0); + status = NtOpenFile (&fh, access, + oldpc.get_object_attr (attr, sec_none_nih), + &io, sharing, flags); + } + if (!NT_SUCCESS (status)) + { + debug_printf ("status %y", status); + if (status == STATUS_SHARING_VIOLATION + && cygwait (10L) != WAIT_SIGNALED) { - yield (); + /* Typical BLODA problem. Some virus scanners check newly + generated files and while doing that disallow DELETE access. + That's really bad because it breaks applications which copy + files by creating a temporary filename and then rename the + temp filename to the target filename. This renaming fails due + to the jealous virus scanner and the application fails to + create the target file. + + This kludge tries to work around that by yielding until the + sharing violation goes away, or a signal arrived, or after + about a second, give or take. */ + if (++retry_count < 40) + { + yield (); + goto retry; + } + } + else if (NT_TRANSACTIONAL_ERROR (status) && trans) + { + /* If NtOpenFile fails due to transactional problems, stop + transaction and go ahead without. */ + stop_transaction (status, old_trans, trans); + debug_printf ("Transaction failure. Retry open."); goto retry; } + __seterrno_from_nt_status (status); + __leave; } - else if (NT_TRANSACTIONAL_ERROR (status) && trans) - { - /* If NtOpenFile fails due to transactional problems, stop - transaction and go ahead without. */ - stop_transaction (status, old_trans, trans); - debug_printf ("Transaction failure. Retry open."); - goto retry; - } - __seterrno_from_nt_status (status); - goto out; - } - /* Renaming a dir to another, existing dir fails always, even if - ReplaceIfExists is set to TRUE and the existing dir is empty. So - we have to remove the destination dir first. This also covers the - case that the destination directory is not empty. In that case, - unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */ - if (dstpc->isdir ()) - { - status = unlink_nt (*dstpc); - if (!NT_SUCCESS (status)) + /* Renaming a dir to another, existing dir fails always, even if + ReplaceIfExists is set to TRUE and the existing dir is empty. So + we have to remove the destination dir first. This also covers the + case that the destination directory is not empty. In that case, + unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */ + if (dstpc->isdir ()) { - __seterrno_from_nt_status (status); - goto out; + status = unlink_nt (*dstpc); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; + } } - } - /* You can't copy a file if the destination exists and has the R/O - attribute set. Remove the R/O attribute first. But first check - if a removepc exists. If so, dstpc points to a non-existing file - due to a mangled suffix. */ - else if (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY)) - { - status = NtOpenFile (&nfh, FILE_WRITE_ATTRIBUTES, - dstpc->get_object_attr (attr, sec_none_nih), - &io, FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT - | (dstpc->is_rep_symlink () - ? FILE_OPEN_REPARSE_POINT : 0)); - if (!NT_SUCCESS (status)) + /* You can't copy a file if the destination exists and has the R/O + attribute set. Remove the R/O attribute first. But first check + if a removepc exists. If so, dstpc points to a non-existing file + due to a mangled suffix. */ + else if (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY)) { - __seterrno_from_nt_status (status); - goto out; + status = NtOpenFile (&nfh, FILE_WRITE_ATTRIBUTES, + dstpc->get_object_attr (attr, sec_none_nih), + &io, FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT + | (dstpc->is_rep_symlink () + ? FILE_OPEN_REPARSE_POINT : 0)); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; + } + status = NtSetAttributesFile (nfh, dstpc->file_attributes () + & ~FILE_ATTRIBUTE_READONLY); + NtClose (nfh); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + __leave; + } } - status = NtSetAttributesFile (nfh, dstpc->file_attributes () - & ~FILE_ATTRIBUTE_READONLY); - NtClose (nfh); - if (!NT_SUCCESS (status)) - { - __seterrno_from_nt_status (status); - goto out; - } - } - /* SUSv3: If the old argument and the new argument resolve to the same - existing file, rename() shall return successfully and perform no - other action. - The test tries to be as quick as possible. Due to the above cross device - check we already know both files are on the same device. So it just - tests if oldpath has more than 1 hardlink, then it opens newpath - and tests for identical file ids. If so, oldpath and newpath refer to - the same file. */ - if ((removepc || dstpc->exists ()) - && !oldpc.isdir () - && NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofsi, sizeof ofsi, - FileStandardInformation)) - && ofsi.NumberOfLinks > 1 - && NT_SUCCESS (NtOpenFile (&nfh, READ_CONTROL, + /* SUSv3: If the old argument and the new argument resolve to the same + existing file, rename() shall return successfully and perform no + other action. + The test tries to be as quick as possible. Due to the above cross + device check we already know both files are on the same device. So + it just tests if oldpath has more than 1 hardlink, then it opens + newpath and tests for identical file ids. If so, oldpath and newpath + refer to the same file. */ + if ((removepc || dstpc->exists ()) + && !oldpc.isdir () + && NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofsi, sizeof ofsi, + FileStandardInformation)) + && ofsi.NumberOfLinks > 1 + && NT_SUCCESS (NtOpenFile (&nfh, READ_CONTROL, (removepc ?: dstpc)->get_object_attr (attr, sec_none_nih), &io, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT | ((removepc ?: dstpc)->is_rep_symlink () ? FILE_OPEN_REPARSE_POINT : 0)))) - { - FILE_INTERNAL_INFORMATION ofii, nfii; + { + FILE_INTERNAL_INFORMATION ofii, nfii; - if (NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofii, sizeof ofii, - FileInternalInformation)) - && NT_SUCCESS (NtQueryInformationFile (nfh, &io, &nfii, sizeof nfii, - FileInternalInformation)) - && ofii.FileId.QuadPart == nfii.FileId.QuadPart) - { - debug_printf ("%s and %s are the same file", oldpath, newpath); - NtClose (nfh); - res = 0; - goto out; - } - NtClose (nfh); - } - /* Create FILE_RENAME_INFORMATION struct. Using a tmp_pathbuf area allows - for paths of up to 32757 chars. This test is just for paranoia's sake. */ - if (dstpc->get_nt_native_path ()->Length > NT_MAX_PATH * sizeof (WCHAR) - - sizeof (FILE_RENAME_INFORMATION)) - { - debug_printf ("target filename too long"); - set_errno (EINVAL); - goto out; - } - pfri = (PFILE_RENAME_INFORMATION) tp.w_get (); - pfri->ReplaceIfExists = TRUE; - pfri->RootDirectory = NULL; - pfri->FileNameLength = dstpc->get_nt_native_path ()->Length; - memcpy (&pfri->FileName, dstpc->get_nt_native_path ()->Buffer, - pfri->FileNameLength); - status = NtSetInformationFile (fh, &io, pfri, - sizeof *pfri + pfri->FileNameLength, - FileRenameInformation); - /* This happens if the access rights don't allow deleting the destination. - Even if the handle to the original file is opened with BACKUP - and/or RECOVERY, these flags don't apply to the destination of the - rename operation. So, a privileged user can't rename a file to an - existing file, if the permissions of the existing file aren't right. - Like directories, we have to handle this separately by removing the - destination before renaming. */ - if (status == STATUS_ACCESS_DENIED && dstpc->exists () && !dstpc->isdir ()) - { - if (wincap.has_transactions () - && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) - && !trans) - { - start_transaction (old_trans, trans); - /* As mentioned earlier, opening the file must be part of the - transaction. Therefore we have to reopen the file here if the - transaction hasn't been started already. Unfortunately we can't - use the NT "reopen file from existing handle" feature. In that - case NtOpenFile returns STATUS_TRANSACTIONAL_CONFLICT. We *have* - to close the handle to the file first, *then* we can re-open it. - Fortunately nothing has happened yet, so the atomicity of the - rename functionality is not spoiled. */ - NtClose (fh); -retry_reopen: - status = NtOpenFile (&fh, DELETE, - oldpc.get_object_attr (attr, sec_none_nih), - &io, FILE_SHARE_VALID_FLAGS, - FILE_OPEN_FOR_BACKUP_INTENT - | (oldpc.is_rep_symlink () - ? FILE_OPEN_REPARSE_POINT : 0)); - if (!NT_SUCCESS (status)) + if (NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofii, sizeof ofii, + FileInternalInformation)) + && NT_SUCCESS (NtQueryInformationFile (nfh, &io, &nfii, + sizeof nfii, + FileInternalInformation)) + && ofii.FileId.QuadPart == nfii.FileId.QuadPart) { - if (NT_TRANSACTIONAL_ERROR (status) && trans) - { - /* If NtOpenFile fails due to transactional problems, stop - transaction and go ahead without. */ - stop_transaction (status, old_trans, trans); - debug_printf ("Transaction failure. Retry open."); - goto retry_reopen; - } - __seterrno_from_nt_status (status); - goto out; + debug_printf ("%s and %s are the same file", oldpath, newpath); + NtClose (nfh); + res = 0; + __leave; } + NtClose (nfh); } - if (NT_SUCCESS (status = unlink_nt (*dstpc))) - status = NtSetInformationFile (fh, &io, pfri, - sizeof *pfri + pfri->FileNameLength, - FileRenameInformation); + /* Create FILE_RENAME_INFORMATION struct. Using a tmp_pathbuf area + allows for paths of up to 32757 chars. This test is just for + paranoia's sake. */ + if (dstpc->get_nt_native_path ()->Length + > NT_MAX_PATH * sizeof (WCHAR) - sizeof (FILE_RENAME_INFORMATION)) + { + debug_printf ("target filename too long"); + set_errno (EINVAL); + __leave; + } + pfri = (PFILE_RENAME_INFORMATION) tp.w_get (); + pfri->ReplaceIfExists = TRUE; + pfri->RootDirectory = NULL; + pfri->FileNameLength = dstpc->get_nt_native_path ()->Length; + memcpy (&pfri->FileName, dstpc->get_nt_native_path ()->Buffer, + pfri->FileNameLength); + status = NtSetInformationFile (fh, &io, pfri, + sizeof *pfri + pfri->FileNameLength, + FileRenameInformation); + /* This happens if the access rights don't allow deleting the destination. + Even if the handle to the original file is opened with BACKUP + and/or RECOVERY, these flags don't apply to the destination of the + rename operation. So, a privileged user can't rename a file to an + existing file, if the permissions of the existing file aren't right. + Like directories, we have to handle this separately by removing the + destination before renaming. */ + if (status == STATUS_ACCESS_DENIED && dstpc->exists () + && !dstpc->isdir ()) + { + if (wincap.has_transactions () + && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS) + && !trans) + { + start_transaction (old_trans, trans); + /* As mentioned earlier, opening the file must be part of the + transaction. Therefore we have to reopen the file here if the + transaction hasn't been started already. Unfortunately we + can't use the NT "reopen file from existing handle" feature. + In that case NtOpenFile returns STATUS_TRANSACTIONAL_CONFLICT. + We *have* to close the handle to the file first, *then* we can + re-open it. Fortunately nothing has happened yet, so the + atomicity of the rename functionality is not spoiled. */ + NtClose (fh); + retry_reopen: + status = NtOpenFile (&fh, DELETE, + oldpc.get_object_attr (attr, sec_none_nih), + &io, FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT + | (oldpc.is_rep_symlink () + ? FILE_OPEN_REPARSE_POINT : 0)); + if (!NT_SUCCESS (status)) + { + if (NT_TRANSACTIONAL_ERROR (status) && trans) + { + /* If NtOpenFile fails due to transactional problems, + stop transaction and go ahead without. */ + stop_transaction (status, old_trans, trans); + debug_printf ("Transaction failure. Retry open."); + goto retry_reopen; + } + __seterrno_from_nt_status (status); + __leave; + } + } + if (NT_SUCCESS (status = unlink_nt (*dstpc))) + status = NtSetInformationFile (fh, &io, pfri, + sizeof *pfri + pfri->FileNameLength, + FileRenameInformation); + } + if (NT_SUCCESS (status)) + { + if (removepc) + unlink_nt (*removepc); + res = 0; + } + else + __seterrno_from_nt_status (status); } - if (NT_SUCCESS (status)) + __except (EFAULT) { - if (removepc) - unlink_nt (*removepc); - res = 0; + res = -1; } - else - __seterrno_from_nt_status (status); - -out: + __endtry if (fh) NtClose (fh); /* Stop transaction if we started one. */ if (trans) stop_transaction (status, old_trans, trans); - syscall_printf ("%R = rename(%s, %s)", res, oldpath, newpath); + if (get_errno () != EFAULT) + syscall_printf ("%R = rename(%s, %s)", res, oldpath, newpath); return res; } @@ -2611,28 +2623,28 @@ system (const char *cmdstring) { pthread_testcancel (); - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - int res; - const char* command[4]; - if (cmdstring == NULL) return 1; - command[0] = "sh"; - command[1] = "-c"; - command[2] = cmdstring; - command[3] = (const char *) NULL; + int res = -1; + const char* command[4]; - if ((res = spawnvp (_P_SYSTEM, "/bin/sh", command)) == -1) + __try { - // when exec fails, return value should be as if shell - // executed exit (127) - res = 127; - } + command[0] = "sh"; + command[1] = "-c"; + command[2] = cmdstring; + command[3] = (const char *) NULL; + if ((res = spawnvp (_P_SYSTEM, "/bin/sh", command)) == -1) + { + // when exec fails, return value should be as if shell + // executed exit (127) + res = 127; + } + } + __except (EFAULT) {} + __endtry return res; } @@ -2677,24 +2689,25 @@ fpathconf (int fd, int v) extern "C" long int pathconf (const char *file, int v) { - fhandler_base *fh; + fhandler_base *fh = NULL; long ret = -1; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - if (!*file) + __try { - set_errno (ENOENT); - return -1; + if (!*file) + { + set_errno (ENOENT); + return -1; + } + if (!(fh = build_fh_name (file, PC_SYM_FOLLOW, stat_suffixes))) + return -1; + if (!fh->exists ()) + set_errno (ENOENT); + else + ret = fh->fpathconf (v); } - if (!(fh = build_fh_name (file, PC_SYM_FOLLOW, stat_suffixes))) - return -1; - if (!fh->exists ()) - set_errno (ENOENT); - else - ret = fh->fpathconf (v); + __except (EFAULT) {} + __endtry delete fh; return ret; } @@ -2703,10 +2716,8 @@ extern "C" int ttyname_r (int fd, char *buf, size_t buflen) { int ret = 0; - myfault efault; - if (efault.faulted ()) - ret = EFAULT; - else + + __try { cygheap_fdget cfd (fd, true); if (cfd < 0) @@ -2717,8 +2728,13 @@ ttyname_r (int fd, char *buf, size_t buflen) ret = ERANGE; else strcpy (buf, cfd->ttyname ()); + debug_printf ("returning %d tty: %s", ret, ret ? "NULL" : buf); } - debug_printf ("returning %d tty: %s", ret, ret ? "NULL" : buf); + __except (NO_ERROR) + { + ret = EFAULT; + } + __endtry return ret; } @@ -2975,14 +2991,16 @@ _get_osfhandle (int fd) extern "C" int fstatvfs (int fd, struct statvfs *sfs) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - cygheap_fdget cfd (fd); - if (cfd < 0) - return -1; - return cfd->fstatvfs (sfs); + __try + { + cygheap_fdget cfd (fd); + if (cfd < 0) + __leave; + return cfd->fstatvfs (sfs); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -2991,30 +3009,31 @@ statvfs (const char *name, struct statvfs *sfs) int res = -1; fhandler_base *fh = NULL; - myfault efault; - if (efault.faulted (EFAULT)) - goto error; - - if (!(fh = build_fh_name (name, PC_SYM_FOLLOW, stat_suffixes))) - goto error; - - if (fh->error ()) + __try { - debug_printf ("got %d error from build_fh_name", fh->error ()); - set_errno (fh->error ()); - } - else if (fh->exists ()) - { - debug_printf ("(%s, %p), file_attributes %d", name, sfs, (DWORD) *fh); - res = fh->fstatvfs (sfs); - } - else - set_errno (ENOENT); + if (!(fh = build_fh_name (name, PC_SYM_FOLLOW, stat_suffixes))) + __leave; + if (fh->error ()) + { + debug_printf ("got %d error from build_fh_name", fh->error ()); + set_errno (fh->error ()); + } + else if (fh->exists ()) + { + debug_printf ("(%s, %p), file_attributes %d", name, sfs, (DWORD) *fh); + res = fh->fstatvfs (sfs); + } + else + set_errno (ENOENT); + + } + __except (EFAULT) {} + __endtry delete fh; - error: MALLOC_CHECK; - syscall_printf ("%R = statvfs(%s,%p)", res, name, sfs); + if (get_errno () != EFAULT) + syscall_printf ("%R = statvfs(%s,%p)", res, name, sfs); return res; } @@ -3155,55 +3174,58 @@ mknod_worker (const char *path, mode_t type, mode_t mode, _major_t major, extern "C" int mknod32 (const char *path, mode_t mode, dev_t dev) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (!*path) + __try { - set_errno (ENOENT); - return -1; + if (!*path) + { + set_errno (ENOENT); + __leave; + } + + if (strlen (path) >= PATH_MAX) + __leave; + + path_conv w32path (path, PC_SYM_NOFOLLOW); + if (w32path.exists ()) + { + set_errno (EEXIST); + __leave; + } + + mode_t type = mode & S_IFMT; + _major_t major = _major (dev); + _minor_t minor = _minor (dev); + switch (type) + { + case S_IFCHR: + case S_IFBLK: + break; + + case S_IFIFO: + major = _major (FH_FIFO); + minor = _minor (FH_FIFO); + break; + + case 0: + case S_IFREG: + { + int fd = open (path, O_CREAT, mode); + if (fd < 0) + __leave; + close (fd); + return 0; + } + + default: + set_errno (EINVAL); + __leave; + } + + return mknod_worker (w32path.get_win32 (), type, mode, major, minor); } - - if (strlen (path) >= PATH_MAX) - return -1; - - path_conv w32path (path, PC_SYM_NOFOLLOW); - if (w32path.exists ()) - { - set_errno (EEXIST); - return -1; - } - - mode_t type = mode & S_IFMT; - _major_t major = _major (dev); - _minor_t minor = _minor (dev); - switch (type) - { - case S_IFCHR: - case S_IFBLK: - break; - - case S_IFIFO: - major = _major (FH_FIFO); - minor = _minor (FH_FIFO); - break; - - case 0: - case S_IFREG: - { - int fd = open (path, O_CREAT, mode); - if (fd < 0) - return -1; - close (fd); - return 0; - } - - default: - set_errno (EINVAL); - return -1; - } - - return mknod_worker (w32path.get_win32 (), type, mode, major, minor); + __except (EFAULT) + __endtry + return -1; } extern "C" int @@ -3912,15 +3934,19 @@ endutent () extern "C" void utmpname (const char *file) { - myfault efault; - if (efault.faulted () || !*file) + __try { - debug_printf ("Invalid file"); - return; + if (*file) + { + endutent (); + utmp_file = strdup (file); + debug_printf ("New UTMP file: %s", utmp_file); + return; + } } - endutent (); - utmp_file = strdup (file); - debug_printf ("New UTMP file: %s", utmp_file); + __except (NO_ERROR) {} + __endtry + debug_printf ("Invalid file"); } EXPORT_ALIAS (utmpname, utmpxname) @@ -3965,94 +3991,99 @@ getutent () extern "C" struct utmp * getutid (const struct utmp *id) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - if (utmp_fd < 0) + __try { - internal_setutent (false); if (utmp_fd < 0) - return NULL; - } - - utmp *ut = utmp_data; - while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut) - { - switch (id->ut_type) { - case RUN_LVL: - case BOOT_TIME: - case OLD_TIME: - case NEW_TIME: - if (id->ut_type == ut->ut_type) - return ut; - break; - case INIT_PROCESS: - case LOGIN_PROCESS: - case USER_PROCESS: - case DEAD_PROCESS: - if (strncmp (id->ut_id, ut->ut_id, UT_IDLEN) == 0) - return ut; - break; - default: - return NULL; + internal_setutent (false); + if (utmp_fd < 0) + __leave; + } + utmp *ut = utmp_data; + while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut) + { + switch (id->ut_type) + { + case RUN_LVL: + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + if (id->ut_type == ut->ut_type) + return ut; + break; + case INIT_PROCESS: + case LOGIN_PROCESS: + case USER_PROCESS: + case DEAD_PROCESS: + if (strncmp (id->ut_id, ut->ut_id, UT_IDLEN) == 0) + return ut; + break; + default: + break; + } } } + __except (EFAULT) {} + __endtry return NULL; } extern "C" struct utmp * getutline (const struct utmp *line) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - if (utmp_fd < 0) + __try { - internal_setutent (false); if (utmp_fd < 0) - return NULL; + { + internal_setutent (false); + if (utmp_fd < 0) + __leave; + } + + utmp *ut = utmp_data; + while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut) + if ((ut->ut_type == LOGIN_PROCESS || + ut->ut_type == USER_PROCESS) && + !strncmp (ut->ut_line, line->ut_line, sizeof (ut->ut_line))) + return ut; } - - utmp *ut = utmp_data; - while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut) - if ((ut->ut_type == LOGIN_PROCESS || - ut->ut_type == USER_PROCESS) && - !strncmp (ut->ut_line, line->ut_line, sizeof (ut->ut_line))) - return ut; - + __except (EFAULT) {} + __endtry return NULL; } extern "C" struct utmp * pututline (const struct utmp *ut) { - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - internal_setutent (true); - if (utmp_fd < 0) + __try { - debug_printf ("error: utmp_fd %d", utmp_fd); - return NULL; - } - debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n", - ut->ut_type, ut->ut_pid, ut->ut_line, ut->ut_id); - debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n", - ut->ut_user, ut->ut_host); + internal_setutent (true); + if (utmp_fd < 0) + { + debug_printf ("error: utmp_fd %d", utmp_fd); + __leave; + } + debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n", + ut->ut_type, ut->ut_pid, ut->ut_line, ut->ut_id); + debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n", + ut->ut_user, ut->ut_host); - struct utmp *u; - if ((u = getutid (ut))) - { - lseek (utmp_fd, -sizeof *ut, SEEK_CUR); - write (utmp_fd, ut, sizeof *ut); + struct utmp *u; + if ((u = getutid (ut))) + { + lseek (utmp_fd, -sizeof *ut, SEEK_CUR); + write (utmp_fd, ut, sizeof *ut); + } + else + locked_append (utmp_fd, ut, sizeof *ut); + /* The documentation says to return a pointer to this which implies that + this has to be cast from a const. That doesn't seem right but the + documentation seems pretty clear on this. */ + return (struct utmp *) ut; } - else - locked_append (utmp_fd, ut, sizeof *ut); - /* The documentation says to return a pointer to this which implies that - this has to be cast from a const. That doesn't seem right but the - documentation seems pretty clear on this. */ - return (struct utmp *) ut; + __except (EFAULT) {} + __endtry + return NULL; } extern "C" void @@ -4070,7 +4101,7 @@ endutxent () extern "C" struct utmpx * getutxent () { - /* UGH. Not thread safe. */ + /* POSIX: Not required to be thread safe. */ static struct utmpx utx; return copy_ut_to_utx (getutent (), &utx); } @@ -4078,40 +4109,49 @@ getutxent () extern "C" struct utmpx * getutxid (const struct utmpx *id) { - /* UGH. Not thread safe. */ + /* POSIX: Not required to be thread safe. */ static struct utmpx utx; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - ((struct utmpx *)id)->ut_time = id->ut_tv.tv_sec; - return copy_ut_to_utx (getutid ((struct utmp *) id), &utx); + __try + { + ((struct utmpx *)id)->ut_time = id->ut_tv.tv_sec; + return copy_ut_to_utx (getutid ((struct utmp *) id), &utx); + } + __except (EFAULT) {} + __endtry + return NULL; } extern "C" struct utmpx * getutxline (const struct utmpx *line) { - /* UGH. Not thread safe. */ + /* POSIX: Not required to be thread safe. */ static struct utmpx utx; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - ((struct utmpx *)line)->ut_time = line->ut_tv.tv_sec; - return copy_ut_to_utx (getutline ((struct utmp *) line), &utx); + __try + { + ((struct utmpx *)line)->ut_time = line->ut_tv.tv_sec; + return copy_ut_to_utx (getutline ((struct utmp *) line), &utx); + } + __except (EFAULT) {} + __endtry + return NULL; } extern "C" struct utmpx * pututxline (const struct utmpx *utmpx) { - /* UGH. Not thread safe. */ + /* POSIX: Not required to be thread safe. */ static struct utmpx utx; - myfault efault; - if (efault.faulted (EFAULT)) - return NULL; - ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec; - return copy_ut_to_utx (pututline ((struct utmp *) utmpx), &utx); + __try + { + ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec; + return copy_ut_to_utx (pututline ((struct utmp *) utmpx), &utx); + } + __except (EFAULT) {} + __endtry + return NULL; } extern "C" void @@ -4475,51 +4515,57 @@ extern "C" int openat (int dirfd, const char *pathname, int flags, ...) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; - va_list ap; - mode_t mode; + va_list ap; + mode_t mode; - va_start (ap, flags); - mode = va_arg (ap, mode_t); - va_end (ap); - return open (path, flags, mode); + va_start (ap, flags); + mode = va_arg (ap, mode_t); + va_end (ap); + return open (path, flags, mode); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int faccessat (int dirfd, const char *pathname, int mode, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - int res = -1; - char *path = tp.c_get (); - if (!gen_full_path_at (path, dirfd, pathname)) + + __try { - if ((mode & ~(F_OK|R_OK|W_OK|X_OK)) - || (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EACCESS))) - set_errno (EINVAL); - else + char *path = tp.c_get (); + if (!gen_full_path_at (path, dirfd, pathname)) { - fhandler_base *fh = build_fh_name (path, (flags & AT_SYMLINK_NOFOLLOW - ? PC_SYM_NOFOLLOW - : PC_SYM_FOLLOW) - | PC_KEEP_HANDLE, - stat_suffixes); - if (fh) + if ((mode & ~(F_OK|R_OK|W_OK|X_OK)) + || (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EACCESS))) + set_errno (EINVAL); + else { - res = fh->fhaccess (mode, !!(flags & AT_EACCESS)); - delete fh; + fhandler_base *fh = build_fh_name (path, + (flags & AT_SYMLINK_NOFOLLOW + ? PC_SYM_NOFOLLOW + : PC_SYM_FOLLOW) + | PC_KEEP_HANDLE, + stat_suffixes); + if (fh) + { + res = fh->fhaccess (mode, !!(flags & AT_EACCESS)); + delete fh; + } } } } + __except (EFAULT) {} + __endtry debug_printf ("returning %d", res); return res; } @@ -4528,40 +4574,46 @@ extern "C" int fchmodat (int dirfd, const char *pathname, mode_t mode, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags) + __try { - /* BSD has lchmod, but Linux does not. POSIX says - AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks; but Linux - blindly fails even for non-symlinks. */ - set_errno ((flags & ~AT_SYMLINK_NOFOLLOW) ? EINVAL : EOPNOTSUPP); - return -1; + if (flags) + { + /* BSD has lchmod, but Linux does not. POSIX says + AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks; but Linux + blindly fails even for non-symlinks. */ + set_errno ((flags & ~AT_SYMLINK_NOFOLLOW) ? EINVAL : EOPNOTSUPP); + __leave; + } + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return chmod (path, mode); } - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return chmod (path, mode); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int fchownat (int dirfd, const char *pathname, uid_t uid, gid_t gid, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags & ~AT_SYMLINK_NOFOLLOW) + __try { - set_errno (EINVAL); - return -1; + if (flags & ~AT_SYMLINK_NOFOLLOW) + { + set_errno (EINVAL); + __leave; + } + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid); } - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW) - ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -4569,21 +4621,24 @@ fstatat (int dirfd, const char *__restrict pathname, struct stat *__restrict st, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags & ~AT_SYMLINK_NOFOLLOW) + __try { - set_errno (EINVAL); - return -1; + if (flags & ~AT_SYMLINK_NOFOLLOW) + { + set_errno (EINVAL); + __leave; + } + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) + | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes); + return stat_worker (pc, st); } - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW) - ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) - | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes); - return stat_worker (pc, st); + __except (EFAULT) {} + __endtry + return -1; } extern int utimens_worker (path_conv &, const struct timespec *); @@ -4593,34 +4648,40 @@ utimensat (int dirfd, const char *pathname, const struct timespec *times, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (flags & ~AT_SYMLINK_NOFOLLOW) + __try { - set_errno (EINVAL); - return -1; + char *path = tp.c_get (); + if (flags & ~AT_SYMLINK_NOFOLLOW) + { + set_errno (EINVAL); + __leave; + } + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + path_conv win32 (path, PC_POSIX | ((flags & AT_SYMLINK_NOFOLLOW) + ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW), + stat_suffixes); + return utimens_worker (win32, times); } - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - path_conv win32 (path, PC_POSIX | ((flags & AT_SYMLINK_NOFOLLOW) - ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW), - stat_suffixes); - return utimens_worker (win32, times); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int futimesat (int dirfd, const char *pathname, const struct timeval *times) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname, true)) - return -1; - return utimes (path, times); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname, true)) + __leave; + return utimes (path, times); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -4629,70 +4690,82 @@ linkat (int olddirfd, const char *oldpathname, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags & ~AT_SYMLINK_FOLLOW) + __try { - set_errno (EINVAL); - return -1; - } - char *oldpath = tp.c_get (); - if (gen_full_path_at (oldpath, olddirfd, oldpathname)) - return -1; - char *newpath = tp.c_get (); - if (gen_full_path_at (newpath, newdirfd, newpathname)) - return -1; - if (flags & AT_SYMLINK_FOLLOW) - { - path_conv old_name (oldpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); - if (old_name.error) + if (flags & ~AT_SYMLINK_FOLLOW) { - set_errno (old_name.error); - return -1; + set_errno (EINVAL); + __leave; } - strcpy (oldpath, old_name.normalized_path); + char *oldpath = tp.c_get (); + if (gen_full_path_at (oldpath, olddirfd, oldpathname)) + __leave; + char *newpath = tp.c_get (); + if (gen_full_path_at (newpath, newdirfd, newpathname)) + __leave; + if (flags & AT_SYMLINK_FOLLOW) + { + path_conv old_name (oldpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); + if (old_name.error) + { + set_errno (old_name.error); + __leave; + } + strcpy (oldpath, old_name.normalized_path); + } + return link (oldpath, newpath); } - return link (oldpath, newpath); + __except (EFAULT) {} + __endtry + return -1; } extern "C" int mkdirat (int dirfd, const char *pathname, mode_t mode) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return mkdir (path, mode); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return mkdir (path, mode); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int mkfifoat (int dirfd, const char *pathname, mode_t mode) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return mkfifo (path, mode); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return mkfifo (path, mode); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int mknodat (int dirfd, const char *pathname, mode_t mode, dev_t dev) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return mknod32 (path, mode, dev); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return mknod32 (path, mode, dev); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" ssize_t @@ -4700,13 +4773,16 @@ readlinkat (int dirfd, const char *__restrict pathname, char *__restrict buf, size_t bufsize) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return readlink (path, buf, bufsize); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return readlink (path, buf, bufsize); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -4714,16 +4790,19 @@ renameat (int olddirfd, const char *oldpathname, int newdirfd, const char *newpathname) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *oldpath = tp.c_get (); - if (gen_full_path_at (oldpath, olddirfd, oldpathname)) - return -1; - char *newpath = tp.c_get (); - if (gen_full_path_at (newpath, newdirfd, newpathname)) - return -1; - return rename (oldpath, newpath); + __try + { + char *oldpath = tp.c_get (); + if (gen_full_path_at (oldpath, olddirfd, oldpathname)) + __leave; + char *newpath = tp.c_get (); + if (gen_full_path_at (newpath, newdirfd, newpathname)) + __leave; + return rename (oldpath, newpath); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int @@ -4732,42 +4811,51 @@ scandirat (int dirfd, const char *pathname, struct dirent ***namelist, int (*compar) (const struct dirent **, const struct dirent **)) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return scandir (pathname, namelist, select, compar); + __try + { + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return scandir (pathname, namelist, select, compar); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int symlinkat (const char *oldpath, int newdirfd, const char *newpathname) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - char *newpath = tp.c_get (); - if (gen_full_path_at (newpath, newdirfd, newpathname)) - return -1; - return symlink (oldpath, newpath); + __try + { + char *newpath = tp.c_get (); + if (gen_full_path_at (newpath, newdirfd, newpathname)) + __leave; + return symlink (oldpath, newpath); + } + __except (EFAULT) {} + __endtry + return -1; } extern "C" int unlinkat (int dirfd, const char *pathname, int flags) { tmp_pathbuf tp; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (flags & ~AT_REMOVEDIR) + __try { - set_errno (EINVAL); - return -1; + if (flags & ~AT_REMOVEDIR) + { + set_errno (EINVAL); + __leave; + } + char *path = tp.c_get (); + if (gen_full_path_at (path, dirfd, pathname)) + __leave; + return (flags & AT_REMOVEDIR) ? rmdir (path) : unlink (path); } - char *path = tp.c_get (); - if (gen_full_path_at (path, dirfd, pathname)) - return -1; - return (flags & AT_REMOVEDIR) ? rmdir (path) : unlink (path); + __except (EFAULT) {} + __endtry + return -1; } diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index dc4faac7c..2ab47b380 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -1,7 +1,7 @@ /* thread.cc: Locking and threading module functions Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - 2009, 2010, 2011, 2012, 2013 Red Hat, Inc. + 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -122,28 +122,29 @@ __cygwin_lock_unlock (_LOCK_T *lock) paranoid_printf ("threadcount %d. unlocked", MT_INTERFACE->threadcount); } -#if __GNUC__ == 4 && __GNUC_MINOR__ >= 7 -/* FIXME: Temporarily workaround gcc 4.7+ bug. */ -static verifyable_object_state -#else static inline verifyable_object_state -#endif verifyable_object_isvalid (void const *objectptr, thread_magic_t magic, void *static_ptr1, void *static_ptr2, void *static_ptr3) { - myfault efault; - if (efault.faulted (objectptr)) - return INVALID_OBJECT; + verifyable_object_state state = INVALID_OBJECT; - verifyable_object **object = (verifyable_object **) objectptr; + __try + { + if (!objectptr || !(*(const char **) objectptr)) + __leave; - if ((static_ptr1 && *object == static_ptr1) || - (static_ptr2 && *object == static_ptr2) || - (static_ptr3 && *object == static_ptr3)) - return VALID_STATIC_OBJECT; - if ((*object)->magic != magic) - return INVALID_OBJECT; - return VALID_OBJECT; + verifyable_object **object = (verifyable_object **) objectptr; + + if ((static_ptr1 && *object == static_ptr1) || + (static_ptr2 && *object == static_ptr2) || + (static_ptr3 && *object == static_ptr3)) + state = VALID_STATIC_OBJECT; + else if ((*object)->magic == magic) + state = VALID_OBJECT; + } + __except (NO_ERROR) {} + __endtry + return state; } /* static members */ @@ -2684,18 +2685,20 @@ pthread_cond::init (pthread_cond_t *cond, const pthread_condattr_t *attr) return EAGAIN; } - myfault efault; - if (efault.faulted ()) + int ret = 0; + + __try + { + *cond = new_cond; + } + __except (NO_ERROR) { delete new_cond; - cond_initialization_lock.unlock (); - return EINVAL; + ret = EINVAL; } - - *cond = new_cond; + __endtry cond_initialization_lock.unlock (); - - return 0; + return ret; } extern "C" int @@ -2747,45 +2750,47 @@ pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, struct timespec tp; LARGE_INTEGER timeout; - myfault efault; - if (efault.faulted ()) - return EINVAL; - pthread_testcancel (); - int err = __pthread_cond_wait_init (cond, mutex); - if (err) - return err; - - /* According to SUSv3, the abstime value must be checked for validity. */ - if (abstime->tv_sec < 0 - || abstime->tv_nsec < 0 - || abstime->tv_nsec > 999999999) - return EINVAL; - - clock_gettime ((*cond)->clock_id, &tp); - - /* Check for immediate timeout before converting */ - if (tp.tv_sec > abstime->tv_sec - || (tp.tv_sec == abstime->tv_sec - && tp.tv_nsec > abstime->tv_nsec)) - return ETIMEDOUT; - - timeout.QuadPart = abstime->tv_sec * NSPERSEC - + (abstime->tv_nsec + 99LL) / 100LL; - - switch ((*cond)->clock_id) + __try { - case CLOCK_REALTIME: - timeout.QuadPart += FACTOR; - break; - default: - /* other clocks must be handled as relative timeout */ - timeout.QuadPart -= tp.tv_sec * NSPERSEC + tp.tv_nsec / 100LL; - timeout.QuadPart *= -1LL; - break; + int err = __pthread_cond_wait_init (cond, mutex); + if (err) + return err; + + /* According to SUSv3, the abstime value must be checked for validity. */ + if (abstime->tv_sec < 0 + || abstime->tv_nsec < 0 + || abstime->tv_nsec > 999999999) + __leave; + + clock_gettime ((*cond)->clock_id, &tp); + + /* Check for immediate timeout before converting */ + if (tp.tv_sec > abstime->tv_sec + || (tp.tv_sec == abstime->tv_sec + && tp.tv_nsec > abstime->tv_nsec)) + return ETIMEDOUT; + + timeout.QuadPart = abstime->tv_sec * NSPERSEC + + (abstime->tv_nsec + 99LL) / 100LL; + + switch ((*cond)->clock_id) + { + case CLOCK_REALTIME: + timeout.QuadPart += FACTOR; + break; + default: + /* other clocks must be handled as relative timeout */ + timeout.QuadPart -= tp.tv_sec * NSPERSEC + tp.tv_nsec / 100LL; + timeout.QuadPart *= -1LL; + break; + } + return (*cond)->wait (*mutex, &timeout); } - return (*cond)->wait (*mutex, &timeout); + __except (NO_ERROR) {} + __endtry + return EINVAL; } extern "C" int @@ -2910,18 +2915,20 @@ pthread_rwlock::init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr return EAGAIN; } - myfault efault; - if (efault.faulted ()) + int ret = 0; + + __try + { + *rwlock = new_rwlock; + } + __except (NO_ERROR) { delete new_rwlock; - rwlock_initialization_lock.unlock (); - return EINVAL; + ret = EINVAL; } - - *rwlock = new_rwlock; + __endtry rwlock_initialization_lock.unlock (); - - return 0; + return ret; } extern "C" int @@ -3133,15 +3140,17 @@ pthread_mutex::init (pthread_mutex_t *mutex, new_mutex->type = PTHREAD_MUTEX_ERRORCHECK; } - myfault efault; - if (efault.faulted ()) + __try + { + *mutex = new_mutex; + } + __except (NO_ERROR) { delete new_mutex; mutex_initialization_lock.unlock (); return EINVAL; } - - *mutex = new_mutex; + __endtry } mutex_initialization_lock.unlock (); pthread_printf ("*mutex %p, attr %p, initializer %p", *mutex, attr, initializer); @@ -3230,16 +3239,17 @@ pthread_spinlock::init (pthread_spinlock_t *spinlock, int pshared) return EAGAIN; } - myfault efault; - if (efault.faulted ()) + __try + { + *spinlock = new_spinlock; + } + __except (NO_ERROR) { delete new_spinlock; return EINVAL; } - - *spinlock = new_spinlock; + __endtry pthread_printf ("*spinlock %p, pshared %d", *spinlock, pshared); - return 0; } @@ -3502,35 +3512,38 @@ semaphore::_timedwait (const struct timespec *abstime) { LARGE_INTEGER timeout; - myfault efault; - if (efault.faulted ()) + __try + { + timeout.QuadPart = abstime->tv_sec * NSPERSEC + + (abstime->tv_nsec + 99) / 100 + FACTOR; + + switch (cygwait (win32_obj_id, &timeout, cw_cancel | cw_cancel_self | cw_sig_eintr)) + { + case WAIT_OBJECT_0: + break; + case WAIT_SIGNALED: + set_errno (EINTR); + return -1; + case WAIT_TIMEOUT: + set_errno (ETIMEDOUT); + return -1; + default: + pthread_printf ("cygwait failed. %E"); + __seterrno (); + return -1; + } + } + __except (NO_ERROR) { /* According to SUSv3, abstime need not be checked for validity, if the semaphore can be locked immediately. */ - if (!_trywait ()) - return 0; - set_errno (EINVAL); - return -1; - } - - timeout.QuadPart = abstime->tv_sec * NSPERSEC - + (abstime->tv_nsec + 99) / 100 + FACTOR; - - switch (cygwait (win32_obj_id, &timeout, cw_cancel | cw_cancel_self | cw_sig_eintr)) - { - case WAIT_OBJECT_0: - break; - case WAIT_SIGNALED: - set_errno (EINTR); - return -1; - case WAIT_TIMEOUT: - set_errno (ETIMEDOUT); - return -1; - default: - pthread_printf ("cygwait failed. %E"); - __seterrno (); - return -1; + if (_trywait ()) + { + set_errno (EINVAL); + return -1; + } } + __endtry return 0; } @@ -3761,36 +3774,38 @@ semaphore::post (sem_t *sem) int semaphore::getvalue (sem_t *sem, int *sval) { - myfault efault; - if (efault.faulted () || !is_good_object (sem)) + __try { - set_errno (EINVAL); - return -1; + if (is_good_object (sem)) + return (*sem)->_getvalue (sval); } - - return (*sem)->_getvalue (sval); + __except (NO_ERROR) {} + __endtry + set_errno (EINVAL); + return -1; } int semaphore::getinternal (sem_t *sem, int *sfd, unsigned long long *shash, LUID *sluid, unsigned int *sval) { - myfault efault; - if (efault.faulted () || !is_good_object (sem)) + __try { - set_errno (EINVAL); - return -1; + if (!is_good_object (sem)) + __leave; + if ((*sfd = (*sem)->fd) < 0) + __leave; + *shash = (*sem)->hash; + *sluid = (*sem)->luid; + /* POSIX defines the value in calls to sem_init/sem_open as unsigned, + but the sem_getvalue gets a pointer to int to return the value. + Go figure! */ + return (*sem)->_getvalue ((int *)sval); } - if ((*sfd = (*sem)->fd) < 0) - { - set_errno (EINVAL); - return -1; - } - *shash = (*sem)->hash; - *sluid = (*sem)->luid; - /* POSIX defines the value in calls to sem_init/sem_open as unsigned, but - the sem_getvalue gets a pointer to int to return the value. Go figure! */ - return (*sem)->_getvalue ((int *)sval); + __except (NO_ERROR) {} + __endtry + set_errno (EINVAL); + return -1; } /* pthread_null */ diff --git a/winsup/cygwin/timer.cc b/winsup/cygwin/timer.cc index b1c6e27aa..bfa1495f6 100644 --- a/winsup/cygwin/timer.cc +++ b/winsup/cygwin/timer.cc @@ -1,6 +1,6 @@ /* timer.cc - Copyright 2004, 2005, 2006, 2008, 2010, 2011, 2012, 2013 Red Hat, Inc. + Copyright 2004, 2005, 2006, 2008, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -219,45 +219,49 @@ it_bad (const timespec& t) int timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalue) { - if (!value) + int ret = -1; + + __try { - set_errno (EINVAL); - return -1; - } + if (!value) + { + set_errno (EINVAL); + __leave; + } - myfault efault; - if (efault.faulted (EFAULT) - || it_bad (value->it_value) - || it_bad (value->it_interval)) - return -1; + if (it_bad (value->it_value) || it_bad (value->it_interval)) + __leave; - long long now = in_flags & TIMER_ABSTIME ? 0 : gtod.usecs (); + long long now = in_flags & TIMER_ABSTIME ? 0 : gtod.usecs (); - lock_timer_tracker here; - cancel (); + lock_timer_tracker here; + cancel (); - if (ovalue) - gettime (ovalue); + if (ovalue) + gettime (ovalue); - if (!value->it_value.tv_sec && !value->it_value.tv_nsec) - interval_us = sleepto_us = 0; - else - { - sleepto_us = now + to_us (value->it_value); - interval_us = to_us (value->it_interval); - it_interval = value->it_interval; - if (!hcancel) - hcancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + if (!value->it_value.tv_sec && !value->it_value.tv_nsec) + interval_us = sleepto_us = 0; else - ResetEvent (hcancel); - if (!syncthread) - syncthread = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); - else - ResetEvent (syncthread); - new cygthread (timer_thread, this, "itimer", syncthread); + { + sleepto_us = now + to_us (value->it_value); + interval_us = to_us (value->it_interval); + it_interval = value->it_interval; + if (!hcancel) + hcancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + else + ResetEvent (hcancel); + if (!syncthread) + syncthread = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + else + ResetEvent (syncthread); + new cygthread (timer_thread, this, "itimer", syncthread); + } + ret = 0; } - - return 0; + __except (EFAULT) {} + __endtry + return ret; } void @@ -280,43 +284,51 @@ timer_tracker::gettime (itimerspec *ovalue) extern "C" int timer_gettime (timer_t timerid, struct itimerspec *ovalue) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; + int ret = -1; - timer_tracker *tt = (timer_tracker *) timerid; - if (tt->magic != TT_MAGIC) + __try { - set_errno (EINVAL); - return -1; - } + timer_tracker *tt = (timer_tracker *) timerid; + if (tt->magic != TT_MAGIC) + { + set_errno (EINVAL); + return -1; + } - tt->gettime (ovalue); - return 0; + tt->gettime (ovalue); + ret = 0; + } + __except (EFAULT) {} + __endtry + return ret; } extern "C" int timer_create (clockid_t clock_id, struct sigevent *__restrict evp, timer_t *__restrict timerid) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; + int ret = -1; - if (CLOCKID_IS_PROCESS (clock_id) || CLOCKID_IS_THREAD (clock_id)) + __try { - set_errno (ENOTSUP); - return -1; - } + if (CLOCKID_IS_PROCESS (clock_id) || CLOCKID_IS_THREAD (clock_id)) + { + set_errno (ENOTSUP); + return -1; + } - if (clock_id != CLOCK_REALTIME) - { - set_errno (EINVAL); - return -1; - } + if (clock_id != CLOCK_REALTIME) + { + set_errno (EINVAL); + return -1; + } - *timerid = (timer_t) new timer_tracker (clock_id, evp); - return 0; + *timerid = (timer_t) new timer_tracker (clock_id, evp); + ret = 0; + } + __except (EFAULT) {} + __endtry + return ret; } extern "C" int @@ -324,42 +336,52 @@ timer_settime (timer_t timerid, int flags, const struct itimerspec *__restrict value, struct itimerspec *__restrict ovalue) { - timer_tracker *tt = (timer_tracker *) timerid; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (tt->magic != TT_MAGIC) - { - set_errno (EINVAL); - return -1; - } + int ret = -1; - return tt->settime (flags, value, ovalue); + __try + { + timer_tracker *tt = (timer_tracker *) timerid; + if (tt->magic != TT_MAGIC) + { + set_errno (EINVAL); + __leave; + } + ret = tt->settime (flags, value, ovalue); + } + __except (EFAULT) {} + __endtry + return ret; } extern "C" int timer_delete (timer_t timerid) { - timer_tracker *in_tt = (timer_tracker *) timerid; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (in_tt->magic != TT_MAGIC) - { - set_errno (EINVAL); - return -1; - } + int ret = -1; - lock_timer_tracker here; - for (timer_tracker *tt = &ttstart; tt->next != NULL; tt = tt->next) - if (tt->next == in_tt) - { - tt->next = in_tt->next; - delete in_tt; - return 0; - } - set_errno (EINVAL); - return 0; + __try + { + timer_tracker *in_tt = (timer_tracker *) timerid; + if (in_tt->magic != TT_MAGIC) + { + set_errno (EINVAL); + __leave; + } + + lock_timer_tracker here; + for (timer_tracker *tt = &ttstart; tt->next != NULL; tt = tt->next) + if (tt->next == in_tt) + { + tt->next = in_tt->next; + delete in_tt; + ret = 0; + __leave; + } + set_errno (EINVAL); + ret = 0; + } + __except (EFAULT) {} + __endtry + return ret; } void @@ -412,18 +434,13 @@ setitimer (int which, const struct itimerval *__restrict value, extern "C" int getitimer (int which, struct itimerval *ovalue) { - int ret; + int ret = -1; + if (which != ITIMER_REAL) - { - set_errno (EINVAL); - ret = -1; - } + set_errno (EINVAL); else { - myfault efault; - if (efault.faulted (EFAULT)) - ret = -1; - else + __try { struct itimerspec spec_ovalue; ret = timer_gettime ((timer_t) &ttstart, &spec_ovalue); @@ -435,6 +452,8 @@ getitimer (int which, struct itimerval *ovalue) ovalue->it_value.tv_usec = spec_ovalue.it_value.tv_nsec / 1000; } } + __except (EFAULT) {} + __endtry } syscall_printf ("%R = getitimer()", ret); return ret; diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 55157d389..cbff13c77 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -1,7 +1,7 @@ /* times.cc Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, - 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc. + 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc. This file is part of Cygwin. @@ -59,35 +59,39 @@ __to_clock_t (PLARGE_INTEGER src, int flag) extern "C" clock_t times (struct tms *buf) { - myfault efault; - if (efault.faulted (EFAULT)) - return ((clock_t) -1); - static SYSTEM_TIMEOFDAY_INFORMATION stodi; KERNEL_USER_TIMES kut; LARGE_INTEGER ticks; + clock_t tc = (clock_t) -1; - /* Fetch boot time if we haven't already. */ - if (!stodi.BootTime.QuadPart) - NtQuerySystemInformation (SystemTimeOfDayInformation, - &stodi, sizeof stodi, NULL); + __try + { + /* Fetch boot time if we haven't already. */ + if (!stodi.BootTime.QuadPart) + NtQuerySystemInformation (SystemTimeOfDayInformation, + &stodi, sizeof stodi, NULL); - NtQueryInformationProcess (NtCurrentProcess (), ProcessTimes, - &kut, sizeof kut, NULL); - get_system_time (&ticks); + NtQueryInformationProcess (NtCurrentProcess (), ProcessTimes, + &kut, sizeof kut, NULL); + get_system_time (&ticks); - /* uptime */ - ticks.QuadPart -= stodi.BootTime.QuadPart; - /* ticks is in in 100ns, convert to clock ticks. */ - clock_t tc = (clock_t) (ticks.QuadPart * CLOCKS_PER_SEC / NSPERSEC); - - buf->tms_stime = __to_clock_t (&kut.KernelTime, 0); - buf->tms_utime = __to_clock_t (&kut.UserTime, 0); - timeval_to_filetime (&myself->rusage_children.ru_stime, &kut.KernelTime); - buf->tms_cstime = __to_clock_t (&kut.KernelTime, 1); - timeval_to_filetime (&myself->rusage_children.ru_utime, &kut.UserTime); - buf->tms_cutime = __to_clock_t (&kut.UserTime, 1); + /* uptime */ + ticks.QuadPart -= stodi.BootTime.QuadPart; + /* ticks is in in 100ns, convert to clock ticks. */ + tc = (clock_t) (ticks.QuadPart * CLOCKS_PER_SEC / NSPERSEC); + buf->tms_stime = __to_clock_t (&kut.KernelTime, 0); + buf->tms_utime = __to_clock_t (&kut.UserTime, 0); + timeval_to_filetime (&myself->rusage_children.ru_stime, &kut.KernelTime); + buf->tms_cstime = __to_clock_t (&kut.KernelTime, 1); + timeval_to_filetime (&myself->rusage_children.ru_utime, &kut.UserTime); + buf->tms_cutime = __to_clock_t (&kut.UserTime, 1); + } + __except (EFAULT) + { + tc = (clock_t) -1; + } + __endtry syscall_printf ("%D = times(%p)", tc, buf); return tc; } @@ -100,34 +104,37 @@ settimeofday (const struct timeval *tv, const struct timezone *tz) { SYSTEMTIME st; struct tm *ptm; - int res; + int res = -1; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - if (tv->tv_usec < 0 || tv->tv_usec >= 1000000) + __try { - set_errno (EINVAL); - return -1; + if (tv->tv_usec < 0 || tv->tv_usec >= 1000000) + { + set_errno (EINVAL); + return -1; + } + + ptm = gmtime (&tv->tv_sec); + st.wYear = ptm->tm_year + 1900; + st.wMonth = ptm->tm_mon + 1; + st.wDayOfWeek = ptm->tm_wday; + st.wDay = ptm->tm_mday; + st.wHour = ptm->tm_hour; + st.wMinute = ptm->tm_min; + st.wSecond = ptm->tm_sec; + st.wMilliseconds = tv->tv_usec / 1000; + + res = -!SetSystemTime (&st); + gtod.reset (); + + if (res) + set_errno (EPERM); } - - ptm = gmtime (&tv->tv_sec); - st.wYear = ptm->tm_year + 1900; - st.wMonth = ptm->tm_mon + 1; - st.wDayOfWeek = ptm->tm_wday; - st.wDay = ptm->tm_mday; - st.wHour = ptm->tm_hour; - st.wMinute = ptm->tm_min; - st.wSecond = ptm->tm_sec; - st.wMilliseconds = tv->tv_usec / 1000; - - res = -!SetSystemTime (&st); - gtod.reset (); - - if (res) - set_errno (EPERM); - + __except (EFAULT) + { + res = -1; + } + __endtry syscall_printf ("%R = settimeofday(%p, %p)", res, tv, tz); return res; } diff --git a/winsup/cygwin/tls_pbuf.cc b/winsup/cygwin/tls_pbuf.cc index c48ca5853..e4f522344 100644 --- a/winsup/cygwin/tls_pbuf.cc +++ b/winsup/cygwin/tls_pbuf.cc @@ -8,17 +8,16 @@ details. */ #include #include -#include "cygtls.h" #include "tls_pbuf.h" -#define tls_pbuf _my_tls.locals.pathbufs +#define tls_pbuf _my_tls.pathbufs void tls_pathbuf::destroy () { - for (unsigned i = 0; i < TP_NUM_C_BUFS && c_buf[i]; ++i) + for (uint32_t i = 0; i < TP_NUM_C_BUFS && c_buf[i]; ++i) free (c_buf[i]); - for (unsigned i = 0; i < TP_NUM_W_BUFS && w_buf[i]; ++i) + for (uint32_t i = 0; i < TP_NUM_W_BUFS && w_buf[i]; ++i) free (w_buf[i]); } diff --git a/winsup/cygwin/tls_pbuf.h b/winsup/cygwin/tls_pbuf.h index e98fd60b8..3a94017a1 100644 --- a/winsup/cygwin/tls_pbuf.h +++ b/winsup/cygwin/tls_pbuf.h @@ -10,20 +10,20 @@ details. */ class tmp_pathbuf { - unsigned c_buf_old; - unsigned w_buf_old; + uint32_t c_buf_old; + uint32_t w_buf_old; public: tmp_pathbuf () __attribute__ ((always_inline)) - : c_buf_old (_my_tls.locals.pathbufs.c_cnt), - w_buf_old (_my_tls.locals.pathbufs.w_cnt) + : c_buf_old (_my_tls.pathbufs.c_cnt), + w_buf_old (_my_tls.pathbufs.w_cnt) {} ~tmp_pathbuf () __attribute__ ((always_inline)) { - _my_tls.locals.pathbufs.c_cnt = c_buf_old; - _my_tls.locals.pathbufs.w_cnt = w_buf_old; + _my_tls.pathbufs.c_cnt = c_buf_old; + _my_tls.pathbufs.w_cnt = w_buf_old; } - inline bool check_usage (unsigned c_need, unsigned w_need) + inline bool check_usage (uint32_t c_need, uint32_t w_need) { return c_need + c_buf_old < TP_NUM_C_BUFS && w_need + w_buf_old < TP_NUM_W_BUFS; diff --git a/winsup/cygwin/tlsoffsets.h b/winsup/cygwin/tlsoffsets.h index 572dfb7b7..308da2d78 100644 --- a/winsup/cygwin/tlsoffsets.h +++ b/winsup/cygwin/tlsoffsets.h @@ -3,44 +3,46 @@ //; $tls::start_offset = -12700; //; $tls::locals = -12700; //; $tls::plocals = 0; -//; $tls::local_clib = -10980; -//; $tls::plocal_clib = 1720; -//; $tls::__dontuse = -10980; -//; $tls::p__dontuse = 1720; -//; $tls::func = -9892; -//; $tls::pfunc = 2808; -//; $tls::saved_errno = -9888; -//; $tls::psaved_errno = 2812; -//; $tls::sa_flags = -9884; -//; $tls::psa_flags = 2816; -//; $tls::oldmask = -9880; -//; $tls::poldmask = 2820; -//; $tls::deltamask = -9876; -//; $tls::pdeltamask = 2824; -//; $tls::errno_addr = -9872; -//; $tls::perrno_addr = 2828; -//; $tls::sigmask = -9868; -//; $tls::psigmask = 2832; -//; $tls::sigwait_mask = -9864; -//; $tls::psigwait_mask = 2836; -//; $tls::sigwait_info = -9860; -//; $tls::psigwait_info = 2840; -//; $tls::signal_arrived = -9856; -//; $tls::psignal_arrived = 2844; -//; $tls::will_wait_for_signal = -9852; -//; $tls::pwill_wait_for_signal = 2848; -//; $tls::thread_context = -9848; -//; $tls::pthread_context = 2852; -//; $tls::thread_id = -9636; -//; $tls::pthread_id = 3064; -//; $tls::infodata = -9632; -//; $tls::pinfodata = 3068; -//; $tls::tid = -9484; -//; $tls::ptid = 3216; -//; $tls::_ctinfo = -9480; -//; $tls::p_ctinfo = 3220; -//; $tls::andreas = -9476; -//; $tls::pandreas = 3224; +//; $tls::local_clib = -11388; +//; $tls::plocal_clib = 1312; +//; $tls::__dontuse = -11388; +//; $tls::p__dontuse = 1312; +//; $tls::func = -10300; +//; $tls::pfunc = 2400; +//; $tls::saved_errno = -10296; +//; $tls::psaved_errno = 2404; +//; $tls::sa_flags = -10292; +//; $tls::psa_flags = 2408; +//; $tls::oldmask = -10288; +//; $tls::poldmask = 2412; +//; $tls::deltamask = -10284; +//; $tls::pdeltamask = 2416; +//; $tls::errno_addr = -10280; +//; $tls::perrno_addr = 2420; +//; $tls::sigmask = -10276; +//; $tls::psigmask = 2424; +//; $tls::sigwait_mask = -10272; +//; $tls::psigwait_mask = 2428; +//; $tls::sigwait_info = -10268; +//; $tls::psigwait_info = 2432; +//; $tls::signal_arrived = -10264; +//; $tls::psignal_arrived = 2436; +//; $tls::will_wait_for_signal = -10260; +//; $tls::pwill_wait_for_signal = 2440; +//; $tls::thread_context = -10256; +//; $tls::pthread_context = 2444; +//; $tls::thread_id = -10044; +//; $tls::pthread_id = 2656; +//; $tls::infodata = -10040; +//; $tls::pinfodata = 2660; +//; $tls::tid = -9892; +//; $tls::ptid = 2808; +//; $tls::_ctinfo = -9888; +//; $tls::p_ctinfo = 2812; +//; $tls::andreas = -9884; +//; $tls::pandreas = 2816; +//; $tls::pathbufs = -9880; +//; $tls::ppathbufs = 2820; //; $tls::wq = -9472; //; $tls::pwq = 3228; //; $tls::sig = -9444; @@ -61,44 +63,46 @@ #define tls_locals (-12700) #define tls_plocals (0) -#define tls_local_clib (-10980) -#define tls_plocal_clib (1720) -#define tls___dontuse (-10980) -#define tls_p__dontuse (1720) -#define tls_func (-9892) -#define tls_pfunc (2808) -#define tls_saved_errno (-9888) -#define tls_psaved_errno (2812) -#define tls_sa_flags (-9884) -#define tls_psa_flags (2816) -#define tls_oldmask (-9880) -#define tls_poldmask (2820) -#define tls_deltamask (-9876) -#define tls_pdeltamask (2824) -#define tls_errno_addr (-9872) -#define tls_perrno_addr (2828) -#define tls_sigmask (-9868) -#define tls_psigmask (2832) -#define tls_sigwait_mask (-9864) -#define tls_psigwait_mask (2836) -#define tls_sigwait_info (-9860) -#define tls_psigwait_info (2840) -#define tls_signal_arrived (-9856) -#define tls_psignal_arrived (2844) -#define tls_will_wait_for_signal (-9852) -#define tls_pwill_wait_for_signal (2848) -#define tls_thread_context (-9848) -#define tls_pthread_context (2852) -#define tls_thread_id (-9636) -#define tls_pthread_id (3064) -#define tls_infodata (-9632) -#define tls_pinfodata (3068) -#define tls_tid (-9484) -#define tls_ptid (3216) -#define tls__ctinfo (-9480) -#define tls_p_ctinfo (3220) -#define tls_andreas (-9476) -#define tls_pandreas (3224) +#define tls_local_clib (-11388) +#define tls_plocal_clib (1312) +#define tls___dontuse (-11388) +#define tls_p__dontuse (1312) +#define tls_func (-10300) +#define tls_pfunc (2400) +#define tls_saved_errno (-10296) +#define tls_psaved_errno (2404) +#define tls_sa_flags (-10292) +#define tls_psa_flags (2408) +#define tls_oldmask (-10288) +#define tls_poldmask (2412) +#define tls_deltamask (-10284) +#define tls_pdeltamask (2416) +#define tls_errno_addr (-10280) +#define tls_perrno_addr (2420) +#define tls_sigmask (-10276) +#define tls_psigmask (2424) +#define tls_sigwait_mask (-10272) +#define tls_psigwait_mask (2428) +#define tls_sigwait_info (-10268) +#define tls_psigwait_info (2432) +#define tls_signal_arrived (-10264) +#define tls_psignal_arrived (2436) +#define tls_will_wait_for_signal (-10260) +#define tls_pwill_wait_for_signal (2440) +#define tls_thread_context (-10256) +#define tls_pthread_context (2444) +#define tls_thread_id (-10044) +#define tls_pthread_id (2656) +#define tls_infodata (-10040) +#define tls_pinfodata (2660) +#define tls_tid (-9892) +#define tls_ptid (2808) +#define tls__ctinfo (-9888) +#define tls_p_ctinfo (2812) +#define tls_andreas (-9884) +#define tls_pandreas (2816) +#define tls_pathbufs (-9880) +#define tls_ppathbufs (2820) #define tls_wq (-9472) #define tls_pwq (3228) #define tls_sig (-9444) diff --git a/winsup/cygwin/tlsoffsets64.h b/winsup/cygwin/tlsoffsets64.h index 991280663..f91a0bf3d 100644 --- a/winsup/cygwin/tlsoffsets64.h +++ b/winsup/cygwin/tlsoffsets64.h @@ -3,44 +3,46 @@ //; $tls::start_offset = -12800; //; $tls::locals = -12800; //; $tls::plocals = 0; -//; $tls::local_clib = -10624; -//; $tls::plocal_clib = 2176; -//; $tls::__dontuse = -10624; -//; $tls::p__dontuse = 2176; -//; $tls::func = -8736; -//; $tls::pfunc = 4064; -//; $tls::saved_errno = -8728; -//; $tls::psaved_errno = 4072; -//; $tls::sa_flags = -8724; -//; $tls::psa_flags = 4076; -//; $tls::oldmask = -8720; -//; $tls::poldmask = 4080; -//; $tls::deltamask = -8712; -//; $tls::pdeltamask = 4088; -//; $tls::errno_addr = -8704; -//; $tls::perrno_addr = 4096; -//; $tls::sigmask = -8696; -//; $tls::psigmask = 4104; -//; $tls::sigwait_mask = -8688; -//; $tls::psigwait_mask = 4112; -//; $tls::sigwait_info = -8680; -//; $tls::psigwait_info = 4120; -//; $tls::signal_arrived = -8672; -//; $tls::psignal_arrived = 4128; -//; $tls::will_wait_for_signal = -8664; -//; $tls::pwill_wait_for_signal = 4136; -//; $tls::thread_context = -8656; -//; $tls::pthread_context = 4144; -//; $tls::thread_id = -7824; -//; $tls::pthread_id = 4976; -//; $tls::infodata = -7820; -//; $tls::pinfodata = 4980; -//; $tls::tid = -7672; -//; $tls::ptid = 5128; -//; $tls::_ctinfo = -7664; -//; $tls::p_ctinfo = 5136; -//; $tls::andreas = -7656; -//; $tls::pandreas = 5144; +//; $tls::local_clib = -11432; +//; $tls::plocal_clib = 1368; +//; $tls::__dontuse = -11432; +//; $tls::p__dontuse = 1368; +//; $tls::func = -9544; +//; $tls::pfunc = 3256; +//; $tls::saved_errno = -9536; +//; $tls::psaved_errno = 3264; +//; $tls::sa_flags = -9532; +//; $tls::psa_flags = 3268; +//; $tls::oldmask = -9528; +//; $tls::poldmask = 3272; +//; $tls::deltamask = -9520; +//; $tls::pdeltamask = 3280; +//; $tls::errno_addr = -9512; +//; $tls::perrno_addr = 3288; +//; $tls::sigmask = -9504; +//; $tls::psigmask = 3296; +//; $tls::sigwait_mask = -9496; +//; $tls::psigwait_mask = 3304; +//; $tls::sigwait_info = -9488; +//; $tls::psigwait_info = 3312; +//; $tls::signal_arrived = -9480; +//; $tls::psignal_arrived = 3320; +//; $tls::will_wait_for_signal = -9472; +//; $tls::pwill_wait_for_signal = 3328; +//; $tls::thread_context = -9464; +//; $tls::pthread_context = 3336; +//; $tls::thread_id = -8632; +//; $tls::pthread_id = 4168; +//; $tls::infodata = -8628; +//; $tls::pinfodata = 4172; +//; $tls::tid = -8480; +//; $tls::ptid = 4320; +//; $tls::_ctinfo = -8472; +//; $tls::p_ctinfo = 4328; +//; $tls::andreas = -8464; +//; $tls::pandreas = 4336; +//; $tls::pathbufs = -8456; +//; $tls::ppathbufs = 4344; //; $tls::wq = -7648; //; $tls::pwq = 5152; //; $tls::sig = -7600; @@ -61,44 +63,46 @@ #define tls_locals (-12800) #define tls_plocals (0) -#define tls_local_clib (-10624) -#define tls_plocal_clib (2176) -#define tls___dontuse (-10624) -#define tls_p__dontuse (2176) -#define tls_func (-8736) -#define tls_pfunc (4064) -#define tls_saved_errno (-8728) -#define tls_psaved_errno (4072) -#define tls_sa_flags (-8724) -#define tls_psa_flags (4076) -#define tls_oldmask (-8720) -#define tls_poldmask (4080) -#define tls_deltamask (-8712) -#define tls_pdeltamask (4088) -#define tls_errno_addr (-8704) -#define tls_perrno_addr (4096) -#define tls_sigmask (-8696) -#define tls_psigmask (4104) -#define tls_sigwait_mask (-8688) -#define tls_psigwait_mask (4112) -#define tls_sigwait_info (-8680) -#define tls_psigwait_info (4120) -#define tls_signal_arrived (-8672) -#define tls_psignal_arrived (4128) -#define tls_will_wait_for_signal (-8664) -#define tls_pwill_wait_for_signal (4136) -#define tls_thread_context (-8656) -#define tls_pthread_context (4144) -#define tls_thread_id (-7824) -#define tls_pthread_id (4976) -#define tls_infodata (-7820) -#define tls_pinfodata (4980) -#define tls_tid (-7672) -#define tls_ptid (5128) -#define tls__ctinfo (-7664) -#define tls_p_ctinfo (5136) -#define tls_andreas (-7656) -#define tls_pandreas (5144) +#define tls_local_clib (-11432) +#define tls_plocal_clib (1368) +#define tls___dontuse (-11432) +#define tls_p__dontuse (1368) +#define tls_func (-9544) +#define tls_pfunc (3256) +#define tls_saved_errno (-9536) +#define tls_psaved_errno (3264) +#define tls_sa_flags (-9532) +#define tls_psa_flags (3268) +#define tls_oldmask (-9528) +#define tls_poldmask (3272) +#define tls_deltamask (-9520) +#define tls_pdeltamask (3280) +#define tls_errno_addr (-9512) +#define tls_perrno_addr (3288) +#define tls_sigmask (-9504) +#define tls_psigmask (3296) +#define tls_sigwait_mask (-9496) +#define tls_psigwait_mask (3304) +#define tls_sigwait_info (-9488) +#define tls_psigwait_info (3312) +#define tls_signal_arrived (-9480) +#define tls_psignal_arrived (3320) +#define tls_will_wait_for_signal (-9472) +#define tls_pwill_wait_for_signal (3328) +#define tls_thread_context (-9464) +#define tls_pthread_context (3336) +#define tls_thread_id (-8632) +#define tls_pthread_id (4168) +#define tls_infodata (-8628) +#define tls_pinfodata (4172) +#define tls_tid (-8480) +#define tls_ptid (4320) +#define tls__ctinfo (-8472) +#define tls_p_ctinfo (4328) +#define tls_andreas (-8464) +#define tls_pandreas (4336) +#define tls_pathbufs (-8456) +#define tls_ppathbufs (4344) #define tls_wq (-7648) #define tls_pwq (5152) #define tls_sig (-7600) diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index ca764269a..732dea836 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -217,10 +217,15 @@ getlogin_r (char *name, size_t namesize) size_t len = strlen (login) + 1; if (len > namesize) return ERANGE; - myfault efault; - if (efault.faulted ()) - return EFAULT; - strncpy (name, login, len); + __try + { + strncpy (name, login, len); + } + __except (NO_ERROR) + { + return EFAULT; + } + __endtry return 0; } diff --git a/winsup/cygwin/uname.cc b/winsup/cygwin/uname.cc index c571850b4..b586e6374 100644 --- a/winsup/cygwin/uname.cc +++ b/winsup/cygwin/uname.cc @@ -1,7 +1,7 @@ /* uname.cc Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, - 2006, 2007, 2008, 2013 Red Hat, Inc. + 2006, 2007, 2008, 2013, 2014 Red Hat, Inc. Written by Steve Chamberlain of Cygnus Support, sac@cygnus.com Rewritten by Geoffrey Noer of Cygnus Solutions, noer@cygnus.com @@ -22,74 +22,77 @@ uname (struct utsname *name) { SYSTEM_INFO sysinfo; - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - - char *snp = strstr (cygwin_version.dll_build_date, "SNP"); - - memset (name, 0, sizeof (*name)); - __small_sprintf (name->sysname, "CYGWIN_%s", wincap.osname ()); - - /* Add a hint to the sysname, that we're running under WOW64. This might - give an early clue if somebody encounters problems. */ - if (wincap.is_wow64 ()) - strncat (name->sysname, "-WOW64", - sizeof name->sysname - strlen (name->sysname) - 1); - - GetSystemInfo (&sysinfo); - - /* Computer name */ - cygwin_gethostname (name->nodename, sizeof (name->nodename) - 1); - - /* Cygwin dll release */ - __small_sprintf (name->release, "%d.%d.%d%s(%d.%d/%d/%d)", - cygwin_version.dll_major / 1000, - cygwin_version.dll_major % 1000, - cygwin_version.dll_minor, - snp ? "s" : "", - cygwin_version.api_major, - cygwin_version.api_minor, - cygwin_version.shared_data, - cygwin_version.mount_registry); - - /* Cygwin "version" aka build date */ - strcpy (name->version, cygwin_version.dll_build_date); - if (snp) - name->version[snp - cygwin_version.dll_build_date] = '\0'; - - /* CPU type */ - switch (sysinfo.wProcessorArchitecture) + __try { - case PROCESSOR_ARCHITECTURE_INTEL: - unsigned int ptype; - if (sysinfo.wProcessorLevel < 3) /* Shouldn't happen. */ - ptype = 3; - else if (sysinfo.wProcessorLevel > 9) /* P4 */ - ptype = 6; - else - ptype = sysinfo.wProcessorLevel; - __small_sprintf (name->machine, "i%d86", ptype); - break; - case PROCESSOR_ARCHITECTURE_IA64: - strcpy (name->machine, "ia64"); - break; - case PROCESSOR_ARCHITECTURE_AMD64: - strcpy (name->machine, "x86_64"); - break; - case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: - strcpy (name->machine, "ia32-win64"); - break; - case PROCESSOR_ARCHITECTURE_ALPHA: - strcpy (name->machine, "alpha"); - break; - case PROCESSOR_ARCHITECTURE_MIPS: - strcpy (name->machine, "mips"); - break; - default: - strcpy (name->machine, "unknown"); - break; - } + char *snp = strstr (cygwin_version.dll_build_date, "SNP"); + memset (name, 0, sizeof (*name)); + __small_sprintf (name->sysname, "CYGWIN_%s", wincap.osname ()); + + /* Add a hint to the sysname, that we're running under WOW64. This might + give an early clue if somebody encounters problems. */ + if (wincap.is_wow64 ()) + strncat (name->sysname, "-WOW64", + sizeof name->sysname - strlen (name->sysname) - 1); + + GetSystemInfo (&sysinfo); + + /* Computer name */ + cygwin_gethostname (name->nodename, sizeof (name->nodename) - 1); + + /* Cygwin dll release */ + __small_sprintf (name->release, "%d.%d.%d%s(%d.%d/%d/%d)", + cygwin_version.dll_major / 1000, + cygwin_version.dll_major % 1000, + cygwin_version.dll_minor, + snp ? "s" : "", + cygwin_version.api_major, + cygwin_version.api_minor, + cygwin_version.shared_data, + cygwin_version.mount_registry); + + /* Cygwin "version" aka build date */ + strcpy (name->version, cygwin_version.dll_build_date); + if (snp) + name->version[snp - cygwin_version.dll_build_date] = '\0'; + + /* CPU type */ + switch (sysinfo.wProcessorArchitecture) + { + case PROCESSOR_ARCHITECTURE_INTEL: + unsigned int ptype; + if (sysinfo.wProcessorLevel < 3) /* Shouldn't happen. */ + ptype = 3; + else if (sysinfo.wProcessorLevel > 9) /* P4 */ + ptype = 6; + else + ptype = sysinfo.wProcessorLevel; + __small_sprintf (name->machine, "i%d86", ptype); + break; + case PROCESSOR_ARCHITECTURE_IA64: + strcpy (name->machine, "ia64"); + break; + case PROCESSOR_ARCHITECTURE_AMD64: + strcpy (name->machine, "x86_64"); + break; + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: + strcpy (name->machine, "ia32-win64"); + break; + case PROCESSOR_ARCHITECTURE_ALPHA: + strcpy (name->machine, "alpha"); + break; + case PROCESSOR_ARCHITECTURE_MIPS: + strcpy (name->machine, "mips"); + break; + default: + strcpy (name->machine, "unknown"); + break; + } + } + __except (EFAULT) + { + return -1; + } + __endtry return 0; }