diff options
Diffstat (limited to 'winsup/cygwin/syscalls.cc')
-rw-r--r-- | winsup/cygwin/syscalls.cc | 1547 |
1 files changed, 779 insertions, 768 deletions
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index f4e53db50..167e9c0f9 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1,6 +1,6 @@ /* syscalls.cc: syscalls - Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc. + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. This file is part of Cygwin. @@ -11,7 +11,6 @@ details. */ #include "winsup.h" #include <sys/stat.h> #include <sys/vfs.h> /* needed for statfs */ -#include <fcntl.h> #include <pwd.h> #include <grp.h> #include <stdlib.h> @@ -32,14 +31,14 @@ details. */ #include "fhandler.h" #include "path.h" #include "dtable.h" -#include "sync.h" #include "sigproc.h" #include "pinfo.h" #include <unistd.h> #include "shared_info.h" #include "cygheap.h" - -extern int normalize_posix_path (const char *, char *); +#define NEED_VFORK +#include <setjmp.h> +#include "perthread.h" SYSTEM_INFO system_info; @@ -65,33 +64,27 @@ close_all_files (void) cygwin_shared->delqueue.process_queue (); } -static BOOL __stdcall -check_ttys_fds (void) +BOOL __stdcall +check_pty_fds (void) { int res = FALSE; - SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "close_all_files"); + SetResourceLock (LOCK_FD_LIST, WRITE_LOCK, "check_pty_fds"); fhandler_base *fh; for (int i = 0; i < (int) cygheap->fdtab.size; i++) - if ((fh = cygheap->fdtab[i]) != NULL && fh->get_device() == FH_TTYS) + if ((fh = cygheap->fdtab[i]) != NULL && + (fh->get_device () == FH_TTYS || fh->get_device () == FH_PTYM)) { res = TRUE; break; } - ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "close_all_files"); + ReleaseResourceLock (LOCK_FD_LIST, WRITE_LOCK, "check_pty_fds"); return res; } int dup (int fd) { - int res; - SetResourceLock (LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup"); - - res = dup2 (fd, cygheap->fdtab.find_unused_handle ()); - - ReleaseResourceLock(LOCK_FD_LIST, WRITE_LOCK | READ_LOCK, "dup"); - - return res; + return cygheap->fdtab.dup2 (fd, cygheap_fdnew ()); } int @@ -104,6 +97,7 @@ extern "C" int _unlink (const char *ourname) { int res = -1; + DWORD devn; sigframe thisframe (mainthread); path_conv win32_name (ourname, PC_SYM_NOFOLLOW | PC_FULL); @@ -114,6 +108,13 @@ _unlink (const char *ourname) goto done; } + if ((devn = win32_name.get_devn ()) == FH_PROC || devn == FH_REGISTRY + || devn == FH_PROCESS) + { + set_errno (EROFS); + goto done; + } + syscall_printf ("_unlink (%s)", win32_name.get_win32 ()); if (!win32_name.exists ()) @@ -185,7 +186,7 @@ _unlink (const char *ourname) bool delete_on_close_ok; delete_on_close_ok = !win32_name.isremote () - && wincap.has_delete_on_close (); + && wincap.has_delete_on_close (); /* Attempt to use "delete on close" semantics to handle removing a file which may be open. */ @@ -203,7 +204,8 @@ _unlink (const char *ourname) syscall_printf ("CreateFile/CloseHandle succeeded"); /* Everything is fine if the file has disappeared or if we know that the FILE_FLAG_DELETE_ON_CLOSE will eventually work. */ - if (GetFileAttributes (win32_name) == (DWORD) -1 || delete_on_close_ok) + if (GetFileAttributes (win32_name) == INVALID_FILE_ATTRIBUTES + || delete_on_close_ok) goto ok; /* The file is either gone already or will eventually be deleted by the OS. */ } @@ -266,11 +268,24 @@ getppid () extern "C" pid_t setsid (void) { - if (myself->pgid != _getpid ()) + vfork_save *vf = vfork_storage.val (); + /* This is a horrible, horrible kludge */ + if (vf && vf->pid < 0) { - if (myself->ctty == TTY_CONSOLE && - !cygheap->fdtab.has_console_fds () && - !check_ttys_fds ()) + pid_t pid = fork (); + if (pid > 0) + { + syscall_printf ("longjmping due to vfork"); + vf->restore_pid (pid); + } + /* assuming that fork was successful */ + } + + if (myself->pgid != myself->pid) + { + if (myself->ctty == TTY_CONSOLE + && !cygheap->fdtab.has_console_fds () + && !check_pty_fds ()) FreeConsole (); myself->ctty = -1; myself->sid = _getpid (); @@ -278,54 +293,124 @@ setsid (void) syscall_printf ("sid %d, pgid %d, ctty %d", myself->sid, myself->pgid, myself->ctty); return myself->sid; } + set_errno (EPERM); return -1; } +extern "C" pid_t +getsid (pid_t pid) +{ + pid_t res; + if (!pid) + res = myself->sid; + else + { + pinfo p (pid); + if (p) + res = p->sid; + else + { + set_errno (ESRCH); + res = -1; + } + } + return res; +} + extern "C" ssize_t _read (int fd, void *ptr, size_t len) { - int res; - fhandler_base *fh; + const struct iovec iov = + { + iov_base: ptr, + iov_len: len + }; + + return readv (fd, &iov, 1); +} + +extern "C" ssize_t +_write (int fd, const void *ptr, size_t len) +{ + const struct iovec iov = + { + iov_base: (void *) ptr, // const_cast + iov_len: len + }; + + return writev (fd, &iov, 1); +} + +extern "C" ssize_t +readv (int fd, const struct iovec *const iov, const int iovcnt) +{ extern int sigcatchers; - int e = get_errno (); + const int e = get_errno (); + + int res = -1; + + const ssize_t tot = check_iovec_for_read (iov, iovcnt); + + if (tot <= 0) + { + res = tot; + goto done; + } while (1) { sigframe thisframe (mainthread); - if (cygheap->fdtab.not_open (fd)) + cygheap_fdget cfd (fd); + if (cfd < 0) + break; + + if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY) { set_errno (EBADF); - return -1; + break; } - // set_sig_errno (0); - fh = cygheap->fdtab[fd]; - DWORD wait = fh->is_nonblocking () ? 0 : INFINITE; + DWORD wait = cfd->is_nonblocking () ? 0 : INFINITE; /* Could block, so let user know we at least got here. */ - syscall_printf ("read (%d, %p, %d) %sblocking, sigcatchers %d", fd, ptr, len, wait ? "" : "non", sigcatchers); + syscall_printf ("readv (%d, %p, %d) %sblocking, sigcatchers %d", + fd, iov, iovcnt, wait ? "" : "non", sigcatchers); - if (wait && (/*!sigcatchers || */!fh->is_slow () || fh->get_r_no_interrupt ())) - debug_printf ("non-interruptible read\n"); - else if (!fh->ready_for_read (fd, wait, 0)) + if (wait && (!cfd->is_slow () || cfd->get_r_no_interrupt ())) + debug_printf ("no need to call ready_for_read\n"); + else if (!cfd->ready_for_read (fd, wait)) { - if (!wait) - set_sig_errno (EAGAIN); /* Don't really need 'set_sig_errno' here, but... */ - else - set_sig_errno (EINTR); res = -1; goto out; } + /* FIXME: This is not thread safe. We need some method to + ensure that an fd, closed in another thread, aborts I/O + operations. */ + if (!cfd.isopen ()) + break; + /* Check to see if this is a background read from a "tty", sending a SIGTTIN, if appropriate */ - res = fh->bg_check (SIGTTIN); + res = cfd->bg_check (SIGTTIN); + + if (!cfd.isopen ()) + { + res = -1; + break; + } + if (res > bg_eof) { myself->process_state |= PID_TTYIN; - res = fh->read (ptr, len); + if (!cfd.isopen ()) + { + res = -1; + break; + } + res = cfd->readv (iov, iovcnt, tot); myself->process_state &= ~PID_TTYIN; } @@ -335,19 +420,31 @@ _read (int fd, void *ptr, size_t len) set_errno (e); } - syscall_printf ("%d = read (%d<%s>, %p, %d), bin %d, errno %d", res, fd, fh->get_name (), - ptr, len, fh->get_r_binary (), get_errno ()); +done: + syscall_printf ("%d = readv (%d, %p, %d), errno %d", res, fd, iov, iovcnt, + get_errno ()); MALLOC_CHECK; return res; } extern "C" ssize_t -_write (int fd, const void *ptr, size_t len) +writev (const int fd, const struct iovec *const iov, const int iovcnt) { int res = -1; + const ssize_t tot = check_iovec_for_write (iov, iovcnt); + sigframe thisframe (mainthread); + cygheap_fdget cfd (fd); + if (cfd < 0) + goto done; - if (cygheap->fdtab.not_open (fd)) + if (tot <= 0) + { + res = tot; + goto done; + } + + if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY) { set_errno (EBADF); goto done; @@ -355,118 +452,29 @@ _write (int fd, const void *ptr, size_t 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); + paranoid_printf ("writev (%d, %p, %d)", fd, iov, iovcnt); else - syscall_printf ("write (%d, %p, %d)", fd, ptr, len); - - fhandler_base *fh; - fh = cygheap->fdtab[fd]; + syscall_printf ("writev (%d, %p, %d)", fd, iov, iovcnt); - res = fh->bg_check (SIGTTOU); + res = cfd->bg_check (SIGTTOU); if (res > bg_eof) { myself->process_state |= PID_TTYOU; - res = fh->write (ptr, len); + res = cfd->writev (iov, iovcnt, tot); myself->process_state &= ~PID_TTYOU; } done: if (fd == 1 || fd == 2) - paranoid_printf ("%d = write (%d, %p, %d)", res, fd, ptr, len); + paranoid_printf ("%d = write (%d, %p, %d), errno %d", + res, fd, iov, iovcnt, get_errno ()); else - syscall_printf ("%d = write (%d, %p, %d)", res, fd, ptr, len); + syscall_printf ("%d = write (%d, %p, %d), errno %d", + res, fd, iov, iovcnt, get_errno ()); MALLOC_CHECK; - return (ssize_t)res; -} - -/* - * FIXME - should really move this interface into fhandler, and implement - * write in terms of it. There are devices in Win32 that could do this with - * overlapped I/O much more efficiently - we should eventually use - * these. - */ - -extern "C" ssize_t -writev (int fd, const struct iovec *iov, int iovcnt) -{ - int i; - ssize_t len, total; - char *base; - - if (iovcnt < 1 || iovcnt > IOV_MAX) - { - set_errno (EINVAL); - return -1; - } - - /* Ensure that the sum of the iov_len values is less than - SSIZE_MAX (per spec), if so, we must fail with no output (per spec). - */ - total = 0; - for (i = 0; i < iovcnt; ++i) - { - total += iov[i].iov_len; - if (total > SSIZE_MAX) - { - set_errno (EINVAL); - return -1; - } - } - /* Now write the data */ - for (i = 0, total = 0; i < iovcnt; i++, iov++) - { - len = iov->iov_len; - base = iov->iov_base; - while (len > 0) - { - register int nbytes; - nbytes = write (fd, base, len); - if (nbytes < 0 && total == 0) - return -1; - if (nbytes <= 0) - return total; - len -= nbytes; - total += nbytes; - base += nbytes; - } - } - return total; -} - -/* - * FIXME - should really move this interface into fhandler, and implement - * read in terms of it. There are devices in Win32 that could do this with - * overlapped I/O much more efficiently - we should eventually use - * these. - */ - -extern "C" ssize_t -readv (int fd, const struct iovec *iov, int iovcnt) -{ - int i; - ssize_t len, total; - char *base; - - for (i = 0, total = 0; i < iovcnt; i++, iov++) - { - len = iov->iov_len; - base = iov->iov_base; - while (len > 0) - { - register int nbytes; - nbytes = read (fd, base, len); - if (nbytes < 0 && total == 0) - return -1; - if (nbytes <= 0) - return total; - len -= nbytes; - total += nbytes; - base += nbytes; - } - } - return total; + return res; } /* _open */ @@ -475,51 +483,46 @@ readv (int fd, const struct iovec *iov, int iovcnt) extern "C" int _open (const char *unix_path, int flags, ...) { - int fd; int res = -1; va_list ap; mode_t mode = 0; - fhandler_base *fh; sigframe thisframe (mainthread); syscall_printf ("open (%s, %p)", unix_path, flags); if (!check_null_empty_str_errno (unix_path)) { - SetResourceLock (LOCK_FD_LIST, WRITE_LOCK|READ_LOCK, " open "); - /* check for optional mode argument */ va_start (ap, flags); mode = va_arg (ap, mode_t); va_end (ap); - fd = cygheap->fdtab.find_unused_handle (); + fhandler_base *fh; + cygheap_fdnew fd; - if (fd < 0) - set_errno (ENMFILE); - else + if (fd >= 0) { path_conv pc; - if (!(fh = cygheap->fdtab.build_fhandler (fd, unix_path, NULL, pc))) + if (!(fh = cygheap->fdtab.build_fhandler_from_name (fd, unix_path, + NULL, pc))) res = -1; // errno already set - else if (!fh->open (pc, flags, (mode & 07777) & ~cygheap->umask)) + else if (!fh->open (&pc, flags, (mode & 07777) & ~cygheap->umask)) { - cygheap->fdtab.release (fd); + fd.release (); res = -1; } else if ((res = fd) <= 2) set_std_handle (res); } - ReleaseResourceLock (LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," open"); } syscall_printf ("%d = open (%s, %p)", res, unix_path, flags); return res; } -extern "C" off_t -_lseek (int fd, off_t pos, int dir) +extern "C" __off64_t +lseek64 (int fd, __off64_t pos, int dir) { - off_t res; + __off64_t res; sigframe thisframe (mainthread); if (dir != SEEK_SET && dir != SEEK_CUR && dir != SEEK_END) @@ -527,20 +530,25 @@ _lseek (int fd, off_t pos, int dir) set_errno (EINVAL); res = -1; } - else if (cygheap->fdtab.not_open (fd)) - { - set_errno (EBADF); - res = -1; - } else { - res = cygheap->fdtab[fd]->lseek (pos, dir); + cygheap_fdget cfd (fd); + if (cfd >= 0) + res = cfd->lseek (pos, dir); + else + res = -1; } - syscall_printf ("%d = lseek (%d, %d, %d)", res, fd, pos, dir); + syscall_printf ("%d = lseek (%d, %D, %d)", res, fd, pos, dir); return res; } +extern "C" __off32_t +_lseek (int fd, __off32_t pos, int dir) +{ + return lseek64 (fd, (__off64_t) pos, dir); +} + extern "C" int _close (int fd) { @@ -550,18 +558,13 @@ _close (int fd) syscall_printf ("close (%d)", fd); MALLOC_CHECK; - if (cygheap->fdtab.not_open (fd)) - { - debug_printf ("handle %d not open", fd); - set_errno (EBADF); - res = -1; - } + cygheap_fdget cfd (fd, true); + if (cfd < 0) + res = -1; else { - SetResourceLock (LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," close"); - res = cygheap->fdtab[fd]->close (); - cygheap->fdtab.release (fd); - ReleaseResourceLock (LOCK_FD_LIST,WRITE_LOCK|READ_LOCK," close"); + res = cfd->close (); + cfd.release (); } syscall_printf ("%d = close (%d)", res, fd); @@ -575,13 +578,11 @@ isatty (int fd) int res; sigframe thisframe (mainthread); - if (cygheap->fdtab.not_open (fd)) - { - syscall_printf ("0 = isatty (%d)", fd); - return 0; - } - - res = cygheap->fdtab[fd]->is_tty (); + cygheap_fdget cfd (fd); + if (cfd < 0) + res = 0; + else + res = cfd->is_tty (); syscall_printf ("%d = isatty (%d)", res, fd); return res; } @@ -598,7 +599,7 @@ _link (const char *a, const char *b) { int res = -1; sigframe thisframe (mainthread); - path_conv real_a (a, PC_SYM_NOFOLLOW | PC_FULL); + path_conv real_a (a, PC_SYM_FOLLOW | PC_FULL); path_conv real_b (b, PC_SYM_NOFOLLOW | PC_FULL); if (real_a.error) @@ -606,6 +607,7 @@ _link (const char *a, const char *b) set_errno (real_a.error); goto done; } + if (real_b.error) { set_errno (real_b.case_clash ? ECASECLASH : real_b.error); @@ -614,11 +616,12 @@ _link (const char *a, const char *b) if (real_b.exists ()) { - syscall_printf ("file '%s' exists?", (char *)real_b); + syscall_printf ("file '%s' exists?", (char *) real_b); set_errno (EEXIST); goto done; } - if (real_b.get_win32 ()[strlen (real_b.get_win32 ()) - 1] == '.') + + if (real_b[strlen (real_b) - 1] == '.') { syscall_printf ("trailing dot, bailing out"); set_errno (EINVAL); @@ -628,7 +631,7 @@ _link (const char *a, const char *b) /* Try to make hard link first on Windows NT */ if (wincap.has_hard_links ()) { - if (CreateHardLinkA (real_b.get_win32 (), real_a.get_win32 (), NULL)) + if (CreateHardLinkA (real_b, real_a, NULL)) { res = 0; goto done; @@ -645,15 +648,10 @@ _link (const char *a, const char *b) BOOL bSuccess; - hFileSource = CreateFile ( - real_a.get_win32 (), - FILE_WRITE_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE /*| FILE_SHARE_DELETE*/, - &sec_none_nih, // sa - OPEN_EXISTING, - 0, - NULL - ); + hFileSource = CreateFile (real_a, FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE /*| FILE_SHARE_DELETE*/, + &sec_none_nih, // sa + OPEN_EXISTING, 0, NULL); if (hFileSource == INVALID_HANDLE_VALUE) { @@ -661,8 +659,7 @@ _link (const char *a, const char *b) goto docopy; } - lpContext = NULL; - cbPathLen = sys_mbstowcs (wbuf, real_b.get_win32 (), MAX_PATH) * sizeof (WCHAR); + cbPathLen = sys_mbstowcs (wbuf, real_b, MAX_PATH) * sizeof (WCHAR); StreamId.dwStreamId = BACKUP_LINK; StreamId.dwStreamAttributes = 0; @@ -671,8 +668,9 @@ _link (const char *a, const char *b) StreamId.Size.LowPart = cbPathLen; StreamSize = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**) + - StreamId.dwStreamNameSize; + StreamId.dwStreamNameSize; + lpContext = NULL; /* Write the WIN32_STREAM_ID */ bSuccess = BackupWrite ( hFileSource, @@ -724,7 +722,7 @@ _link (const char *a, const char *b) } docopy: /* do this with a copy */ - if (CopyFileA (real_a.get_win32 (), real_b.get_win32 (), 1)) + if (CopyFileA (real_a, real_b, 1)) res = 0; else __seterrno (); @@ -740,11 +738,11 @@ done: * systems, it is only a stub that always returns zero. */ static int -chown_worker (const char *name, unsigned fmode, uid_t uid, gid_t gid) +chown_worker (const char *name, unsigned fmode, __uid32_t uid, __gid32_t gid) { int res; - uid_t old_uid; - gid_t old_gid; + __uid32_t old_uid; + __gid32_t old_gid; if (check_null_empty_str_errno (name)) return -1; @@ -781,14 +779,14 @@ chown_worker (const char *name, unsigned fmode, uid_t uid, gid_t gid) &old_gid); if (!res) { - if (uid == (uid_t) -1) + if (uid == ILLEGAL_UID) uid = old_uid; - if (gid == (gid_t) -1) + if (gid == ILLEGAL_GID) gid = old_gid; - if (win32_path.isdir()) + if (win32_path.isdir ()) attrib |= S_IFDIR; res = set_file_attribute (win32_path.has_acls (), win32_path, uid, - gid, attrib, cygheap->user.logsrv ()); + gid, attrib); } if (res != 0 && (!win32_path.has_acls () || !allow_ntsec)) { @@ -805,31 +803,47 @@ done: } extern "C" int -chown (const char * name, uid_t uid, gid_t gid) +chown32 (const char * name, __uid32_t uid, __gid32_t gid) { sigframe thisframe (mainthread); return chown_worker (name, PC_SYM_FOLLOW, uid, gid); } extern "C" int -lchown (const char * name, uid_t uid, gid_t gid) +chown (const char * name, __uid16_t uid, __gid16_t gid) +{ + sigframe thisframe (mainthread); + return chown_worker (name, PC_SYM_FOLLOW, + uid16touid32 (uid), gid16togid32 (gid)); +} + +extern "C" int +lchown32 (const char * name, __uid32_t uid, __gid32_t gid) { sigframe thisframe (mainthread); return chown_worker (name, PC_SYM_NOFOLLOW, uid, gid); } extern "C" int -fchown (int fd, uid_t uid, gid_t gid) +lchown (const char * name, __uid16_t uid, __gid16_t gid) +{ + sigframe thisframe (mainthread); + return chown_worker (name, PC_SYM_NOFOLLOW, + uid16touid32 (uid), gid16togid32 (gid)); +} + +extern "C" int +fchown32 (int fd, __uid32_t uid, __gid32_t gid) { sigframe thisframe (mainthread); - if (cygheap->fdtab.not_open (fd)) + cygheap_fdget cfd (fd); + if (cfd < 0) { syscall_printf ("-1 = fchown (%d,...)", fd); - set_errno (EBADF); return -1; } - const char *path = cygheap->fdtab[fd]->get_name (); + const char *path = cfd->get_name (); if (path == NULL) { @@ -843,6 +857,12 @@ fchown (int fd, uid_t uid, gid_t gid) return chown_worker (path, PC_SYM_FOLLOW, uid, gid); } +extern "C" int +fchown (int fd, __uid16_t uid, __gid16_t gid) +{ + return fchown32 (fd, uid16touid32 (uid), gid16togid32 (gid)); +} + /* umask: POSIX 5.3.3.1 */ extern "C" mode_t umask (mode_t mask) @@ -884,8 +904,8 @@ chmod (const char *path, mode_t mode) /* temporary erase read only bit, to be able to set file security */ SetFileAttributes (win32_path, (DWORD) win32_path & ~FILE_ATTRIBUTE_READONLY); - uid_t uid; - gid_t gid; + __uid32_t uid; + __gid32_t gid; if (win32_path.isdir ()) mode |= S_IFDIR; @@ -896,7 +916,7 @@ chmod (const char *path, mode_t mode) if (win32_path.isdir ()) mode |= S_IFDIR; if (!set_file_attribute (win32_path.has_acls (), win32_path, uid, gid, - mode, cygheap->user.logsrv ()) + mode) && allow_ntsec) res = 0; @@ -931,14 +951,14 @@ extern "C" int fchmod (int fd, mode_t mode) { sigframe thisframe (mainthread); - if (cygheap->fdtab.not_open (fd)) + cygheap_fdget cfd (fd); + if (cfd < 0) { syscall_printf ("-1 = fchmod (%d, 0%o)", fd, mode); - set_errno (EBADF); return -1; } - const char *path = cygheap->fdtab[fd]->get_name (); + const char *path = cfd->get_name (); if (path == NULL) { @@ -952,56 +972,61 @@ fchmod (int fd, mode_t mode) return chmod (path, mode); } -/* Cygwin internal */ -static int -num_entries (const char *win32_name) +static void +stat64_to_stat32 (struct __stat64 *src, struct __stat32 *dst) { - WIN32_FIND_DATA buf; - HANDLE handle; - char buf1[MAX_PATH]; - int count = 0; - - strcpy (buf1, win32_name); - int len = strlen (buf1); - if (len == 0 || isdirsep (buf1[len - 1])) - strcat (buf1, "*"); - else - strcat (buf1, "/*"); /* */ - - handle = FindFirstFileA (buf1, &buf); - - if (handle == INVALID_HANDLE_VALUE) - return 0; - count ++; - while (FindNextFileA (handle, &buf)) - { - if ((buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - count ++; - } - FindClose (handle); - return count; + dst->st_dev = ((src->st_dev >> 8) & 0xff00) | (src->st_dev & 0xff); + dst->st_ino = src->st_ino; + dst->st_mode = src->st_mode; + dst->st_nlink = src->st_nlink; + dst->st_uid = src->st_uid; + dst->st_gid = src->st_gid; + dst->st_rdev = ((src->st_rdev >> 8) & 0xff00) | (src->st_rdev & 0xff); + dst->st_size = src->st_size; + dst->st_atim = src->st_atim; + dst->st_mtim = src->st_mtim; + dst->st_ctim = src->st_ctim; + dst->st_blksize = src->st_blksize; + dst->st_blocks = src->st_blocks; } extern "C" int -_fstat (int fd, struct stat *buf) +fstat64 (int fd, struct __stat64 *buf) { - int r; + int res; sigframe thisframe (mainthread); - if (cygheap->fdtab.not_open (fd)) - { - syscall_printf ("-1 = fstat (%d, %p)", fd, buf); - set_errno (EBADF); - r = -1; - } + cygheap_fdget cfd (fd); + if (cfd < 0) + res = -1; else { - memset (buf, 0, sizeof (struct stat)); - r = cygheap->fdtab[fd]->fstat (buf); - syscall_printf ("%d = fstat (%d, %x)", r, fd, buf); + path_conv pc (cfd->get_win32_name (), PC_SYM_NOFOLLOW); + memset (buf, 0, sizeof (struct __stat64)); + res = cfd->fstat (buf, &pc); + if (!res) + { + if (!buf->st_ino) + buf->st_ino = hash_path_name (0, cfd->get_win32_name ()); + if (!buf->st_dev) + buf->st_dev = (cfd->get_device () << 16) | cfd->get_unit (); + if (!buf->st_rdev) + buf->st_rdev = buf->st_dev; + } } - return r; + syscall_printf ("%d = fstat (%d, %p)", res, fd, buf); + return res; +} + +extern "C" int +_fstat (int fd, struct __stat32 *buf) +{ + struct __stat64 buf64; + int ret = fstat64 (fd, &buf64); + if (!ret) + stat64_to_stat32 (&buf64, buf); + return ret; } /* fsync: P96 6.6.1.1 */ @@ -1009,16 +1034,14 @@ extern "C" int fsync (int fd) { sigframe thisframe (mainthread); - if (cygheap->fdtab.not_open (fd)) + cygheap_fdget cfd (fd); + if (cfd < 0) { syscall_printf ("-1 = fsync (%d)", fd); - set_errno (EBADF); return -1; } - HANDLE h = cygheap->fdtab[fd]->get_handle (); - - if (FlushFileBuffers (h) == 0) + if (FlushFileBuffers (cfd->get_handle ()) == 0) { __seterrno (); return -1; @@ -1033,32 +1056,6 @@ sync () return 0; } -int __stdcall -stat_dev (DWORD devn, int unit, unsigned long ino, struct stat *buf) -{ - sigframe thisframe (mainthread); - switch (devn) - { - case FH_PIPEW: - buf->st_mode = STD_WBITS | S_IWGRP | S_IWOTH; - break; - case FH_PIPER: - buf->st_mode = STD_RBITS; - break; - default: - buf->st_mode = STD_RBITS | STD_WBITS | S_IWGRP | S_IWOTH; - break; - } - - buf->st_mode |= devn == FH_FLOPPY ? S_IFBLK : S_IFCHR; - buf->st_blksize = S_BLKSIZE; - buf->st_nlink = 1; - buf->st_dev = buf->st_rdev = FHDEVN (devn) << 8 | (unit & 0xff); - buf->st_ino = ino; - buf->st_atime = buf->st_mtime = buf->st_ctime = time (NULL); - return 0; -} - suffix_info stat_suffixes[] = { suffix_info ("", 1), @@ -1067,152 +1064,91 @@ suffix_info stat_suffixes[] = }; /* Cygwin internal */ -static int -stat_worker (const char *caller, const char *name, struct stat *buf, - int nofollow) +int __stdcall +stat_worker (const char *name, struct __stat64 *buf, int nofollow, + path_conv *pc) { int res = -1; - int oret; - uid_t uid; - gid_t gid; path_conv real_path; fhandler_base *fh = NULL; - MALLOC_CHECK; - int open_flags = O_RDONLY | O_BINARY | O_DIROPEN - | (nofollow ? O_NOSYMLINK : 0); - - debug_printf ("%s (%s, %p)", caller, name, buf); - if (check_null_invalid_struct_errno (buf)) goto done; - fh = cygheap->fdtab.build_fhandler (-1, name, NULL, real_path, - (nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW) - | PC_FULL, stat_suffixes); + if (!pc) + pc = &real_path; + + fh = cygheap->fdtab.build_fhandler_from_name (-1, name, NULL, *pc, + (nofollow ? PC_SYM_NOFOLLOW + : PC_SYM_FOLLOW) + | PC_FULL, stat_suffixes); - if (real_path.error) + if (pc->error) { - set_errno (real_path.error); - goto done; + debug_printf ("got %d error from build_fhandler_from_name", pc->error); + set_errno (pc->error); } - - memset (buf, 0, sizeof (struct stat)); - - if (real_path.is_device ()) - return stat_dev (real_path.get_devn (), real_path.get_unitn (), - hash_path_name (0, real_path.get_win32 ()), buf); - - debug_printf ("%d = file_attributes for '%s'", (DWORD) real_path, - (char *) real_path); - - if ((oret = fh->open (real_path, open_flags, 0))) - /* ok */; else { - int ntsec_atts = 0; - /* If we couldn't open the file, try a "query open" with no permissions. - This will allow us to determine *some* things about the file, at least. */ - fh->set_query_open (TRUE); - if ((oret = fh->open (real_path, open_flags, 0))) - /* ok */; - else if (allow_ntsec && real_path.has_acls () && get_errno () == EACCES - && !get_file_attribute (TRUE, real_path, &ntsec_atts, &uid, &gid) - && !ntsec_atts && uid == myself->uid && gid == myself->gid) - { - /* Check a special case here. If ntsec is ON it happens - that a process creates a file using mode 000 to disallow - other processes access. In contrast to UNIX, this results - in a failing open call in the same process. Check that - case. */ - set_file_attribute (TRUE, real_path, 0400); - oret = fh->open (real_path, open_flags, 0); - set_file_attribute (TRUE, real_path, ntsec_atts); - } - } - if (oret) - { - res = fh->fstat (buf); - /* The number of links to a directory includes the - number of subdirectories in the directory, since all - those subdirectories point to it. - This is too slow on remote drives, so we do without it and - set the number of links to 2. */ - /* Unfortunately the count of 2 confuses `find (1)' command. So - let's try it with `1' as link count. */ - if (real_path.isdir ()) - buf->st_nlink = (real_path.isremote () - ? 1 : num_entries (real_path.get_win32 ())); - fh->close (); - } - else if (real_path.exists ()) - { - /* Unfortunately, the above open may fail if the file exists, though. - So we have to care for this case here, too. */ - WIN32_FIND_DATA wfd; - HANDLE handle; - buf->st_nlink = 1; - if (real_path.isdir () && real_path.isremote ()) - buf->st_nlink = num_entries (real_path.get_win32 ()); - buf->st_dev = FHDEVN (FH_DISK) << 8; - buf->st_ino = hash_path_name (0, real_path.get_win32 ()); - if (real_path.isdir ()) - buf->st_mode = S_IFDIR; - else if (real_path.issymlink ()) - buf->st_mode = S_IFLNK; - else if (real_path.issocket ()) - buf->st_mode = S_IFSOCK; - else - buf->st_mode = S_IFREG; - if (!real_path.has_acls () - || get_file_attribute (TRUE, real_path.get_win32 (), - &buf->st_mode, - &buf->st_uid, &buf->st_gid)) - { - buf->st_mode |= STD_RBITS | STD_XBITS; - if (!(real_path.has_attribute (FILE_ATTRIBUTE_READONLY))) - buf->st_mode |= STD_WBITS; - if (real_path.issymlink ()) - buf->st_mode |= S_IRWXU | S_IRWXG | S_IRWXO; - get_file_attribute (FALSE, real_path.get_win32 (), - NULL, &buf->st_uid, &buf->st_gid); - } - if ((handle = FindFirstFile (real_path.get_win32 (), &wfd)) - != INVALID_HANDLE_VALUE) + debug_printf ("(%s, %p, %d, %p), file_attributes %d", name, buf, nofollow, + pc, (DWORD) real_path); + memset (buf, 0, sizeof (*buf)); + res = fh->fstat (buf, pc); + if (!res) { - buf->st_atime = to_time_t (&wfd.ftLastAccessTime); - buf->st_mtime = to_time_t (&wfd.ftLastWriteTime); - buf->st_ctime = to_time_t (&wfd.ftCreationTime); - buf->st_size = wfd.nFileSizeLow; - buf->st_blksize = S_BLKSIZE; - buf->st_blocks = ((unsigned long) buf->st_size + - S_BLKSIZE-1) / S_BLKSIZE; - FindClose (handle); + if (!buf->st_ino) + buf->st_ino = hash_path_name (0, fh->get_win32_name ()); + if (!buf->st_dev) + buf->st_dev = (fh->get_device () << 16) | fh->get_unit (); + if (!buf->st_rdev) + buf->st_rdev = buf->st_dev; } - res = 0; } done: if (fh) delete fh; MALLOC_CHECK; - syscall_printf ("%d = %s (%s, %p)", res, caller, name, buf); + syscall_printf ("%d = (%s, %p)", res, name, buf); return res; } extern "C" int -_stat (const char *name, struct stat *buf) +stat64 (const char *name, struct __stat64 *buf) { sigframe thisframe (mainthread); - return stat_worker ("stat", name, buf, 0); + syscall_printf ("entering"); + return stat_worker (name, buf, 0); +} + +extern "C" int +_stat (const char *name, struct __stat32 *buf) +{ + struct __stat64 buf64; + int ret = stat64 (name, &buf64); + if (!ret) + stat64_to_stat32 (&buf64, buf); + return ret; } /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */ extern "C" int -lstat (const char *name, struct stat *buf) +lstat64 (const char *name, struct __stat64 *buf) { sigframe thisframe (mainthread); - return stat_worker ("lstat", name, buf, 1); + syscall_printf ("entering"); + return stat_worker (name, buf, 1); +} + +/* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */ +extern "C" int +cygwin_lstat (const char *name, struct __stat32 *buf) +{ + struct __stat64 buf64; + int ret = lstat64 (name, &buf64); + if (!ret) + stat64_to_stat32 (&buf64, buf); + return ret; } extern int acl_access (const char *, int); @@ -1222,7 +1158,7 @@ access (const char *fn, int flags) { sigframe thisframe (mainthread); // flags were incorrectly specified - if (flags & ~ (F_OK|R_OK|W_OK|X_OK)) + if (flags & ~(F_OK|R_OK|W_OK|X_OK)) { set_errno (EINVAL); return -1; @@ -1231,8 +1167,8 @@ access (const char *fn, int flags) if (allow_ntsec) return acl_access (fn, flags); - struct stat st; - int r = stat (fn, &st); + struct __stat64 st; + int r = stat_worker (fn, &st, 0); if (r) return -1; r = -1; @@ -1240,45 +1176,45 @@ access (const char *fn, int flags) { if (st.st_uid == myself->uid) { - if (! (st.st_mode & S_IRUSR)) + if (!(st.st_mode & S_IRUSR)) goto done; } else if (st.st_gid == myself->gid) { - if (! (st.st_mode & S_IRGRP)) + if (!(st.st_mode & S_IRGRP)) goto done; } - else if (! (st.st_mode & S_IROTH)) + else if (!(st.st_mode & S_IROTH)) goto done; } if (flags & W_OK) { if (st.st_uid == myself->uid) { - if (! (st.st_mode & S_IWUSR)) + if (!(st.st_mode & S_IWUSR)) goto done; } else if (st.st_gid == myself->gid) { - if (! (st.st_mode & S_IWGRP)) + if (!(st.st_mode & S_IWGRP)) goto done; } - else if (! (st.st_mode & S_IWOTH)) + else if (!(st.st_mode & S_IWOTH)) goto done; } if (flags & X_OK) { if (st.st_uid == myself->uid) { - if (! (st.st_mode & S_IXUSR)) + if (!(st.st_mode & S_IXUSR)) goto done; } else if (st.st_gid == myself->gid) { - if (! (st.st_mode & S_IXGRP)) + if (!(st.st_mode & S_IXGRP)) goto done; } - else if (! (st.st_mode & S_IXOTH)) + else if (!(st.st_mode & S_IXOTH)) goto done; } r = 0; @@ -1396,7 +1332,16 @@ done: else { /* make the new file have the permissions of the old one */ - SetFileAttributes (real_new, real_old); + DWORD attr = real_old; +#ifdef HIDDEN_DOT_FILES + char *c = strrchr (real_old.get_win32 (), '\\'); + if ((c && c[1] == '.') || *real_old.get_win32 () == '.') + attr &= ~FILE_ATTRIBUTE_HIDDEN; + c = strrchr (real_new.get_win32 (), '\\'); + if ((c && c[1] == '.') || *real_new.get_win32 () == '.') + attr |= FILE_ATTRIBUTE_HIDDEN; +#endif + SetFileAttributes (real_new, attr); /* Shortcut hack, No. 2, part 2 */ /* if the new filename was an existing shortcut, remove it now if the @@ -1417,6 +1362,9 @@ done: extern "C" int system (const char *cmdstring) { + if (check_null_empty_str_errno (cmdstring)) + return -1; + sigframe thisframe (mainthread); int res; const char* command[4]; @@ -1511,11 +1459,9 @@ check_posix_perm (const char *fname, int v) extern "C" long int fpathconf (int fd, int v) { - if (cygheap->fdtab.not_open (fd)) - { - set_errno (EBADF); - return -1; - } + cygheap_fdget cfd (fd); + if (cfd < 0) + return -1; switch (v) { case _PC_LINK_MAX: @@ -1538,7 +1484,7 @@ fpathconf (int fd, int v) case _PC_NO_TRUNC: return -1; case _PC_VDISABLE: - if (isatty (fd)) + if (cfd->is_tty ()) return -1; else { @@ -1547,13 +1493,10 @@ fpathconf (int fd, int v) } case _PC_POSIX_PERMISSIONS: case _PC_POSIX_SECURITY: - { - fhandler_base *fh = cygheap->fdtab[fd]; - if (fh->get_device () == FH_DISK) - return check_posix_perm (fh->get_win32_name (), v); - set_errno (EINVAL); - return -1; - } + if (cfd->get_device () == FH_DISK) + return check_posix_perm (cfd->get_win32_name (), v); + set_errno (EINVAL); + return -1; default: set_errno (EINVAL); return -1; @@ -1566,6 +1509,8 @@ pathconf (const char *file, int v) switch (v) { case _PC_PATH_MAX: + if (check_null_empty_str_errno (file)) + return -1; return PATH_MAX - strlen (file); case _PC_NAME_MAX: return PATH_MAX; @@ -1606,11 +1551,12 @@ pathconf (const char *file, int v) extern "C" char * ttyname (int fd) { - if (cygheap->fdtab.not_open (fd) || !cygheap->fdtab[fd]->is_tty ()) + cygheap_fdget cfd (fd); + if (cfd < 0 || !cfd->is_tty ()) { return 0; } - return (char *) (cygheap->fdtab[fd]->ttyname ()); + return (char *) (cfd->ttyname ()); } extern "C" char * @@ -1637,21 +1583,20 @@ _cygwin_istext_for_stdio (int fd) return 0; /* we do it for old apps, due to getc/putc macros */ } - if (cygheap->fdtab.not_open (fd)) + cygheap_fdget cfd (fd, false, false); + if (cfd < 0) { syscall_printf (" _cifs: fd not open\n"); return 0; } - fhandler_base *p = cygheap->fdtab[fd]; - - if (p->get_device () != FH_DISK) + if (cfd->get_device () != FH_DISK) { syscall_printf (" _cifs: fd not disk file\n"); return 0; } - if (p->get_w_binary () || p->get_r_binary ()) + if (cfd->get_w_binary () || cfd->get_r_binary ()) { syscall_printf (" _cifs: get_*_binary\n"); return 0; @@ -1673,8 +1618,8 @@ setmode_helper (FILE *f) if (fileno (f) != setmode_file) return 0; syscall_printf ("setmode: file was %s now %s\n", - f->_flags & __SCLE ? "cle" : "raw", - setmode_mode & O_TEXT ? "cle" : "raw"); + f->_flags & __SCLE ? "text" : "raw", + setmode_mode & O_TEXT ? "text" : "raw"); if (setmode_mode & O_TEXT) f->_flags |= __SCLE; else @@ -1685,13 +1630,11 @@ setmode_helper (FILE *f) extern "C" int getmode (int fd) { - if (cygheap->fdtab.not_open (fd)) - { - set_errno (EBADF); - return -1; - } + cygheap_fdget cfd (fd); + if (cfd < 0) + return -1; - return cygheap->fdtab[fd]->get_flags () & (O_BINARY | O_TEXT); + return cfd->get_flags () & (O_BINARY | O_TEXT); } /* Set a file descriptor into text or binary mode, returning the @@ -1700,44 +1643,32 @@ getmode (int fd) extern "C" int setmode (int fd, int mode) { - if (cygheap->fdtab.not_open (fd)) - { - set_errno (EBADF); - return -1; - } + cygheap_fdget cfd (fd); + if (cfd < 0) + return -1; if (mode != O_BINARY && mode != O_TEXT && mode != 0) { set_errno (EINVAL); return -1; } - fhandler_base *p = cygheap->fdtab[fd]; - /* Note that we have no way to indicate the case that writes are binary but not reads, or vice-versa. These cases can arise when using the tty or console interface. People using those interfaces should not use setmode. */ int res; - if (p->get_w_binary () && p->get_r_binary ()) + if (cfd->get_w_binary () && cfd->get_r_binary ()) res = O_BINARY; - else if (p->get_w_binset () && p->get_r_binset ()) + else if (cfd->get_w_binset () && cfd->get_r_binset ()) res = O_TEXT; /* Specifically set O_TEXT */ else res = 0; if (!mode) - p->reset_to_open_binmode (); - else if (mode & O_BINARY) - { - p->set_w_binary (1); - p->set_r_binary (1); - } + cfd->reset_to_open_binmode (); else - { - p->set_w_binary (0); - p->set_r_binary (0); - } + cfd->set_flags ((cfd->get_flags () & ~(O_TEXT | O_BINARY)) | mode); if (_cygwin_istext_for_stdio (fd)) setmode_mode = O_TEXT; @@ -1746,57 +1677,57 @@ setmode (int fd, int mode) setmode_file = fd; _fwalk (_REENT, setmode_helper); - syscall_printf ("setmode (%d<%s>, %s) returns %s\n", fd, p->get_name (), - mode & O_TEXT ? "text" : "binary", - res & O_TEXT ? "text" : "binary"); + syscall_printf ("setmode (%d<%s>, %p) returns %s\n", fd, cfd->get_name (), + mode, res & O_TEXT ? "text" : "binary"); return res; } -/* ftruncate: P96 5.6.7.1 */ extern "C" int -ftruncate (int fd, off_t length) +ftruncate64 (int fd, __off64_t length) { sigframe thisframe (mainthread); int res = -1; if (length < 0) - { - set_errno (EINVAL); - } - else if (cygheap->fdtab.not_open (fd)) - { - set_errno (EBADF); - } + set_errno (EINVAL); else { - HANDLE h = cygheap->fdtab[fd]->get_handle (); - off_t prev_loc; - - if (h) + cygheap_fdget cfd (fd); + if (cfd >= 0) { - /* remember curr file pointer location */ - prev_loc = cygheap->fdtab[fd]->lseek (0, SEEK_CUR); + HANDLE h = cygheap->fdtab[fd]->get_handle (); - cygheap->fdtab[fd]->lseek (length, SEEK_SET); - if (!SetEndOfFile (h)) + if (cfd->get_handle ()) { - __seterrno (); - } - else - res = 0; + /* remember curr file pointer location */ + __off64_t prev_loc = cfd->lseek (0, SEEK_CUR); - /* restore original file pointer location */ - cygheap->fdtab[fd]->lseek (prev_loc, 0); + cfd->lseek (length, SEEK_SET); + if (!SetEndOfFile (h)) + __seterrno (); + else + res = 0; + + /* restore original file pointer location */ + cfd->lseek (prev_loc, SEEK_SET); + } } } - syscall_printf ("%d = ftruncate (%d, %d)", res, fd, length); + syscall_printf ("%d = ftruncate (%d, %d)", res, fd, length); return res; } +/* ftruncate: P96 5.6.7.1 */ +extern "C" int +ftruncate (int fd, __off32_t length) +{ + return ftruncate64 (fd, (__off64_t)length); +} + /* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */ extern "C" int -truncate (const char *pathname, off_t length) +truncate64 (const char *pathname, __off64_t length) { sigframe thisframe (mainthread); int fd; @@ -1808,7 +1739,7 @@ truncate (const char *pathname, off_t length) set_errno (EBADF); else { - res = ftruncate (fd, length); + res = ftruncate64 (fd, length); close (fd); } syscall_printf ("%d = truncate (%s, %d)", res, pathname, length); @@ -1816,15 +1747,23 @@ truncate (const char *pathname, off_t length) return res; } +/* truncate: Provided by SVR4 and 4.3+BSD. Not part of POSIX.1 or XPG3 */ +extern "C" int +truncate (const char *pathname, __off32_t length) +{ + return truncate64 (pathname, (__off64_t)length); +} + extern "C" long get_osfhandle (int fd) { - long res = -1; + long res; - if (cygheap->fdtab.not_open (fd)) - set_errno (EBADF); + cygheap_fdget cfd (fd); + if (cfd >= 0) + res = (long) cfd->get_handle (); else - res = (long) cygheap->fdtab[fd]->get_handle (); + res = -1; syscall_printf ("%d = get_osfhandle (%d)", res, fd); return res; @@ -1875,13 +1814,10 @@ extern "C" int fstatfs (int fd, struct statfs *sfs) { sigframe thisframe (mainthread); - if (cygheap->fdtab.not_open (fd)) - { - set_errno (EBADF); - return -1; - } - fhandler_disk_file *f = (fhandler_disk_file *) cygheap->fdtab[fd]; - return statfs (f->get_name (), sfs); + cygheap_fdget cfd (fd); + if (cfd < 0) + return -1; + return statfs (cfd->get_name (), sfs); } /* setpgid: POSIX 4.3.3.1 */ @@ -1961,16 +1897,14 @@ extern "C" char * ptsname (int fd) { sigframe thisframe (mainthread); - if (cygheap->fdtab.not_open (fd)) - { - set_errno (EBADF); - return 0; - } - return (char *) (cygheap->fdtab[fd]->ptsname ()); + cygheap_fdget cfd (fd); + if (cfd < 0) + return 0; + return (char *) (cfd->ptsname ()); } /* FIXME: what is this? */ -extern "C" int +extern "C" int __declspec(dllexport) regfree () { return 0; @@ -1996,296 +1930,278 @@ mkfifo (const char *_path, mode_t mode) return -1; } -/* setgid: POSIX 4.2.2.1 */ +/* seteuid: standards? */ extern "C" int -setgid (gid_t gid) +seteuid32 (__uid32_t uid) { - int ret = setegid (gid); - if (!ret) - cygheap->user.real_gid = myself->gid; - return ret; -} -/* setuid: POSIX 4.2.2.1 */ -extern "C" int -setuid (uid_t uid) -{ - int ret = seteuid (uid); - if (!ret) - cygheap->user.real_uid = myself->uid; - debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid); - return ret; -} + debug_printf ("uid: %d myself->gid: %d", uid, myself->gid); -extern struct passwd *internal_getlogin (cygheap_user &user); + if (!wincap.has_security () + || (uid == myself->uid && !cygheap->user.groups.ischanged)) + { + debug_printf ("Nothing happens"); + return 0; + } -/* seteuid: standards? */ -extern "C" int -seteuid (uid_t uid) -{ - sigframe thisframe (mainthread); - if (wincap.has_security ()) + if (uid == ILLEGAL_UID) { - char orig_username[UNLEN + 1]; - char orig_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; - char username[UNLEN + 1]; - DWORD ulen = UNLEN + 1; - char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; - DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; - SID_NAME_USE use; + set_errno (EINVAL); + return -1; + } - if (uid == (uid_t) -1 || uid == myself->uid) - { - debug_printf ("new euid == current euid, nothing happens"); - return 0; - } - struct passwd *pw_new = getpwuid (uid); - if (!pw_new) - { - set_errno (EINVAL); - return -1; - } + sigframe thisframe (mainthread); + cygsid usersid; + user_groups &groups = cygheap->user.groups; + HANDLE ptok, sav_token; + BOOL sav_impersonated, sav_token_is_internal_token; + BOOL process_ok, explicitly_created_token = FALSE; + struct passwd * pw_new; + PSID origpsid, psid2 = NO_SID; - cygsid tok_usersid; - DWORD siz; + pw_new = getpwuid32 (uid); + if (!usersid.getfrompw (pw_new)) + { + set_errno (EINVAL); + return -1; + } + /* Save current information */ + sav_token = cygheap->user.token; + sav_impersonated = cygheap->user.impersonated; - char *env; - orig_username[0] = orig_domain[0] = '\0'; - if ((env = getenv ("USERNAME"))) - strncat (orig_username, env, UNLEN + 1); - if ((env = getenv ("USERDOMAIN"))) - strncat (orig_domain, env, INTERNET_MAX_HOST_NAME_LENGTH + 1); - if (uid == cygheap->user.orig_uid) + RevertToSelf (); + if (!OpenProcessToken (hMainProc, TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &ptok)) + { + __seterrno (); + goto failed; + } + /* Verify if the process token is suitable. + Currently we do not try to differentiate between + internal tokens and others */ + process_ok = verify_token (ptok, usersid, groups); + debug_printf ("Process token %sverified", process_ok ? "" : "not "); + if (process_ok) + { + if (cygheap->user.issetuid ()) + cygheap->user.impersonated = FALSE; + else { - - debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)", - cygheap->user.token); - RevertToSelf (); - if (cygheap->user.token != INVALID_HANDLE_VALUE) - cygheap->user.impersonated = FALSE; - - HANDLE ptok = INVALID_HANDLE_VALUE; - if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &ptok)) - debug_printf ("OpenProcessToken(): %E\n"); - else if (!GetTokenInformation (ptok, TokenUser, &tok_usersid, - sizeof tok_usersid, &siz)) - debug_printf ("GetTokenInformation(): %E"); - else if (!LookupAccountSid (NULL, tok_usersid, username, &ulen, - domain, &dlen, &use)) - debug_printf ("LookupAccountSid(): %E"); - else - { - setenv ("USERNAME", username, 1); - setenv ("USERDOMAIN", domain, 1); - } - if (ptok != INVALID_HANDLE_VALUE) - CloseHandle (ptok); + CloseHandle (ptok); + goto success; /* No change */ } + } + + if (!process_ok && cygheap->user.token != INVALID_HANDLE_VALUE) + { + /* Verify if the current tokem is suitable */ + BOOL token_ok = verify_token (cygheap->user.token, usersid, groups, + &sav_token_is_internal_token); + debug_printf ("Thread token %d %sverified", + cygheap->user.token, token_ok?"":"not "); + if (!token_ok) + cygheap->user.token = INVALID_HANDLE_VALUE; else { - cygsid usersid, pgrpsid, tok_pgrpsid; - HANDLE sav_token = INVALID_HANDLE_VALUE; - BOOL sav_impersonation; - BOOL current_token_is_internal_token = FALSE; - BOOL explicitely_created_token = FALSE; - - struct group *gr = getgrgid (myself->gid); - debug_printf ("myself->gid: %d, gr: %d", myself->gid, gr); - - usersid.getfrompw (pw_new); - pgrpsid.getfromgr (gr); - - /* Only when ntsec is ON! */ - /* Check if new user == user of impersonation token and - - if reasonable - new pgrp == pgrp of impersonation token. */ - if (allow_ntsec && cygheap->user.token != INVALID_HANDLE_VALUE) + /* Return if current token is valid */ + if (cygheap->user.impersonated) { - if (!GetTokenInformation (cygheap->user.token, TokenUser, - &tok_usersid, sizeof tok_usersid, &siz)) - { - debug_printf ("GetTokenInformation(): %E"); - tok_usersid = NO_SID; - } - if (!GetTokenInformation (cygheap->user.token, TokenPrimaryGroup, - &tok_pgrpsid, sizeof tok_pgrpsid, &siz)) - { - debug_printf ("GetTokenInformation(): %E"); - tok_pgrpsid = NO_SID; - } - /* Check if the current user token was internally created. */ - TOKEN_SOURCE ts; - if (!GetTokenInformation (cygheap->user.token, TokenSource, - &ts, sizeof ts, &siz)) - debug_printf ("GetTokenInformation(): %E"); - else if (!memcmp (ts.SourceName, "Cygwin.1", 8)) - current_token_is_internal_token = TRUE; - if ((usersid && tok_usersid && usersid != tok_usersid) || - /* Check for pgrp only if current token is an internal - token. Otherwise the external provided token is - very likely overwritten here. */ - (current_token_is_internal_token && - pgrpsid && tok_pgrpsid && pgrpsid != tok_pgrpsid)) - { - /* If not, RevertToSelf and close old token. */ - debug_printf ("tsid != usersid"); - RevertToSelf (); - sav_token = cygheap->user.token; - sav_impersonation = cygheap->user.impersonated; - cygheap->user.token = INVALID_HANDLE_VALUE; - cygheap->user.impersonated = FALSE; - } + CloseHandle (ptok); + if (!ImpersonateLoggedOnUser (cygheap->user.token)) + system_printf ("Impersonating in seteuid failed: %E"); + goto success; /* No change */ } + } + } - /* Only when ntsec is ON! */ - /* If no impersonation token is available, try to - authenticate using NtCreateToken() or subauthentication. */ - if (allow_ntsec && cygheap->user.token == INVALID_HANDLE_VALUE) - { - HANDLE ptok = INVALID_HANDLE_VALUE; + /* Set process def dacl to allow access to impersonated token */ + char dacl_buf[MAX_DACL_LEN (5)]; + if (usersid != (origpsid = cygheap->user.orig_sid ())) psid2 = usersid; + if (sec_acl ((PACL) dacl_buf, FALSE, origpsid, psid2)) + { + TOKEN_DEFAULT_DACL tdacl; + tdacl.DefaultDacl = (PACL) dacl_buf; + if (!SetTokenInformation (ptok, TokenDefaultDacl, + &tdacl, sizeof dacl_buf)) + debug_printf ("SetTokenInformation" + "(TokenDefaultDacl): %E"); + } + CloseHandle (ptok); - ptok = create_token (usersid, pgrpsid); - if (ptok != INVALID_HANDLE_VALUE) - explicitely_created_token = TRUE; - else - { - /* create_token failed. Try subauthentication. */ - debug_printf ("create token failed, try subauthentication."); - ptok = subauth (pw_new); - } - if (ptok != INVALID_HANDLE_VALUE) - { - cygwin_set_impersonation_token (ptok); - /* If sav_token was internally created, destroy it. */ - if (sav_token != INVALID_HANDLE_VALUE && - current_token_is_internal_token) - CloseHandle (sav_token); - } - else if (sav_token != INVALID_HANDLE_VALUE) - cygheap->user.token = sav_token; - } - /* If no impersonation is active but an impersonation - token is available, try to impersonate. */ - if (cygheap->user.token != INVALID_HANDLE_VALUE && - !cygheap->user.impersonated) - { - debug_printf ("Impersonate (uid == %d)", uid); - RevertToSelf (); - - /* If the token was explicitely created, all information has - already been set correctly. */ - if (!explicitely_created_token) - { - /* Try setting owner to same value as user. */ - if (usersid && - !SetTokenInformation (cygheap->user.token, TokenOwner, - &usersid, sizeof usersid)) - debug_printf ("SetTokenInformation(user.token, " - "TokenOwner): %E"); - /* Try setting primary group in token to current group - if token not explicitely created. */ - if (pgrpsid && - !SetTokenInformation (cygheap->user.token, - TokenPrimaryGroup, - &pgrpsid, sizeof pgrpsid)) - debug_printf ("SetTokenInformation(user.token, " - "TokenPrimaryGroup): %E"); - - } - - /* Now try to impersonate. */ - if (!LookupAccountSid (NULL, usersid, username, &ulen, - domain, &dlen, &use)) - debug_printf ("LookupAccountSid (): %E"); - else if (!ImpersonateLoggedOnUser (cygheap->user.token)) - system_printf ("Impersonating (%d) in set(e)uid failed: %E", - cygheap->user.token); - else - { - cygheap->user.impersonated = TRUE; - setenv ("USERNAME", username, 1); - setenv ("USERDOMAIN", domain, 1); - } - } + if (!process_ok && cygheap->user.token == INVALID_HANDLE_VALUE) + { + /* If no impersonation token is available, try to + authenticate using NtCreateToken () or subauthentication. */ + cygheap->user.token = create_token (usersid, groups, pw_new); + if (cygheap->user.token != INVALID_HANDLE_VALUE) + explicitly_created_token = TRUE; + else + { + /* create_token failed. Try subauthentication. */ + debug_printf ("create token failed, try subauthentication."); + cygheap->user.token = subauth (pw_new); + if (cygheap->user.token == INVALID_HANDLE_VALUE) + goto failed; } + } - cygheap_user user; - /* user.token is used in internal_getlogin () to determine if - impersonation is active. If so, the token is used for - retrieving user's SID. */ - user.token = cygheap->user.impersonated ? cygheap->user.token - : INVALID_HANDLE_VALUE; - struct passwd *pw_cur = internal_getlogin (user); - if (pw_cur != pw_new) + /* If using the token, set info and impersonate */ + if (!process_ok) + { + /* If the token was explicitly created, all information has + already been set correctly. */ + if (!explicitly_created_token) { - debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d", - cygheap->user.token, pw_cur->pw_uid, - pw_new->pw_uid, cygheap->user.orig_uid); - setenv ("USERNAME", orig_username, 1); - setenv ("USERDOMAIN", orig_domain, 1); - set_errno (EPERM); - return -1; + /* Try setting owner to same value as user. */ + if (!SetTokenInformation (cygheap->user.token, TokenOwner, + &usersid, sizeof usersid)) + debug_printf ("SetTokenInformation(user.token, " + "TokenOwner): %E"); + /* Try setting primary group in token to current group */ + if (!SetTokenInformation (cygheap->user.token, + TokenPrimaryGroup, + &groups.pgsid, sizeof (cygsid))) + debug_printf ("SetTokenInformation(user.token, " + "TokenPrimaryGroup): %E"); } - myself->uid = uid; - cygheap->user = user; - } - else - set_errno (ENOSYS); - debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid); + /* Now try to impersonate. */ + if (!ImpersonateLoggedOnUser (cygheap->user.token)) + { + debug_printf ("ImpersonateLoggedOnUser %E"); + __seterrno (); + goto failed; + } + cygheap->user.impersonated = TRUE; + } + + /* If sav_token was internally created and is replaced, destroy it. */ + if (sav_token != INVALID_HANDLE_VALUE && + sav_token != cygheap->user.token && + sav_token_is_internal_token) + CloseHandle (sav_token); + cygheap->user.set_name (pw_new->pw_name); + cygheap->user.set_sid (usersid); +success: + myself->uid = uid; + groups.ischanged = FALSE; return 0; + + failed: + cygheap->user.token = sav_token; + cygheap->user.impersonated = sav_impersonated; + if (cygheap->user.issetuid () + && !ImpersonateLoggedOnUser (cygheap->user.token)) + system_printf ("Impersonating in seteuid failed: %E"); + return -1; +} + +extern "C" int +seteuid (__uid16_t uid) +{ + return seteuid32 (uid16touid32 (uid)); +} + +/* setuid: POSIX 4.2.2.1 */ +extern "C" int +setuid32 (__uid32_t uid) +{ + int ret = seteuid32 (uid); + if (!ret) + cygheap->user.real_uid = myself->uid; + debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid); + return ret; +} + +extern "C" int +setuid (__uid16_t uid) +{ + return setuid32 (uid16touid32 (uid)); } /* setegid: from System V. */ extern "C" int -setegid (gid_t gid) +setegid32 (__gid32_t gid) { + if (!wincap.has_security () || gid == myself->gid) + return 0; + + if (gid == ILLEGAL_GID) + { + set_errno (EINVAL); + return -1; + } + sigframe thisframe (mainthread); - if (wincap.has_security ()) + user_groups * groups = &cygheap->user.groups; + cygsid gsid; + HANDLE ptok; + + struct __group32 * gr = getgrgid32 (gid); + if (!gr || gr->gr_gid != gid || !gsid.getfromgr (gr)) { - if (gid != (gid_t) -1) - { - struct group *gr; + set_errno (EINVAL); + return -1; + } + myself->gid = gid; - if (!(gr = getgrgid (gid))) - { - set_errno (EINVAL); - return -1; - } - myself->gid = gid; - if (allow_ntsec) - { - cygsid gsid; - HANDLE ptok; - - if (gsid.getfromgr (gr)) - { - if (!OpenProcessToken (GetCurrentProcess (), - TOKEN_ADJUST_DEFAULT, - &ptok)) - debug_printf ("OpenProcessToken(): %E\n"); - else - { - if (!SetTokenInformation (ptok, TokenPrimaryGroup, - &gsid, sizeof gsid)) - debug_printf ("SetTokenInformation(myself, " - "TokenPrimaryGroup): %E"); - CloseHandle (ptok); - } - } - } - } + groups->update_pgrp (gsid); + /* If impersonated, update primary group and revert */ + if (cygheap->user.issetuid ()) + { + if (!SetTokenInformation (cygheap->user.token, + TokenPrimaryGroup, + &gsid, sizeof gsid)) + debug_printf ("SetTokenInformation(thread, " + "TokenPrimaryGroup): %E"); + RevertToSelf (); } + if (!OpenProcessToken (hMainProc, TOKEN_ADJUST_DEFAULT, &ptok)) + debug_printf ("OpenProcessToken(): %E\n"); else - set_errno (ENOSYS); + { + if (!SetTokenInformation (ptok, TokenPrimaryGroup, + &gsid, sizeof gsid)) + debug_printf ("SetTokenInformation(process, " + "TokenPrimaryGroup): %E"); + CloseHandle (ptok); + } + if (cygheap->user.issetuid () + && !ImpersonateLoggedOnUser (cygheap->user.token)) + system_printf ("Impersonating in setegid failed: %E"); return 0; } +extern "C" int +setegid (__gid16_t gid) +{ + return setegid32 (gid16togid32 (gid)); +} + +/* setgid: POSIX 4.2.2.1 */ +extern "C" int +setgid32 (__gid32_t gid) +{ + int ret = setegid32 (gid); + if (!ret) + cygheap->user.real_gid = myself->gid; + return ret; +} + +extern "C" int +setgid (__gid16_t gid) +{ + int ret = setegid32 (gid16togid32 (gid)); + if (!ret) + cygheap->user.real_gid = myself->gid; + return ret; +} + /* chroot: privileged Unix system call. */ /* FIXME: Not privileged here. How should this be done? */ extern "C" int chroot (const char *newroot) { sigframe thisframe (mainthread); - path_conv path (newroot, PC_SYM_FOLLOW | PC_FULL); + path_conv path (newroot, PC_SYM_FOLLOW | PC_FULL | PC_POSIX); int ret; if (path.error) @@ -2302,9 +2218,7 @@ chroot (const char *newroot) } else { - char buf[MAX_PATH]; - normalize_posix_path (newroot, buf); - cygheap->root.set (buf, path); + cygheap->root.set (path.normalized_path, path); ret = 0; } @@ -2514,17 +2428,16 @@ logout (char *line) return 0; ut_fd = CreateFile (win32_path.get_win32 (), - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - NULL); + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); if (ut_fd != INVALID_HANDLE_VALUE) { struct utmp *ut; struct utmp ut_buf[100]; - off_t pos = 0; /* Position in file */ + /* FIXME: utmp file access is not 64 bit clean for now. */ + __off32_t pos = 0; /* Position in file */ DWORD rd; while (!res && ReadFile (ut_fd, ut_buf, sizeof ut_buf, &rd, NULL) @@ -2559,3 +2472,101 @@ logout (char *line) return res; } + +static int utmp_fd = -2; +static char *utmp_file = (char *) _PATH_UTMP; + +static struct utmp utmp_data; + +extern "C" void +setutent () +{ + sigframe thisframe (mainthread); + if (utmp_fd == -2) + { + utmp_fd = _open (utmp_file, O_RDONLY); + } + _lseek (utmp_fd, 0, SEEK_SET); +} + +extern "C" void +endutent () +{ + sigframe thisframe (mainthread); + _close (utmp_fd); + utmp_fd = -2; +} + +extern "C" void +utmpname (_CONST char *file) +{ + sigframe thisframe (mainthread); + if (check_null_empty_str (file)) + { + debug_printf ("Invalid file"); + return; + } + utmp_file = strdup (file); + debug_printf ("New UTMP file: %s", utmp_file); +} + +extern "C" struct utmp * +getutent () +{ + sigframe thisframe (mainthread); + if (utmp_fd == -2) + setutent (); + if (_read (utmp_fd, &utmp_data, sizeof (utmp_data)) != sizeof (utmp_data)) + return NULL; + return &utmp_data; +} + +extern "C" struct utmp * +getutid (struct utmp *id) +{ + sigframe thisframe (mainthread); + if (check_null_invalid_struct_errno (id)) + return NULL; + while (_read (utmp_fd, &utmp_data, sizeof (utmp_data)) == sizeof (utmp_data)) + { + switch (id->ut_type) + { +#if 0 /* Not available in Cygwin. */ + case RUN_LVL: + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + if (id->ut_type == utmp_data.ut_type) + return &utmp_data; + break; +#endif + case INIT_PROCESS: + case LOGIN_PROCESS: + case USER_PROCESS: + case DEAD_PROCESS: + if (id->ut_id == utmp_data.ut_id) + return &utmp_data; + break; + default: + return NULL; + } + } + return NULL; +} + +extern "C" struct utmp * +getutline (struct utmp *line) +{ + sigframe thisframe (mainthread); + if (check_null_invalid_struct_errno (line)) + return NULL; + while (_read (utmp_fd, &utmp_data, sizeof (utmp_data)) == sizeof (utmp_data)) + { + if ((utmp_data.ut_type == LOGIN_PROCESS || + utmp_data.ut_type == USER_PROCESS) && + !strncmp (utmp_data.ut_line, line->ut_line, + sizeof (utmp_data.ut_line))) + return &utmp_data; + } + return NULL; +} |