OSDN Git Service

* Makefile.in (DLL_OFILES): Add posix_ipc.o.
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / syscalls.cc
1 /* syscalls.cc: syscalls
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4    2005, 2006, 2007 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #define fstat __FOOfstat__
13 #define lstat __FOOlstat__
14 #define stat __FOOstat__
15 #define _close __FOO_close__
16 #define _lseek __FOO_lseek__
17 #define _open __FOO_open__
18 #define _read __FOO_read__
19 #define _write __FOO_write__
20 #define _open64 __FOO_open64__
21 #define _lseek64 __FOO_lseek64__
22 #define _fstat64 __FOO_fstat64__
23 #define pread __FOO_pread
24 #define pwrite __FOO_pwrite
25
26 #include "winsup.h"
27 #include <sys/stat.h>
28 #include <sys/vfs.h> /* needed for statfs */
29 #include <sys/statvfs.h> /* needed for statvfs */
30 #include <pwd.h>
31 #include <grp.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <process.h>
35 #include <utmp.h>
36 #include <utmpx.h>
37 #include <sys/uio.h>
38 #include <errno.h>
39 #include <ctype.h>
40 #include <limits.h>
41 #include <unistd.h>
42 #include <setjmp.h>
43 #include <sys/wait.h>
44 #include <winnls.h>
45 #include <wininet.h>
46 #include <winioctl.h>
47 #include <lmcons.h> /* for UNLEN */
48 #include <rpc.h>
49 #include <shellapi.h>
50 #include <ntdef.h>
51 #include "ntdll.h"
52
53 #undef fstat
54 #undef lstat
55 #undef stat
56 #undef pread
57 #undef pwrite
58
59 #include <cygwin/version.h>
60 #include <sys/cygwin.h>
61 #include "cygerrno.h"
62 #include "perprocess.h"
63 #include "security.h"
64 #include "path.h"
65 #include "fhandler.h"
66 #include "dtable.h"
67 #include "sigproc.h"
68 #include "pinfo.h"
69 #include "shared_info.h"
70 #include "cygheap.h"
71 #include "pwdgrp.h"
72 #include "cpuid.h"
73 #include "registry.h"
74 #include "environ.h"
75
76 #undef _close
77 #undef _lseek
78 #undef _open
79 #undef _read
80 #undef _write
81 #undef _open64
82 #undef _lseek64
83 #undef _fstat64
84
85 suffix_info stat_suffixes[] =
86 {
87   suffix_info ("", 1),
88   suffix_info (".exe", 1),
89   suffix_info (NULL)
90 };
91
92 bool transparent_exe = false;
93
94 SYSTEM_INFO system_info;
95
96 static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t,
97                                    _minor_t);
98
99 static int __stdcall stat_worker (const char *name, struct __stat64 *buf,
100                                   int nofollow) __attribute__ ((regparm (3)));
101
102 /* Close all files and process any queued deletions.
103    Lots of unix style applications will open a tmp file, unlink it,
104    but never call close.  This function is called by _exit to
105    ensure we don't leave any such files lying around.  */
106
107 void __stdcall
108 close_all_files (bool norelease)
109 {
110   cygheap->fdtab.lock ();
111
112   fhandler_base *fh;
113   for (int i = 0; i < (int) cygheap->fdtab.size; i++)
114     if ((fh = cygheap->fdtab[i]) != NULL)
115       {
116 #ifdef DEBUGGING
117         debug_printf ("closing fd %d", i);
118 #endif
119         fh->close ();
120         if (!norelease)
121           cygheap->fdtab.release (i);
122       }
123
124   if (!hExeced && cygheap->ctty)
125     cygheap->close_ctty ();
126
127   cygheap->fdtab.unlock ();
128   user_shared->delqueue.process_queue ();
129 }
130
131 int
132 dup (int fd)
133 {
134   return cygheap->fdtab.dup2 (fd, cygheap_fdnew ());
135 }
136
137 int
138 dup2 (int oldfd, int newfd)
139 {
140   return cygheap->fdtab.dup2 (oldfd, newfd);
141 }
142
143 static void
144 try_to_bin (path_conv &win32_path, HANDLE h)
145 {
146   NTSTATUS status;
147   IO_STATUS_BLOCK io;
148   char recycler[CYG_MAX_PATH + 20];
149
150   char *c = recycler + win32_path.rootdir (recycler);
151   if (wincap.has_recycle_dot_bin ())
152     {
153       strcpy (c, "$Recycle.Bin");       /* NTFS and FAT since Vista */
154       c += 12;
155     }
156   else if (win32_path.fs_is_ntfs ())
157     {
158       strcpy (c, "RECYCLER");           /* NTFS up to 2K3 */
159       c += 8;
160     }
161   else if (win32_path.fs_is_fat ())
162     {
163       strcpy (c, "Recycled");           /* FAT up to 2K3 */
164       c += 8;
165     }
166   else
167     return;
168
169   /* Yes, we can really do that.  Typically the recycle bin is created
170      by the first user actually using the bin.  The permissions are the
171      default permissions propagated from the root directory. */
172   if (GetFileAttributes (recycler) == INVALID_FILE_ATTRIBUTES)
173     {
174       if (!CreateDirectory (recycler, NULL))
175         {
176           debug_printf ("Can't create folder %s, %E", recycler);
177           return;
178         }
179       SetFileAttributes (recycler,
180                          FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
181     }
182
183   /* Up to Windows 2003 Server, the default settings for the top level recycle
184      bin are so that everybody has the right to create files in it.  Starting
185      with Vista, users are by default not allowed to create files in that
186      directory, only subdirectories.  Too bad, but that requires to move
187      files to the user's own recycler subdir.  Instead of adding yet another
188      special case, we just move the stuff to the user's recycler, especially
189      since only shared files are moved at all. */
190   if (win32_path.fs_is_ntfs ())
191     {
192       *c++ = '\\';
193       cygheap->user.get_windows_id (c);
194       while (*c)
195        ++c;
196       if (GetFileAttributes (recycler) == INVALID_FILE_ATTRIBUTES)
197         {
198           if (!CreateDirectory (recycler,
199                                 sec_user ((PSECURITY_ATTRIBUTES) alloca (1024),
200                                           cygheap->user.sid ())))
201             {
202               debug_printf ("Can't create folder %s, %E", recycler);
203               return;
204             }
205           SetFileAttributes (recycler,
206                              FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN);
207         }
208     }
209
210   /* Create hopefully unique filename. */
211   __small_sprintf (c, "\\cyg%016X", hash_path_name (myself->uid,
212                                                     win32_path.get_win32 ()));
213   c += 20;
214
215   /* Length of the WCHAR path in bytes. */
216   ULONG len = 2 * (c - recycler);
217   /* Choose size big enough to fit a local native NT path into it. */
218   ULONG size = sizeof (FILE_RENAME_INFORMATION) + len + 10;
219   PFILE_RENAME_INFORMATION pfri = (PFILE_RENAME_INFORMATION) alloca (size);
220
221   pfri->ReplaceIfExists = TRUE;
222   pfri->RootDirectory = NULL;
223   UNICODE_STRING uname = { 0, len + 10, pfri->FileName };
224   get_nt_native_path (recycler, uname);
225   pfri->FileNameLength = uname.Length;
226   status = NtSetInformationFile (h, &io, pfri, size, FileRenameInformation);
227   if (!NT_SUCCESS (status))
228     debug_printf ("Move %s to %s failed, status = %p", win32_path.get_win32 (),
229                   recycler, status);
230 }
231
232 static DWORD
233 unlink_9x (path_conv &win32_name)
234 {
235   BOOL ret = DeleteFile (win32_name);
236   syscall_printf ("DeleteFile %s", ret ? "succeeded" : "failed");
237   return GetLastError ();
238 }
239
240 DWORD
241 unlink_nt (path_conv &win32_name, bool setattrs)
242 {
243   WCHAR wpath[CYG_MAX_PATH + 10];
244   UNICODE_STRING upath = {0, sizeof (wpath), wpath};
245   OBJECT_ATTRIBUTES attr;
246   IO_STATUS_BLOCK io;
247   NTSTATUS status;
248   HANDLE h;
249
250   ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
251   /* Don't open directories with "delete on close", because the NT internal
252      semantic is apparently different from the file semantic.  If a directory
253      is opened "delete on close", the rename operation in try_to_bin fails
254      with STATUS_ACCESS_DENIED.  So directories must be deleted using
255      NtSetInformationFile, class FileDispositionInformation, which works fine.
256      
257      Correction, moving a directory opened with delete-on-close fails ONLY
258      on XP.  Note to myself: Never take anything for granted on Windows!
259      
260      Don't try "delete on close" if the file is on a remote share.  If two
261      processes have open handles on a file and one of them calls unlink, then
262      it happens that the file is removed from the remote share even though the
263      other process still has an open handle.  This other process than gets
264      Win32 error 59, ERROR_UNEXP_NET_ERR when trying to access the file.  That
265      does not happen when using NtSetInformationFile, class
266      FileDispositionInformation, which nicely succeeds but still, the file is
267      available for the other process.  Microsoft KB 837665 describes this
268      problem as a bug in 2K3, but I have reproduced it on shares on Samba
269      2.2.8, Samba 3.0.2, NT4SP6, XP64SP1 and 2K3 and in all cases, DeleteFile
270      works, "delete on close" does not. */
271   if (!win32_name.isdir () && !win32_name.isremote ())
272     flags |= FILE_DELETE_ON_CLOSE;
273   /* Add the reparse point flag to native symlinks, otherwise we remove the
274      target, not the symlink. */
275   if (win32_name.is_rep_symlink ())
276     flags |= FILE_OPEN_REPARSE_POINT;
277
278   win32_name.get_nt_native_path (upath);
279   InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
280                               NULL, sec_none_nih.lpSecurityDescriptor);
281   /* First try to open the file with sharing not allowed.  If the file
282      has an open handle on it, this will fail.  That indicates that the
283      file has to be moved to the recycle bin so that it actually disappears
284      from its directory even though its in use.  Otherwise, if opening
285      doesn't fail, the file is not in use and by simply closing the handle
286      the file will disappear. */
287   bool move_to_bin = false;
288   status = NtOpenFile (&h, DELETE, &attr, &io, 0, flags);
289   if (status == STATUS_SHARING_VIOLATION)
290     {
291       move_to_bin = true;
292       status = NtOpenFile (&h, DELETE, &attr, &io, wincap.shared (), flags);
293     }
294   if (!NT_SUCCESS (status))
295     {
296       if (status == STATUS_DELETE_PENDING)
297         {
298           syscall_printf ("Delete already pending, status = %p", status);
299           return 0;
300         }
301       syscall_printf ("Opening file for delete failed, status = %p", status);
302       return RtlNtStatusToDosError (status);
303     }
304
305   if (setattrs)
306     SetFileAttributes (win32_name, (DWORD) win32_name);
307
308   if (move_to_bin && !win32_name.isremote ())
309     try_to_bin (win32_name, h);
310
311   DWORD lasterr = 0;
312
313   if (win32_name.isdir () || win32_name.isremote ())
314     {
315       FILE_DISPOSITION_INFORMATION disp = { TRUE };
316       status = NtSetInformationFile (h, &io, &disp, sizeof disp,
317                                      FileDispositionInformation);
318       if (!NT_SUCCESS (status))
319         {
320           syscall_printf ("Setting delete disposition failed, status = %p",
321                           status);
322           lasterr = RtlNtStatusToDosError (status);
323         }
324     }
325
326   status = NtClose (h);
327   if (!NT_SUCCESS (status))
328     {
329       /* Maybe that's really paranoid, but not being able to close the file
330          also means that deleting fails. */
331       syscall_printf ("%p = NtClose (%p)", status, h);
332       if (!lasterr)
333         lasterr = RtlNtStatusToDosError (status);
334     }
335
336   syscall_printf ("Deleting succeeded");
337   return lasterr;
338 }
339
340 extern "C" int
341 unlink (const char *ourname)
342 {
343   int res = -1;
344   DWORD devn;
345
346   path_conv win32_name (ourname, PC_SYM_NOFOLLOW,
347                         transparent_exe ? stat_suffixes : NULL);
348
349   if (win32_name.error)
350     {
351       set_errno (win32_name.error);
352       goto done;
353     }
354
355   devn = win32_name.get_devn ();
356   if (isproc_dev (devn))
357     {
358       set_errno (EROFS);
359       goto done;
360     }
361
362   syscall_printf ("_unlink (%s)", win32_name.get_win32 ());
363
364   if (!win32_name.exists ())
365     {
366       syscall_printf ("unlinking a nonexistent file");
367       set_errno (ENOENT);
368       goto done;
369     }
370   else if (win32_name.isdir ())
371     {
372       syscall_printf ("unlinking a directory");
373       set_errno (EPERM);
374       goto done;
375     }
376
377   bool setattrs;
378   if (!((DWORD) win32_name & (FILE_ATTRIBUTE_READONLY
379                               | FILE_ATTRIBUTE_SYSTEM
380                               | FILE_ATTRIBUTE_HIDDEN)))
381     setattrs = false;
382   else
383     {
384       /* Allow us to delete even if read-only */
385       setattrs = SetFileAttributes (win32_name,
386                                     (DWORD) win32_name
387                                     & ~(FILE_ATTRIBUTE_READONLY
388                                         | FILE_ATTRIBUTE_SYSTEM
389                                         | FILE_ATTRIBUTE_HIDDEN));
390     }
391
392   DWORD lasterr;
393   lasterr = wincap.is_winnt () ? unlink_nt (win32_name, setattrs)
394                                : unlink_9x (win32_name);
395   if (!lasterr)
396     res = 0;
397   else
398     {
399       SetFileAttributes (win32_name, (DWORD) win32_name);
400
401       /* Windows 9x seems to report ERROR_ACCESS_DENIED rather than sharing
402          violation. */
403       if ((wincap.access_denied_on_delete () && lasterr == ERROR_ACCESS_DENIED
404            && !win32_name.isremote ())
405           || lasterr == ERROR_SHARING_VIOLATION)
406         {
407           /* Add file to the "to be deleted" queue. */
408           syscall_printf ("Sharing violation, couldn't delete file");
409           user_shared->delqueue.queue_file (win32_name);
410           res = 0;
411         }
412       else
413         __seterrno_from_win_error (lasterr);
414     }
415
416  done:
417   syscall_printf ("%d = unlink (%s)", res, ourname);
418   return res;
419 }
420
421 extern "C" int
422 _remove_r (struct _reent *, const char *ourname)
423 {
424   path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
425
426   if (win32_name.error)
427     {
428       set_errno (win32_name.error);
429       syscall_printf ("-1 = remove (%s)", ourname);
430       return -1;
431     }
432
433   return win32_name.isdir () ? rmdir (ourname) : unlink (ourname);
434 }
435
436 extern "C" int
437 remove (const char *ourname)
438 {
439   path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
440
441   if (win32_name.error)
442     {
443       set_errno (win32_name.error);
444       syscall_printf ("-1 = remove (%s)", ourname);
445       return -1;
446     }
447
448   return win32_name.isdir () ? rmdir (ourname) : unlink (ourname);
449 }
450
451 extern "C" pid_t
452 getpid ()
453 {
454   return myself->pid;
455 }
456
457 extern "C" pid_t
458 _getpid_r (struct _reent *)
459 {
460   return getpid ();
461 }
462
463 /* getppid: POSIX 4.1.1.1 */
464 extern "C" pid_t
465 getppid ()
466 {
467   return myself->ppid;
468 }
469
470 /* setsid: POSIX 4.3.2.1 */
471 extern "C" pid_t
472 setsid (void)
473 {
474 #ifdef NEWVFORK
475   vfork_save *vf = vfork_storage.val ();
476   /* This is a horrible, horrible kludge */
477   if (vf && vf->pid < 0)
478     {
479       pid_t pid = fork ();
480       if (pid > 0)
481         {
482           syscall_printf ("longjmping due to vfork");
483           vf->restore_pid (pid);
484         }
485       /* assuming that fork was successful */
486     }
487 #endif
488
489   if (myself->pgid == myself->pid)
490     syscall_printf ("hmm.  pgid %d pid %d", myself->pgid, myself->pid);
491   else
492     {
493       myself->ctty = -1;
494       cygheap->manage_console_count ("setsid", 0);
495       myself->sid = getpid ();
496       myself->pgid = getpid ();
497       if (cygheap->ctty)
498         cygheap->close_ctty ();
499       syscall_printf ("sid %d, pgid %d, %s", myself->sid, myself->pgid, myctty ());
500       return myself->sid;
501     }
502
503   set_errno (EPERM);
504   return -1;
505 }
506
507 extern "C" pid_t
508 getsid (pid_t pid)
509 {
510   pid_t res;
511   if (!pid)
512     res = myself->sid;
513   else
514     {
515       pinfo p (pid);
516       if (p)
517         res = p->sid;
518       else
519         {
520           set_errno (ESRCH);
521           res = -1;
522         }
523     }
524   return res;
525 }
526
527 extern "C" ssize_t
528 read (int fd, void *ptr, size_t len)
529 {
530   const iovec iov =
531     {
532       iov_base: ptr,
533       iov_len: len
534     };
535
536   return readv (fd, &iov, 1);
537 }
538
539 extern "C" ssize_t
540 pread (int fd, void *ptr, size_t len, _off64_t off)
541 {
542   ssize_t res;
543   cygheap_fdget cfd (fd);
544   if (cfd < 0)
545     res = -1;
546   else
547     res = cfd->pread (ptr, len, off);
548
549   syscall_printf ("%d = pread (%d, %p, %d, %d), errno %d",
550                   res, fd, ptr, len, off, get_errno ());
551   return res;
552 }
553
554 extern "C" ssize_t
555 pwrite (int fd, void *ptr, size_t len, _off64_t off)
556 {
557   ssize_t res;
558   cygheap_fdget cfd (fd);
559   if (cfd < 0)
560     res = -1;
561   else
562     res = cfd->pwrite (ptr, len, off);
563
564   syscall_printf ("%d = pwrite (%d, %p, %d, %d), errno %d",
565                   res, fd, ptr, len, off, get_errno ());
566   return res;
567 }
568
569 EXPORT_ALIAS (read, _read)
570
571 extern "C" ssize_t
572 write (int fd, const void *ptr, size_t len)
573 {
574   const struct iovec iov =
575     {
576       iov_base: (void *) ptr,   // const_cast
577       iov_len: len
578     };
579
580   return writev (fd, &iov, 1);
581 }
582
583 EXPORT_ALIAS (write, _write)
584
585 extern "C" ssize_t
586 readv (int fd, const struct iovec *const iov, const int iovcnt)
587 {
588   extern int sigcatchers;
589   const int e = get_errno ();
590
591   int res = -1;
592
593   const ssize_t tot = check_iovec_for_read (iov, iovcnt);
594
595   if (tot <= 0)
596     {
597       res = tot;
598       goto done;
599     }
600
601   while (1)
602     {
603       sig_dispatch_pending ();
604
605       cygheap_fdget cfd (fd);
606       if (cfd < 0)
607         break;
608
609       if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY)
610         {
611           set_errno (EBADF);
612           break;
613         }
614
615       DWORD wait = cfd->is_nonblocking () ? 0 : INFINITE;
616
617       /* Could block, so let user know we at least got here.  */
618       syscall_printf ("readv (%d, %p, %d) %sblocking, sigcatchers %d",
619                       fd, iov, iovcnt, wait ? "" : "non", sigcatchers);
620
621       if (wait && (!cfd->is_slow () || cfd->uninterruptible_io ()))
622         debug_printf ("no need to call ready_for_read");
623       else if (!cfd->ready_for_read (fd, wait))
624         {
625           res = -1;
626           goto out;
627         }
628
629       /* FIXME: This is not thread safe.  We need some method to
630          ensure that an fd, closed in another thread, aborts I/O
631          operations. */
632       if (!cfd.isopen ())
633         break;
634
635       /* Check to see if this is a background read from a "tty",
636          sending a SIGTTIN, if appropriate */
637       res = cfd->bg_check (SIGTTIN);
638
639       if (!cfd.isopen ())
640         {
641           res = -1;
642           break;
643         }
644
645       if (res > bg_eof)
646         {
647           myself->process_state |= PID_TTYIN;
648           if (!cfd.isopen ())
649             {
650               res = -1;
651               break;
652             }
653           res = cfd->readv (iov, iovcnt, tot);
654           myself->process_state &= ~PID_TTYIN;
655         }
656
657     out:
658       if (res >= 0 || get_errno () != EINTR || !_my_tls.call_signal_handler ())
659         break;
660       set_errno (e);
661     }
662
663 done:
664   syscall_printf ("%d = readv (%d, %p, %d), errno %d", res, fd, iov, iovcnt,
665                   get_errno ());
666   MALLOC_CHECK;
667   return res;
668 }
669
670 extern "C" ssize_t
671 writev (const int fd, const struct iovec *const iov, const int iovcnt)
672 {
673   int res = -1;
674   sig_dispatch_pending ();
675   const ssize_t tot = check_iovec_for_write (iov, iovcnt);
676
677   cygheap_fdget cfd (fd);
678   if (cfd < 0)
679     goto done;
680
681   if (tot <= 0)
682     {
683       res = tot;
684       goto done;
685     }
686
687   if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
688     {
689       set_errno (EBADF);
690       goto done;
691     }
692
693   /* Could block, so let user know we at least got here.  */
694   if (fd == 1 || fd == 2)
695     paranoid_printf ("writev (%d, %p, %d)", fd, iov, iovcnt);
696   else
697     syscall_printf  ("writev (%d, %p, %d)", fd, iov, iovcnt);
698
699   res = cfd->bg_check (SIGTTOU);
700
701   if (res > (int) bg_eof)
702     {
703       myself->process_state |= PID_TTYOU;
704       res = cfd->writev (iov, iovcnt, tot);
705       myself->process_state &= ~PID_TTYOU;
706     }
707
708 done:
709   if (fd == 1 || fd == 2)
710     paranoid_printf ("%d = write (%d, %p, %d), errno %d",
711                      res, fd, iov, iovcnt, get_errno ());
712   else
713     syscall_printf ("%d = write (%d, %p, %d), errno %d",
714                     res, fd, iov, iovcnt, get_errno ());
715
716   MALLOC_CHECK;
717   return res;
718 }
719
720 /* _open */
721 /* newlib's fcntl.h defines _open as taking variable args so we must
722    correspond.  The third arg if it exists is: mode_t mode. */
723 extern "C" int
724 open (const char *unix_path, int flags, ...)
725 {
726   int res = -1;
727   va_list ap;
728   mode_t mode = 0;
729   sig_dispatch_pending ();
730
731   syscall_printf ("open (%s, %p)", unix_path, flags);
732   myfault efault;
733   if (efault.faulted (EFAULT))
734     /* errno already set */;
735   else if (!*unix_path)
736     set_errno (ENOENT);
737   else
738     {
739       /* check for optional mode argument */
740       va_start (ap, flags);
741       mode = va_arg (ap, mode_t);
742       va_end (ap);
743
744       fhandler_base *fh;
745       cygheap_fdnew fd;
746
747       if (fd >= 0)
748         {
749           if (!(fh = build_fh_name (unix_path, NULL, (flags & O_NOFOLLOW) ?
750                                     PC_SYM_NOFOLLOW : PC_SYM_FOLLOW,
751                                     transparent_exe ? stat_suffixes : NULL)))
752             res = -1;           // errno already set
753           else if ((flags & O_NOFOLLOW) && fh->issymlink ())
754             {
755               delete fh;
756               res = -1;
757               set_errno (ELOOP);
758             }
759           else if (((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) && fh->exists ())
760             {
761               delete fh;
762               res = -1;
763               set_errno (EEXIST);
764             }
765           else if (fh->is_fs_special () && fh->device_access_denied (flags))
766             {
767               delete fh;
768               res = -1;
769             }
770           else if (!fh->open (flags, (mode & 07777) & ~cygheap->umask))
771             {
772               delete fh;
773               res = -1;
774             }
775           else
776             {
777               cygheap->fdtab[fd] = fh;
778               if ((res = fd) <= 2)
779                 set_std_handle (res);
780             }
781         }
782     }
783
784   syscall_printf ("%d = open (%s, %p)", res, unix_path, flags);
785   return res;
786 }
787
788 EXPORT_ALIAS (open, _open )
789 EXPORT_ALIAS (open, _open64 )
790
791 extern "C" _off64_t
792 lseek64 (int fd, _off64_t pos, int dir)
793 {
794   _off64_t res;
795
796   if (dir != SEEK_SET && dir != SEEK_CUR && dir != SEEK_END)
797     {
798       set_errno (EINVAL);
799       res = -1;
800     }
801   else
802     {
803       cygheap_fdget cfd (fd);
804       if (cfd >= 0)
805         res = cfd->lseek (pos, dir);
806       else
807         res = -1;
808     }
809   syscall_printf ("%D = lseek (%d, %D, %d)", res, fd, pos, dir);
810
811   return res;
812 }
813
814 EXPORT_ALIAS (lseek64, _lseek64)
815
816 extern "C" _off_t
817 lseek (int fd, _off_t pos, int dir)
818 {
819   return lseek64 (fd, (_off64_t) pos, dir);
820 }
821
822 EXPORT_ALIAS (lseek, _lseek)
823
824 extern "C" int
825 close (int fd)
826 {
827   int res;
828
829   syscall_printf ("close (%d)", fd);
830
831   MALLOC_CHECK;
832   cygheap_fdget cfd (fd, true);
833   if (cfd < 0)
834     res = -1;
835   else
836     {
837       res = cfd->close ();
838       cfd.release ();
839     }
840
841   syscall_printf ("%d = close (%d)", res, fd);
842   MALLOC_CHECK;
843   return res;
844 }
845
846 EXPORT_ALIAS (close, _close)
847
848 extern "C" int
849 isatty (int fd)
850 {
851   int res;
852
853   cygheap_fdget cfd (fd);
854   if (cfd < 0)
855     res = 0;
856   else
857     res = cfd->is_tty ();
858   syscall_printf ("%d = isatty (%d)", res, fd);
859   return res;
860 }
861
862 /* Under NT, try to make a hard link using backup API.  If that
863    fails or we are Win 95, just copy the file.
864    FIXME: We should actually be checking partition type, not OS.
865    Under NTFS, we should support hard links.  On FAT partitions,
866    we should just copy the file.
867 */
868
869 extern "C" int
870 link (const char *oldpath, const char *newpath)
871 {
872   int res = -1;
873   fhandler_base *fh;
874
875   if (!(fh = build_fh_name (oldpath, NULL, PC_SYM_NOFOLLOW,
876                             transparent_exe ? stat_suffixes : NULL)))
877     goto error;
878
879   if (fh->error ())
880     {
881       debug_printf ("got %d error from build_fh_name", fh->error ());
882       set_errno (fh->error ());
883     }
884   else
885     res = fh->link (newpath);
886
887   delete fh;
888  error:
889   syscall_printf ("%d = link (%s, %s)", res, oldpath, newpath);
890   return res;
891 }
892
893 /* chown: POSIX 5.6.5.1 */
894 /*
895  * chown () is only implemented for Windows NT.  Under other operating
896  * systems, it is only a stub that always returns zero.
897  */
898 static int
899 chown_worker (const char *name, unsigned fmode, __uid32_t uid, __gid32_t gid)
900 {
901   if (!wincap.has_security ())  // real chown only works on NT
902     return 0;                   // return zero (and do nothing) under Windows 9x
903
904   int res = -1;
905   fhandler_base *fh;
906
907   if (!(fh = build_fh_name (name, NULL, fmode, stat_suffixes)))
908     goto error;
909
910   if (fh->error ())
911     {
912       debug_printf ("got %d error from build_fh_name", fh->error ());
913       set_errno (fh->error ());
914     }
915   else
916     res = fh->fchown (uid, gid);
917
918   delete fh;
919  error:
920   syscall_printf ("%d = %schown (%s,...)",
921                   res, (fmode & PC_SYM_NOFOLLOW) ? "l" : "", name);
922   return res;
923 }
924
925 extern "C" int
926 chown32 (const char * name, __uid32_t uid, __gid32_t gid)
927 {
928   return chown_worker (name, PC_SYM_FOLLOW, uid, gid);
929 }
930
931 extern "C" int
932 chown (const char * name, __uid16_t uid, __gid16_t gid)
933 {
934   return chown_worker (name, PC_SYM_FOLLOW,
935                        uid16touid32 (uid), gid16togid32 (gid));
936 }
937
938 extern "C" int
939 lchown32 (const char * name, __uid32_t uid, __gid32_t gid)
940 {
941   return chown_worker (name, PC_SYM_NOFOLLOW, uid, gid);
942 }
943
944 extern "C" int
945 lchown (const char * name, __uid16_t uid, __gid16_t gid)
946 {
947   return chown_worker (name, PC_SYM_NOFOLLOW,
948                        uid16touid32 (uid), gid16togid32 (gid));
949 }
950
951 extern "C" int
952 fchown32 (int fd, __uid32_t uid, __gid32_t gid)
953 {
954   if (!wincap.has_security ())  // real chown only works on NT
955     return 0;                   // return zero (and do nothing) under Windows 9x
956
957   cygheap_fdget cfd (fd);
958   if (cfd < 0)
959     {
960       syscall_printf ("-1 = fchown (%d,...)", fd);
961       return -1;
962     }
963
964   int res = cfd->fchown (uid, gid);
965
966   syscall_printf ("%d = fchown (%s,...)", res, cfd->get_name ());
967   return res;
968 }
969
970 extern "C" int
971 fchown (int fd, __uid16_t uid, __gid16_t gid)
972 {
973   return fchown32 (fd, uid16touid32 (uid), gid16togid32 (gid));
974 }
975
976 /* umask: POSIX 5.3.3.1 */
977 extern "C" mode_t
978 umask (mode_t mask)
979 {
980   mode_t oldmask;
981
982   oldmask = cygheap->umask;
983   cygheap->umask = mask & 0777;
984   return oldmask;
985 }
986
987 int
988 chmod_device (path_conv& pc, mode_t mode)
989 {
990   return mknod_worker (pc, pc.dev.mode & S_IFMT, mode, pc.dev.major, pc.dev.minor);
991 }
992
993 /* chmod: POSIX 5.6.4.1 */
994 extern "C" int
995 chmod (const char *path, mode_t mode)
996 {
997   int res = -1;
998   fhandler_base *fh;
999   if (!(fh = build_fh_name (path, NULL, PC_SYM_FOLLOW, stat_suffixes)))
1000     goto error;
1001
1002   if (fh->error ())
1003     {
1004       debug_printf ("got %d error from build_fh_name", fh->error ());
1005       set_errno (fh->error ());
1006     }
1007   else
1008     res = fh->fchmod (mode);
1009
1010   delete fh;
1011  error:
1012   syscall_printf ("%d = chmod (%s, %p)", res, path, mode);
1013   return res;
1014 }
1015
1016 /* fchmod: P96 5.6.4.1 */
1017
1018 extern "C" int
1019 fchmod (int fd, mode_t mode)
1020 {
1021   cygheap_fdget cfd (fd);
1022   if (cfd < 0)
1023     {
1024       syscall_printf ("-1 = fchmod (%d, 0%o)", fd, mode);
1025       return -1;
1026     }
1027
1028   return cfd->fchmod (mode);
1029 }
1030
1031 static void
1032 stat64_to_stat32 (struct __stat64 *src, struct __stat32 *dst)
1033 {
1034   dst->st_dev = ((src->st_dev >> 8) & 0xff00) | (src->st_dev & 0xff);
1035   dst->st_ino = ((unsigned) (src->st_ino >> 32)) | (unsigned) src->st_ino;
1036   dst->st_mode = src->st_mode;
1037   dst->st_nlink = src->st_nlink;
1038   dst->st_uid = src->st_uid;
1039   dst->st_gid = src->st_gid;
1040   dst->st_rdev = ((src->st_rdev >> 8) & 0xff00) | (src->st_rdev & 0xff);
1041   dst->st_size = src->st_size;
1042   dst->st_atim = src->st_atim;
1043   dst->st_mtim = src->st_mtim;
1044   dst->st_ctim = src->st_ctim;
1045   dst->st_blksize = src->st_blksize;
1046   dst->st_blocks = src->st_blocks;
1047 }
1048
1049 extern "C" int
1050 fstat64 (int fd, struct __stat64 *buf)
1051 {
1052   int res;
1053
1054   cygheap_fdget cfd (fd);
1055   if (cfd < 0)
1056     res = -1;
1057   else
1058     {
1059       memset (buf, 0, sizeof (struct __stat64));
1060       res = cfd->fstat (buf);
1061       if (!res)
1062         {
1063           if (!buf->st_ino)
1064             buf->st_ino = cfd->get_namehash ();
1065           if (!buf->st_dev)
1066             buf->st_dev = cfd->get_device ();
1067           if (!buf->st_rdev)
1068             buf->st_rdev = buf->st_dev;
1069         }
1070     }
1071
1072   syscall_printf ("%d = fstat (%d, %p)", res, fd, buf);
1073   return res;
1074 }
1075
1076 extern "C" int
1077 _fstat64_r (struct _reent *ptr, int fd, struct __stat64 *buf)
1078 {
1079   int ret;
1080
1081   if ((ret = fstat64 (fd, buf)) == -1)
1082     ptr->_errno = get_errno ();
1083   return ret;
1084 }
1085
1086 extern "C" int
1087 fstat (int fd, struct __stat32 *buf)
1088 {
1089   struct __stat64 buf64;
1090   int ret = fstat64 (fd, &buf64);
1091   if (!ret)
1092     stat64_to_stat32 (&buf64, buf);
1093   return ret;
1094 }
1095
1096 extern "C" int
1097 _fstat_r (struct _reent *ptr, int fd, struct __stat32 *buf)
1098 {
1099   int ret;
1100
1101   if ((ret = fstat (fd, buf)) == -1)
1102     ptr->_errno = get_errno ();
1103   return ret;
1104 }
1105
1106 /* fsync: P96 6.6.1.1 */
1107 extern "C" int
1108 fsync (int fd)
1109 {
1110   cygheap_fdget cfd (fd);
1111   if (cfd < 0)
1112     {
1113       syscall_printf ("-1 = fsync (%d)", fd);
1114       return -1;
1115     }
1116   return cfd->fsync ();
1117 }
1118
1119 EXPORT_ALIAS (fsync, fdatasync)
1120
1121 static void
1122 sync_worker (const char *vol)
1123 {
1124   HANDLE fh = CreateFileA (vol, GENERIC_WRITE, wincap.shared (),
1125                            &sec_none_nih, OPEN_EXISTING, 0, NULL);
1126   if (fh != INVALID_HANDLE_VALUE)
1127     {
1128       FlushFileBuffers (fh);
1129       CloseHandle (fh);
1130     }
1131   else
1132     debug_printf ("Open failed with %E");
1133 }
1134
1135 /* sync: SUSv3 */
1136 extern "C" void
1137 sync ()
1138 {
1139   char vol[CYG_MAX_PATH];
1140
1141   if (wincap.has_guid_volumes ()) /* Win2k and newer */
1142     {
1143       char a_drive[CYG_MAX_PATH] = {0};
1144       char b_drive[CYG_MAX_PATH] = {0};
1145
1146       if (is_floppy ("A:"))
1147         GetVolumeNameForVolumeMountPointA ("A:\\", a_drive, CYG_MAX_PATH);
1148       if (is_floppy ("B:"))
1149         GetVolumeNameForVolumeMountPointA ("B:\\", b_drive, CYG_MAX_PATH);
1150
1151       HANDLE sh = FindFirstVolumeA (vol, CYG_MAX_PATH);
1152       if (sh != INVALID_HANDLE_VALUE)
1153         {
1154           do
1155             {
1156               debug_printf ("Try volume %s", vol);
1157
1158               /* Check vol for being a floppy on A: or B:.  Skip them. */
1159               if (strcasematch (vol, a_drive) || strcasematch (vol, b_drive))
1160                 {
1161                   debug_printf ("Is floppy, don't sync");
1162                   continue;
1163                 }
1164
1165               /* Eliminate trailing backslash. */
1166               vol[strlen (vol) - 1] = '\0';
1167               sync_worker (vol);
1168             }
1169           while (FindNextVolumeA (sh, vol, CYG_MAX_PATH));
1170           FindVolumeClose (sh);
1171         }
1172     }
1173   else if (wincap.is_winnt ())  /* 9x has no concept for opening volumes */
1174     {
1175       DWORD drives = GetLogicalDrives ();
1176       DWORD mask = 1;
1177       /* Skip floppies on A: and B: as in setmntent. */
1178       if ((drives & 1) && is_floppy ("A:"))
1179         drives &= ~1;
1180       if ((drives & 2) && is_floppy ("B:"))
1181         drives &= ~2;
1182       strcpy (vol, "\\\\.\\A:");
1183       do
1184         {
1185           /* Geeh.  Try to sync only non-floppy drives. */
1186           if (drives & mask)
1187             {
1188               debug_printf ("Try volume %s", vol);
1189               sync_worker (vol);
1190             }
1191           vol[4]++;
1192         }
1193       while ((mask <<= 1) <= 1 << 25);
1194     }
1195 }
1196
1197 /* Cygwin internal */
1198 static int __stdcall
1199 stat_worker (const char *name, struct __stat64 *buf, int nofollow)
1200 {
1201   int res = -1;
1202   fhandler_base *fh = NULL;
1203
1204   myfault efault;
1205   if (efault.faulted (EFAULT))
1206     goto error;
1207
1208   if (!(fh = build_fh_name (name, NULL, nofollow ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW,
1209                             stat_suffixes)))
1210     goto error;
1211
1212   if (fh->error ())
1213     {
1214       debug_printf ("got %d error from build_fh_name", fh->error ());
1215       set_errno (fh->error ());
1216     }
1217   else if (fh->exists ())
1218     {
1219       debug_printf ("(%s, %p, %d, %p), file_attributes %d", name, buf, nofollow,
1220                     fh, (DWORD) *fh);
1221       memset (buf, 0, sizeof (*buf));
1222       res = fh->fstat (buf);
1223       if (!res)
1224         {
1225           if (!buf->st_ino)
1226             buf->st_ino = fh->get_namehash ();
1227           if (!buf->st_dev)
1228             buf->st_dev = fh->get_device ();
1229           if (!buf->st_rdev)
1230             buf->st_rdev = buf->st_dev;
1231         }
1232     }
1233   else
1234     set_errno (ENOENT);
1235
1236   delete fh;
1237  error:
1238   MALLOC_CHECK;
1239   syscall_printf ("%d = (%s, %p)", res, name, buf);
1240   return res;
1241 }
1242
1243 extern "C" int
1244 stat64 (const char *name, struct __stat64 *buf)
1245 {
1246   syscall_printf ("entering");
1247   return stat_worker (name, buf, 0);
1248 }
1249
1250 extern "C" int
1251 _stat64_r (struct _reent *ptr, const char *name, struct __stat64 *buf)
1252 {
1253   int ret;
1254
1255   if ((ret = stat64 (name, buf)) == -1)
1256     ptr->_errno = get_errno ();
1257   return ret;
1258 }
1259
1260 extern "C" int
1261 stat (const char *name, struct __stat32 *buf)
1262 {
1263   struct __stat64 buf64;
1264   int ret = stat64 (name, &buf64);
1265   if (!ret)
1266     stat64_to_stat32 (&buf64, buf);
1267   return ret;
1268 }
1269
1270 extern "C" int
1271 _stat_r (struct _reent *ptr, const char *name, struct __stat32 *buf)
1272 {
1273   int ret;
1274
1275   if ((ret = stat (name, buf)) == -1)
1276     ptr->_errno = get_errno ();
1277   return ret;
1278 }
1279
1280 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
1281 extern "C" int
1282 lstat64 (const char *name, struct __stat64 *buf)
1283 {
1284   syscall_printf ("entering");
1285   return stat_worker (name, buf, 1);
1286 }
1287
1288 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
1289 extern "C" int
1290 lstat (const char *name, struct __stat32 *buf)
1291 {
1292   struct __stat64 buf64;
1293   int ret = lstat64 (name, &buf64);
1294   if (!ret)
1295     stat64_to_stat32 (&buf64, buf);
1296   return ret;
1297 }
1298
1299 extern "C" int
1300 access (const char *fn, int flags)
1301 {
1302   // flags were incorrectly specified
1303   int res = -1;
1304   if (flags & ~(F_OK|R_OK|W_OK|X_OK))
1305     set_errno (EINVAL);
1306   else
1307     {
1308       fhandler_base *fh = build_fh_name (fn, NULL, PC_SYM_FOLLOW, stat_suffixes);
1309       if (fh)
1310         {
1311           res =  fh->fhaccess (flags);
1312           delete fh;
1313         }
1314     }
1315   debug_printf ("returning %d", res);
1316   return res;
1317 }
1318
1319 extern "C" int
1320 rename (const char *oldpath, const char *newpath)
1321 {
1322   int res = 0;
1323   char *lnk_suffix = NULL;
1324   bool no_lnk_file_exists = false;
1325
1326   path_conv real_old (oldpath, PC_SYM_NOFOLLOW,
1327                       transparent_exe ? stat_suffixes : NULL);
1328
1329   if (real_old.error)
1330     {
1331       syscall_printf ("-1 = rename (%s, %s)", oldpath, newpath);
1332       set_errno (real_old.error);
1333       return -1;
1334     }
1335
1336   if (!real_old.exists ()) /* file to move doesn't exist */
1337     {
1338       syscall_printf ("file to move doesn't exist");
1339       set_errno (ENOENT);
1340       return -1;
1341     }
1342
1343   path_conv real_new (newpath, PC_SYM_NOFOLLOW,
1344                       transparent_exe ? stat_suffixes : NULL);
1345
1346   char new_buf[CYG_MAX_PATH + 5];
1347   if (!real_new.error && !real_new.case_clash)
1348     {
1349       DWORD bintype;
1350       int len;
1351
1352       if (real_old.is_lnk_special ())
1353         {
1354           if (real_new.exists ())
1355             {
1356               /* This early directory test is necessary because the below test
1357                  tests against the name with attached .lnk suffix.  To avoid
1358                  name collisions, we shouldn't rename a file to "foo.lnk"
1359                  if a "foo" directory exists. */
1360               if (real_new.isdir ())
1361                 {
1362                   syscall_printf ("newpath is directory, but oldpath is not");
1363                   set_errno (EISDIR);
1364                   return -1;
1365                 }
1366               /* Shortcut hack, No. 3, part 1 */
1367               no_lnk_file_exists = true;
1368             }
1369           /* Shortcut hack. */
1370           strcpy (new_buf, newpath);
1371           strcat (new_buf, ".lnk");
1372           newpath = new_buf;
1373           real_new.check (newpath, PC_SYM_NOFOLLOW);
1374         }
1375       else if (transparent_exe
1376                && !real_old.isdir ()
1377                && GetBinaryType (real_old, &bintype)
1378                && (len = strlen (real_new)) > 4
1379                && !strcasematch ((const char *) real_new + len - 4, ".exe"))
1380         {
1381           /* Executable hack. */
1382           strcpy (new_buf, newpath);
1383           strcat (new_buf, ".exe");
1384           newpath = new_buf;
1385           real_new.check (newpath, PC_SYM_NOFOLLOW);
1386         }
1387     }
1388
1389   if (real_new.error || real_new.case_clash)
1390     {
1391       syscall_printf ("-1 = rename (%s, %s)", oldpath, newpath);
1392       set_errno (real_new.case_clash ? ECASECLASH : real_new.error);
1393       return -1;
1394     }
1395
1396   if (real_new.isdir () && !real_old.isdir ())
1397     {
1398       syscall_printf ("newpath is directory, but oldpath is not");
1399       set_errno (EISDIR);
1400       return -1;
1401     }
1402
1403   /* Destination file exists and is read only, change that or else
1404      the rename won't work. */
1405   if (real_new.has_attribute (FILE_ATTRIBUTE_READONLY))
1406     SetFileAttributes (real_new, (DWORD) real_new & ~FILE_ATTRIBUTE_READONLY);
1407
1408   /* Shortcut hack No. 2, part 1 */
1409   if (!real_old.issymlink () && !real_new.error && real_new.is_lnk_special ()
1410       && (lnk_suffix = strrchr (real_new.get_win32 (), '.')))
1411      *lnk_suffix = '\0';
1412
1413   if (MoveFile (real_old, real_new))
1414     goto done;
1415
1416   res = -1;
1417
1418   /* Test for an attempt to make a directory a subdirectory of itself first.
1419      This test has to be made before any attempt to remove the potentially
1420      existing file or directory real_new.  Otherwise we end up with a
1421      non-moved directory *and* a deleted read_new path.  Also this case
1422      has to generate an EINVAL in all circumstances,
1423
1424      NB: We could test this also before calling MoveFile but the idea is
1425      that this is a somewhat seldom case and we like to avoid expensive
1426      string comparison.  So we allow MoveFile to fail and test the error
1427      code instead.
1428
1429      The order in the condition is (hopefully) trimmed for doing the least
1430      expensive stuff first.  Nevertheless it would be nice if 9x could
1431      generate the same error codes as NT.
1432      NT generates ERROR_SHARING_VIOLATION in all cases, while 9x generates
1433      ERROR_ACCESS_DENIED if the target path doesn't exist,
1434      ERROR_ALREADY_EXISTS otherwise */
1435   int len;
1436   DWORD lasterr;
1437   lasterr = GetLastError ();
1438   if (real_old.isdir ()
1439       && ((lasterr == ERROR_SHARING_VIOLATION && wincap.has_move_file_ex ())
1440        || (lasterr == ERROR_ACCESS_DENIED && !real_new.exists ()
1441            && !wincap.has_move_file_ex ())
1442        || (lasterr == ERROR_ALREADY_EXISTS && real_new.exists ()
1443            && !wincap.has_move_file_ex ()))
1444       && (len = strlen (real_old), strncasematch (real_old, real_new, len))
1445       && real_new[len] == '\\')
1446     SetLastError (ERROR_INVALID_PARAMETER);
1447   else if (real_new.isdir ())
1448     {
1449       /* Since neither MoveFileEx(MOVEFILE_REPLACE_EXISTING) nor DeleteFile
1450          allow to remove directories, this case is handled separately. */
1451       if (!RemoveDirectoryA (real_new))
1452         {
1453           syscall_printf ("Can't remove target directory");
1454           /* On 9X ERROR_ACCESS_DENIED is returned if you try to remove
1455              a non-empty directory. */
1456           if (GetLastError () == ERROR_ACCESS_DENIED
1457               && wincap.access_denied_on_delete ())
1458             SetLastError (ERROR_DIR_NOT_EMPTY);
1459         }
1460       else if (MoveFile (real_old, real_new))
1461         res = 0;
1462     }
1463   else if (wincap.has_move_file_ex ())
1464     {
1465       if (MoveFileEx (real_old.get_win32 (), real_new.get_win32 (),
1466                       MOVEFILE_REPLACE_EXISTING))
1467         res = 0;
1468     }
1469   else if (lasterr == ERROR_ALREADY_EXISTS || lasterr == ERROR_FILE_EXISTS)
1470     {
1471       syscall_printf ("try win95 hack");
1472       for (int i = 0; i < 2; i++)
1473         {
1474           if (!DeleteFileA (real_new) &&
1475               GetLastError () != ERROR_FILE_NOT_FOUND)
1476             {
1477               syscall_printf ("deleting %s to be paranoid",
1478                               real_new.get_win32 ());
1479               break;
1480             }
1481           else if (MoveFile (real_old, real_new))
1482             {
1483               res = 0;
1484               break;
1485             }
1486         }
1487     }
1488
1489 done:
1490   if (res)
1491     {
1492       __seterrno ();
1493       /* Reset R/O attributes if neccessary. */
1494       if (real_new.has_attribute (FILE_ATTRIBUTE_READONLY))
1495         SetFileAttributes (real_new, real_new);
1496     }
1497   else
1498     {
1499       /* make the new file have the permissions of the old one */
1500       DWORD attr = real_old;
1501 #ifdef HIDDEN_DOT_FILES
1502       char *c = strrchr (real_old.get_win32 (), '\\');
1503       if ((c && c[1] == '.') || *real_old.get_win32 () == '.')
1504         attr &= ~FILE_ATTRIBUTE_HIDDEN;
1505       c = strrchr (real_new.get_win32 (), '\\');
1506       if ((c && c[1] == '.') || *real_new.get_win32 () == '.')
1507         attr |= FILE_ATTRIBUTE_HIDDEN;
1508 #endif
1509       SetFileAttributes (real_new, attr);
1510
1511       /* Shortcut hack, No. 2, part 2 */
1512       /* if the new filename was an existing shortcut, remove it now if the
1513          new filename is equal to the shortcut name without .lnk suffix. */
1514       if (lnk_suffix)
1515         {
1516           *lnk_suffix = '.';
1517           DeleteFile (real_new);
1518         }
1519       /* Shortcut hack, No. 3, part 2 */
1520       /* If a file with the given name exists, it must be deleted after the
1521          symlink has been renamed.  Otherwise we end up with two files of
1522          the same name in the directory, one file "newpath", which already
1523          exited before rename has been called, and one file "newpath.lnk",
1524          which is the result of the rename operation. */
1525       else if (no_lnk_file_exists)
1526         {
1527           lnk_suffix = strrchr (real_new.get_win32 (), '.');
1528           *lnk_suffix = '\0';
1529           DeleteFile (real_new);
1530         }
1531     }
1532
1533   syscall_printf ("%d = rename (%s, %s)", res, (char *) real_old,
1534                   (char *) real_new);
1535
1536   return res;
1537 }
1538
1539 extern "C" int
1540 system (const char *cmdstring)
1541 {
1542   pthread_testcancel ();
1543
1544   myfault efault;
1545   if (efault.faulted (EFAULT))
1546     return -1;
1547
1548   int res;
1549   const char* command[4];
1550
1551   if (cmdstring == NULL)
1552     return 1;
1553
1554   command[0] = "sh";
1555   command[1] = "-c";
1556   command[2] = cmdstring;
1557   command[3] = (const char *) NULL;
1558
1559   if ((res = spawnvp (_P_SYSTEM, "/bin/sh", command)) == -1)
1560     {
1561       // when exec fails, return value should be as if shell
1562       // executed exit (127)
1563       res = 127;
1564     }
1565
1566   return res;
1567 }
1568
1569 extern "C" int
1570 setdtablesize (int size)
1571 {
1572   if (size <= (int)cygheap->fdtab.size || cygheap->fdtab.extend (size - cygheap->fdtab.size))
1573     return 0;
1574
1575   return -1;
1576 }
1577
1578 extern "C" int
1579 getdtablesize ()
1580 {
1581   return cygheap->fdtab.size > OPEN_MAX ? cygheap->fdtab.size : OPEN_MAX;
1582 }
1583
1584 extern "C" size_t
1585 getpagesize ()
1586 {
1587   if (!system_info.dwAllocationGranularity)
1588     GetSystemInfo (&system_info);
1589   return (size_t) system_info.dwAllocationGranularity;
1590 }
1591
1592 size_t
1593 getsystempagesize ()
1594 {
1595   if (!system_info.dwPageSize)
1596     GetSystemInfo (&system_info);
1597   return (size_t) system_info.dwPageSize;
1598 }
1599
1600 /* FIXME: not all values are correct... */
1601 extern "C" long int
1602 fpathconf (int fd, int v)
1603 {
1604   cygheap_fdget cfd (fd);
1605   if (cfd < 0)
1606     return -1;
1607   return cfd->fpathconf (v);
1608 }
1609
1610 extern "C" long int
1611 pathconf (const char *file, int v)
1612 {
1613   fhandler_base *fh;
1614
1615   myfault efault;
1616   if (efault.faulted (EFAULT))
1617     return -1;
1618   if (!*file)
1619     {
1620       set_errno (ENOENT);
1621       return -1;
1622     }
1623   if (!(fh = build_fh_name (file, NULL, PC_SYM_FOLLOW,
1624                             transparent_exe ? stat_suffixes : NULL)))
1625     return -1;
1626   if (!fh->exists ())
1627     {
1628       set_errno (ENOENT);
1629       return -1;
1630     }
1631   return fh->fpathconf (v);
1632 }
1633
1634 extern "C" int
1635 ttyname_r (int fd, char *buf, size_t buflen)
1636 {
1637   int ret = 0;
1638   myfault efault;
1639   if (efault.faulted ())
1640     ret = EFAULT;
1641   else
1642     {
1643       cygheap_fdget cfd (fd, true);
1644       if (cfd < 0)
1645         ret = EBADF;
1646       else if (!cfd->is_tty ())
1647         ret = ENOTTY;
1648       else if (buflen < strlen (cfd->ttyname ()) + 1)
1649         ret = ERANGE;
1650       else
1651         strcpy (buf, cfd->ttyname ());
1652     }
1653   debug_printf ("returning %d tty: %s", ret, ret ? "NULL" : buf);
1654   return ret;
1655 }
1656
1657 extern "C" char *
1658 ttyname (int fd)
1659 {
1660   static char name[TTY_NAME_MAX + 1];
1661   int ret = ttyname_r (fd, name, TTY_NAME_MAX + 1);
1662   if (ret)
1663     {
1664       set_errno (ret);
1665       return NULL;
1666     }
1667   return name;
1668 }
1669
1670 extern "C" char *
1671 ctermid (char *str)
1672 {
1673   static NO_COPY char buf[16];
1674   if (str == NULL)
1675     str = buf;
1676   if (!real_tty_attached (myself))
1677     strcpy (str, "/dev/conin");
1678   else
1679     __small_sprintf (str, "/dev/tty%d", myself->ctty);
1680   return str;
1681 }
1682
1683 /* Tells stdio if it should do the cr/lf conversion for this file */
1684 extern "C" int
1685 _cygwin_istext_for_stdio (int fd)
1686 {
1687   if (CYGWIN_VERSION_OLD_STDIO_CRLF_HANDLING)
1688     {
1689       syscall_printf ("fd %d: old API", fd);
1690       return 0; /* we do it for old apps, due to getc/putc macros */
1691     }
1692
1693   cygheap_fdget cfd (fd, false, false);
1694   if (cfd < 0)
1695     {
1696       syscall_printf ("fd %d: not open", fd);
1697       return 0;
1698     }
1699
1700 #if 0
1701   if (cfd->get_device () != FH_FS)
1702     {
1703       syscall_printf ("fd not disk file.  Defaulting to binary.");
1704       return 0;
1705     }
1706 #endif
1707
1708   if (cfd->wbinary () || cfd->rbinary ())
1709     {
1710       syscall_printf ("fd %d: opened as binary", fd);
1711       return 0;
1712     }
1713
1714   syscall_printf ("fd %d: defaulting to text", fd);
1715   return 1;
1716 }
1717
1718 /* internal newlib function */
1719 extern "C" int _fwalk (struct _reent *ptr, int (*function) (FILE *));
1720
1721 static int
1722 setmode_helper (FILE *f)
1723 {
1724   if (fileno (f) != _my_tls.locals.setmode_file)
1725     {
1726       syscall_printf ("improbable, but %d != %d", fileno (f), _my_tls.locals.setmode_file);
1727       return 0;
1728     }
1729   syscall_printf ("file was %s now %s", f->_flags & __SCLE ? "text" : "binary",
1730                   _my_tls.locals.setmode_mode & O_TEXT ? "text" : "binary");
1731   if (_my_tls.locals.setmode_mode & O_TEXT)
1732     f->_flags |= __SCLE;
1733   else
1734     f->_flags &= ~__SCLE;
1735   return 0;
1736 }
1737
1738 extern "C" int
1739 getmode (int fd)
1740 {
1741   cygheap_fdget cfd (fd);
1742   if (cfd < 0)
1743     return -1;
1744
1745   return cfd->get_flags () & (O_BINARY | O_TEXT);
1746 }
1747
1748 /* Set a file descriptor into text or binary mode, returning the
1749    previous mode.  */
1750
1751 extern "C" int
1752 setmode (int fd, int mode)
1753 {
1754   cygheap_fdget cfd (fd);
1755   if (cfd < 0)
1756     return -1;
1757   if (mode != O_BINARY  && mode != O_TEXT && mode != 0)
1758     {
1759       set_errno (EINVAL);
1760       return -1;
1761     }
1762
1763   /* Note that we have no way to indicate the case that writes are
1764      binary but not reads, or vice-versa.  These cases can arise when
1765      using the tty or console interface.  People using those
1766      interfaces should not use setmode.  */
1767
1768   int res;
1769   if (cfd->wbinary () && cfd->rbinary ())
1770     res = O_BINARY;
1771   else if (cfd->wbinset () && cfd->rbinset ())
1772     res = O_TEXT;       /* Specifically set O_TEXT */
1773   else
1774     res = 0;
1775
1776   if (!mode)
1777     cfd->reset_to_open_binmode ();
1778   else
1779     cfd->set_flags ((cfd->get_flags () & ~(O_TEXT | O_BINARY)) | mode);
1780
1781   syscall_printf ("(%d<%s>, %p) returning %s", fd, cfd->get_name (),
1782                   mode, res & O_TEXT ? "text" : "binary");
1783   return res;
1784 }
1785
1786 extern "C" int
1787 cygwin_setmode (int fd, int mode)
1788 {
1789   int res = setmode (fd, mode);
1790   if (res != -1)
1791     {
1792       _my_tls.locals.setmode_file = fd;
1793       if (_cygwin_istext_for_stdio (fd))
1794         _my_tls.locals.setmode_mode = O_TEXT;
1795       else
1796         _my_tls.locals.setmode_mode = O_BINARY;
1797       _fwalk (_GLOBAL_REENT, setmode_helper);
1798     }
1799   return res;
1800 }
1801
1802 extern "C" int
1803 posix_fadvise (int fd, _off64_t offset, _off64_t len, int advice)
1804 {
1805   int res = -1;
1806   cygheap_fdget cfd (fd);
1807   if (cfd >= 0)
1808     res = cfd->fadvise (offset, len, advice);
1809   else
1810     set_errno (EBADF);
1811   syscall_printf ("%d = posix_fadvice (%d, %D, %D, %d)",
1812                   res, fd, offset, len, advice);
1813   return res;
1814 }
1815
1816 extern "C" int
1817 posix_fallocate (int fd, _off64_t offset, _off64_t len)
1818 {
1819   int res = -1;
1820   if (offset < 0 || len == 0)
1821     set_errno (EINVAL);
1822   else
1823     {
1824       cygheap_fdget cfd (fd);
1825       if (cfd >= 0)
1826         res = cfd->ftruncate (offset + len, false);
1827       else
1828         set_errno (EBADF);
1829     }
1830   syscall_printf ("%d = posix_fallocate (%d, %D, %D)", res, fd, offset, len);
1831   return res;
1832 }
1833
1834 extern "C" int
1835 ftruncate64 (int fd, _off64_t length)
1836 {
1837   int res = -1;
1838   cygheap_fdget cfd (fd);
1839   if (cfd >= 0)
1840     res = cfd->ftruncate (length, true);
1841   else
1842     set_errno (EBADF);
1843   syscall_printf ("%d = ftruncate (%d, %D)", res, fd, length);
1844   return res;
1845 }
1846
1847 /* ftruncate: P96 5.6.7.1 */
1848 extern "C" int
1849 ftruncate (int fd, _off_t length)
1850 {
1851   return ftruncate64 (fd, (_off64_t)length);
1852 }
1853
1854 /* truncate: Provided by SVR4 and 4.3+BSD.  Not part of POSIX.1 or XPG3 */
1855 extern "C" int
1856 truncate64 (const char *pathname, _off64_t length)
1857 {
1858   int fd;
1859   int res = -1;
1860
1861   fd = open (pathname, O_RDWR);
1862
1863   if (fd != -1)
1864     {
1865       res = ftruncate64 (fd, length);
1866       close (fd);
1867     }
1868   syscall_printf ("%d = truncate (%s, %D)", res, pathname, length);
1869
1870   return res;
1871 }
1872
1873 /* truncate: Provided by SVR4 and 4.3+BSD.  Not part of POSIX.1 or XPG3 */
1874 extern "C" int
1875 truncate (const char *pathname, _off_t length)
1876 {
1877   return truncate64 (pathname, (_off64_t)length);
1878 }
1879
1880 extern "C" long
1881 get_osfhandle (int fd)
1882 {
1883   long res;
1884
1885   cygheap_fdget cfd (fd);
1886   if (cfd >= 0)
1887     res = (long) cfd->get_handle ();
1888   else
1889     res = -1;
1890
1891   syscall_printf ("%d = get_osfhandle (%d)", res, fd);
1892   return res;
1893 }
1894
1895 extern "C" int
1896 statvfs (const char *fname, struct statvfs *sfs)
1897 {
1898   int ret = -1;
1899   char root[CYG_MAX_PATH];
1900
1901   myfault efault;
1902   if (efault.faulted (EFAULT))
1903     return -1;
1904   if (!*fname)
1905     {
1906       set_errno (ENOENT);
1907       return -1;
1908     }
1909
1910   syscall_printf ("statfs %s", fname);
1911
1912   if (!sfs)
1913     {
1914       set_errno (EFAULT);
1915       return -1;
1916     }
1917
1918   path_conv full_path (fname, PC_SYM_FOLLOW);
1919   if (!full_path.rootdir (root))
1920     {
1921       set_errno (ENOTDIR);
1922       return -1;
1923     }
1924
1925   ULARGE_INTEGER availb, freeb, totalb;
1926   DWORD spc, bps, availc, freec, totalc, vsn, maxlen, flags;
1927   BOOL status, statusex;
1928
1929   /* GetDiskFreeSpaceEx must be called before GetDiskFreeSpace on
1930      WinME, to avoid the MS KB 314417 bug */
1931   statusex = GetDiskFreeSpaceEx (root, &availb, &totalb, &freeb);
1932   status = GetDiskFreeSpace (root, &spc, &bps, &freec, &totalc);
1933   if (!status && statusex)
1934     {
1935       /* Grrr, this can happen on 9x when a share isn't attached to
1936          a drive letter.  Fake, fake, hoorah. */
1937       status = TRUE;
1938       bps = 512;
1939       spc = 8;
1940       while ((totalb.QuadPart % (spc*bps)) && spc > 1)
1941         spc >>= 1;
1942     }
1943   if (status)
1944     {
1945       if (statusex)
1946         {
1947           availc = availb.QuadPart / (spc*bps);
1948           totalc = totalb.QuadPart / (spc*bps);
1949           freec = freeb.QuadPart / (spc*bps);
1950           if (freec > availc)
1951             {
1952               /* Quotas active.  We can't trust totalc. */
1953               HANDLE hdl = CreateFile (full_path, READ_CONTROL,
1954                                        wincap.shared (), &sec_none_nih,
1955                                        OPEN_EXISTING,
1956                                        FILE_FLAG_BACKUP_SEMANTICS, NULL);
1957               if (hdl == INVALID_HANDLE_VALUE)
1958                 debug_printf ("CreateFile (%s) failed, %E", (char *) full_path);
1959               else
1960                 {
1961                   NTFS_VOLUME_DATA_BUFFER nvdb;
1962                   DWORD bytes;
1963                   if (!DeviceIoControl (hdl, FSCTL_GET_NTFS_VOLUME_DATA, NULL,
1964                                         0, &nvdb, sizeof nvdb, &bytes, NULL))
1965                     debug_printf ("DeviceIoControl (%s) failed, %E", (char *) full_path);
1966                   else
1967                     totalc = nvdb.TotalClusters.QuadPart;
1968                   CloseHandle (hdl);
1969                 }
1970             }
1971         }
1972       else
1973         availc = freec;
1974       if (GetVolumeInformation (root, NULL, 0, &vsn, &maxlen, &flags, NULL, 0))
1975         {
1976           sfs->f_bsize = spc*bps;
1977           sfs->f_frsize = spc*bps;
1978           sfs->f_blocks = totalc;
1979           sfs->f_bfree = freec;
1980           sfs->f_bavail = availc;
1981           sfs->f_files = ULONG_MAX;
1982           sfs->f_ffree = ULONG_MAX;
1983           sfs->f_favail = ULONG_MAX;
1984           sfs->f_fsid = vsn;
1985           sfs->f_flag = flags;
1986           sfs->f_namemax = maxlen;
1987           ret = 0;
1988         }
1989     }
1990   if (ret)
1991     __seterrno ();
1992
1993   return ret;
1994 }
1995
1996 extern "C" int
1997 fstatvfs (int fd, struct statvfs *sfs)
1998 {
1999   cygheap_fdget cfd (fd);
2000   if (cfd < 0)
2001     return -1;
2002   return statvfs (cfd->get_name (), sfs);
2003 }
2004
2005 extern "C" int
2006 statfs (const char *fname, struct statfs *sfs)
2007 {
2008   myfault efault;
2009   if (efault.faulted (EFAULT))
2010     return -1;
2011   struct statvfs vfs;
2012   int ret = statvfs (fname, &vfs);
2013   if (!ret)
2014     {
2015       sfs->f_type = vfs.f_flag;
2016       sfs->f_bsize = vfs.f_bsize;
2017       sfs->f_blocks = vfs.f_blocks;
2018       sfs->f_bavail = vfs.f_bavail;
2019       sfs->f_bfree = vfs.f_bfree;
2020       sfs->f_files = -1;
2021       sfs->f_ffree = -1;
2022       sfs->f_fsid = vfs.f_fsid;
2023       sfs->f_namelen = vfs.f_namemax;
2024     }
2025   return ret;
2026 }
2027
2028 extern "C" int
2029 fstatfs (int fd, struct statfs *sfs)
2030 {
2031   cygheap_fdget cfd (fd);
2032   if (cfd < 0)
2033     return -1;
2034   return statfs (cfd->get_name (), sfs);
2035 }
2036
2037 /* setpgid: POSIX 4.3.3.1 */
2038 extern "C" int
2039 setpgid (pid_t pid, pid_t pgid)
2040 {
2041   int res = -1;
2042   if (pid == 0)
2043     pid = getpid ();
2044   if (pgid == 0)
2045     pgid = pid;
2046
2047   if (pgid < 0)
2048     set_errno (EINVAL);
2049   else
2050     {
2051       pinfo p (pid, PID_MAP_RW);
2052       if (!p)
2053         set_errno (ESRCH);
2054       else if (p->pgid == pgid)
2055         res = 0;
2056       /* A process may only change the process group of itself and its children */
2057       else if (p != myself && p->ppid != myself->pid)
2058         set_errno (EPERM);
2059       else
2060         {
2061           p->pgid = pgid;
2062           if (p->pid != p->pgid)
2063             p->set_has_pgid_children (0);
2064           res = 0;
2065         }
2066     }
2067
2068   syscall_printf ("pid %d, pgid %d, res %d", pid, pgid, res);
2069   return res;
2070 }
2071
2072 extern "C" pid_t
2073 getpgid (pid_t pid)
2074 {
2075   if (pid == 0)
2076     pid = getpid ();
2077
2078   pinfo p (pid);
2079   if (p == 0)
2080     {
2081       set_errno (ESRCH);
2082       return -1;
2083     }
2084   return p->pgid;
2085 }
2086
2087 extern "C" int
2088 setpgrp (void)
2089 {
2090   return setpgid (0, 0);
2091 }
2092
2093 extern "C" pid_t
2094 getpgrp (void)
2095 {
2096   return getpgid (0);
2097 }
2098
2099 extern "C" char *
2100 ptsname (int fd)
2101 {
2102   cygheap_fdget cfd (fd);
2103   if (cfd < 0)
2104     return 0;
2105   return (char *) (cfd->ptsname ());
2106 }
2107
2108 /* FIXME: what is this? */
2109 extern "C" int __declspec(dllexport)
2110 regfree ()
2111 {
2112   return 0;
2113 }
2114
2115 static int __stdcall
2116 mknod_worker (const char *path, mode_t type, mode_t mode, _major_t major,
2117               _minor_t minor)
2118 {
2119   char buf[sizeof (":\\00000000:00000000:00000000") + CYG_MAX_PATH];
2120   sprintf (buf, ":\\%x:%x:%x", major, minor,
2121            type | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)));
2122   return symlink_worker (buf, path, true, true);
2123 }
2124
2125 extern "C" int
2126 mknod32 (const char *path, mode_t mode, __dev32_t dev)
2127 {
2128   myfault efault;
2129   if (efault.faulted (EFAULT))
2130     return -1;
2131   if (!*path)
2132     {
2133       set_errno (ENOENT);
2134       return -1;
2135     }
2136
2137   if (strlen (path) >= CYG_MAX_PATH)
2138     return -1;
2139
2140   path_conv w32path (path, PC_SYM_NOFOLLOW);
2141   if (w32path.exists ())
2142     {
2143       set_errno (EEXIST);
2144       return -1;
2145     }
2146
2147   mode_t type = mode & S_IFMT;
2148   _major_t major = _major (dev);
2149   _minor_t minor = _minor (dev);
2150   switch (type)
2151     {
2152     case S_IFCHR:
2153     case S_IFBLK:
2154       break;
2155
2156     case S_IFIFO:
2157       major = _major (FH_FIFO);
2158       minor = _minor (FH_FIFO);
2159       break;
2160
2161     case 0:
2162     case S_IFREG:
2163       {
2164         int fd = open (path, O_CREAT, mode);
2165         if (fd < 0)
2166           return -1;
2167         close (fd);
2168         return 0;
2169       }
2170
2171     default:
2172       set_errno (EINVAL);
2173       return -1;
2174     }
2175
2176   return mknod_worker (w32path, type, mode, major, minor);
2177 }
2178
2179 extern "C" int
2180 mknod (const char *_path, mode_t mode, __dev16_t dev)
2181 {
2182   return mknod32 (_path, mode, (__dev32_t) dev);
2183 }
2184
2185 extern "C" int
2186 mkfifo (const char *path, mode_t mode)
2187 {
2188   return mknod32 (path, (mode & ~S_IFMT) | S_IFIFO, 0);
2189 }
2190
2191 /* seteuid: standards? */
2192 extern "C" int
2193 seteuid32 (__uid32_t uid)
2194 {
2195   debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
2196                 uid, myself->uid, myself->gid);
2197
2198   if (uid == myself->uid && !cygheap->user.groups.ischanged)
2199     {
2200       debug_printf ("Nothing happens");
2201       return 0;
2202     }
2203
2204   cygsid usersid;
2205   user_groups &groups = cygheap->user.groups;
2206   HANDLE new_token = INVALID_HANDLE_VALUE;
2207   struct passwd * pw_new;
2208   bool token_is_internal, issamesid = false;
2209
2210   pw_new = internal_getpwuid (uid);
2211   if (!wincap.has_security () && pw_new)
2212     {
2213       load_registry_hive (pw_new->pw_name);
2214       goto success_9x;
2215     }
2216   if (!usersid.getfrompw (pw_new))
2217     {
2218       set_errno (EINVAL);
2219       return -1;
2220     }
2221
2222   cygheap->user.deimpersonate ();
2223
2224   /* Verify if the process token is suitable. */
2225   if (verify_token (hProcToken, usersid, groups))
2226     new_token = hProcToken;
2227   /* Verify if the external token is suitable */
2228   else if (cygheap->user.external_token != NO_IMPERSONATION
2229            && verify_token (cygheap->user.external_token, usersid, groups))
2230     new_token = cygheap->user.external_token;
2231   /* Verify if the current token (internal or former external) is suitable */
2232   else if (cygheap->user.curr_primary_token != NO_IMPERSONATION
2233            && cygheap->user.curr_primary_token != cygheap->user.external_token
2234            && verify_token (cygheap->user.curr_primary_token, usersid, groups,
2235                             &token_is_internal))
2236     new_token = cygheap->user.curr_primary_token;
2237   /* Verify if the internal token is suitable */
2238   else if (cygheap->user.internal_token != NO_IMPERSONATION
2239            && cygheap->user.internal_token != cygheap->user.curr_primary_token
2240            && verify_token (cygheap->user.internal_token, usersid, groups,
2241                             &token_is_internal))
2242     new_token = cygheap->user.internal_token;
2243
2244   debug_printf ("Found token %d", new_token);
2245
2246   /* If no impersonation token is available, try to
2247      authenticate using NtCreateToken () or LSA authentication. */
2248   if (new_token == INVALID_HANDLE_VALUE)
2249     {
2250       if (!(new_token = lsaauth (usersid, groups, pw_new)))
2251         {
2252           debug_printf ("lsaauth failed, try create_token.");
2253           new_token = create_token (usersid, groups, pw_new);
2254           if (new_token == INVALID_HANDLE_VALUE)
2255             {
2256               debug_printf ("create_token failed, bail out of here");
2257               cygheap->user.reimpersonate ();
2258               return -1;
2259             }
2260         }
2261
2262       /* Keep at most one internal token */
2263       if (cygheap->user.internal_token != NO_IMPERSONATION)
2264         CloseHandle (cygheap->user.internal_token);
2265       cygheap->user.internal_token = new_token;
2266     }
2267
2268   if (new_token != hProcToken)
2269     {
2270       /* Avoid having HKCU use default user */
2271       char name[128];
2272       load_registry_hive (usersid.string (name));
2273
2274       /* Try setting owner to same value as user. */
2275       if (!SetTokenInformation (new_token, TokenOwner,
2276                                 &usersid, sizeof usersid))
2277         debug_printf ("SetTokenInformation(user.token, TokenOwner), %E");
2278       /* Try setting primary group in token to current group */
2279       if (!SetTokenInformation (new_token, TokenPrimaryGroup,
2280                                 &groups.pgsid, sizeof (cygsid)))
2281         debug_printf ("SetTokenInformation(user.token, TokenPrimaryGroup), %E");
2282       /* Try setting default DACL */
2283       PACL dacl_buf = (PACL) alloca (MAX_DACL_LEN (5));
2284       if (sec_acl (dacl_buf, true, true, usersid))
2285         {
2286           TOKEN_DEFAULT_DACL tdacl = { dacl_buf };
2287           if (!SetTokenInformation (new_token, TokenDefaultDacl,
2288                                     &tdacl, sizeof (tdacl)))
2289             debug_printf ("SetTokenInformation (TokenDefaultDacl), %E");
2290         }
2291     }
2292
2293   issamesid = (usersid == cygheap->user.sid ());
2294   cygheap->user.set_sid (usersid);
2295   cygheap->user.curr_primary_token = new_token == hProcToken ? NO_IMPERSONATION
2296                                                         : new_token;
2297   if (cygheap->user.current_token != NO_IMPERSONATION)
2298     {
2299       CloseHandle (cygheap->user.current_token);
2300       cygheap->user.current_token = NO_IMPERSONATION;
2301     }
2302   if (cygheap->user.curr_primary_token != NO_IMPERSONATION)
2303     {
2304       if (!DuplicateTokenEx (cygheap->user.curr_primary_token, MAXIMUM_ALLOWED,
2305                              &sec_none, SecurityImpersonation,
2306                              TokenImpersonation, &cygheap->user.current_token))
2307         {
2308           __seterrno ();
2309           cygheap->user.curr_primary_token = NO_IMPERSONATION;
2310           return -1;
2311         }
2312       set_cygwin_privileges (cygheap->user.current_token);
2313     }
2314   if (!cygheap->user.reimpersonate ())
2315     {
2316       __seterrno ();
2317       return -1;
2318     }
2319
2320 success_9x:
2321   cygheap->user.set_name (pw_new->pw_name);
2322   myself->uid = uid;
2323   groups.ischanged = FALSE;
2324   if (!issamesid)
2325     user_shared_initialize (true);
2326   return 0;
2327 }
2328
2329 extern "C" int
2330 seteuid (__uid16_t uid)
2331 {
2332   return seteuid32 (uid16touid32 (uid));
2333 }
2334
2335 /* setuid: POSIX 4.2.2.1 */
2336 extern "C" int
2337 setuid32 (__uid32_t uid)
2338 {
2339   int ret = seteuid32 (uid);
2340   if (!ret)
2341     cygheap->user.real_uid = myself->uid;
2342   debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
2343   return ret;
2344 }
2345
2346 extern "C" int
2347 setuid (__uid16_t uid)
2348 {
2349   return setuid32 (uid16touid32 (uid));
2350 }
2351
2352 extern "C" int
2353 setreuid32 (__uid32_t ruid, __uid32_t euid)
2354 {
2355   int ret = 0;
2356   bool tried = false;
2357   __uid32_t old_euid = myself->uid;
2358
2359   if (ruid != ILLEGAL_UID && cygheap->user.real_uid != ruid && euid != ruid)
2360     tried = !(ret = seteuid32 (ruid));
2361   if (!ret && euid != ILLEGAL_UID)
2362     ret = seteuid32 (euid);
2363   if (tried && (ret || euid == ILLEGAL_UID) && seteuid32 (old_euid))
2364     system_printf ("Cannot restore original euid %u", old_euid);
2365   if (!ret && ruid != ILLEGAL_UID)
2366     cygheap->user.real_uid = ruid;
2367   debug_printf ("real: %u, effective: %u", cygheap->user.real_uid, myself->uid);
2368   return ret;
2369 }
2370
2371 extern "C" int
2372 setreuid (__uid16_t ruid, __uid16_t euid)
2373 {
2374   return setreuid32 (uid16touid32 (ruid), uid16touid32 (euid));
2375 }
2376
2377 /* setegid: from System V.  */
2378 extern "C" int
2379 setegid32 (__gid32_t gid)
2380 {
2381   debug_printf ("new egid: %u current: %u", gid, myself->gid);
2382
2383   if (gid == myself->gid || !wincap.has_security ())
2384     {
2385       myself->gid = gid;
2386       return 0;
2387     }
2388
2389   user_groups * groups = &cygheap->user.groups;
2390   cygsid gsid;
2391   struct __group32 * gr = internal_getgrgid (gid);
2392
2393   if (!gsid.getfromgr (gr))
2394     {
2395       set_errno (EINVAL);
2396       return -1;
2397     }
2398   myself->gid = gid;
2399
2400   groups->update_pgrp (gsid);
2401   if (cygheap->user.issetuid ())
2402     {
2403       /* If impersonated, update impersonation token... */
2404       if (!SetTokenInformation (cygheap->user.primary_token (),
2405                                 TokenPrimaryGroup, &gsid, sizeof gsid))
2406         debug_printf ("SetTokenInformation(primary_token, "
2407                       "TokenPrimaryGroup), %E");
2408       if (!SetTokenInformation (cygheap->user.token (), TokenPrimaryGroup,
2409                                 &gsid, sizeof gsid))
2410         debug_printf ("SetTokenInformation(token, TokenPrimaryGroup), %E");
2411     }
2412   cygheap->user.deimpersonate ();
2413   if (!SetTokenInformation (hProcToken, TokenPrimaryGroup, &gsid, sizeof gsid))
2414     debug_printf ("SetTokenInformation(hProcToken, TokenPrimaryGroup), %E");
2415   clear_procimptoken ();
2416   cygheap->user.reimpersonate ();
2417   return 0;
2418 }
2419
2420 extern "C" int
2421 setegid (__gid16_t gid)
2422 {
2423   return setegid32 (gid16togid32 (gid));
2424 }
2425
2426 /* setgid: POSIX 4.2.2.1 */
2427 extern "C" int
2428 setgid32 (__gid32_t gid)
2429 {
2430   int ret = setegid32 (gid);
2431   if (!ret)
2432     cygheap->user.real_gid = myself->gid;
2433   return ret;
2434 }
2435
2436 extern "C" int
2437 setgid (__gid16_t gid)
2438 {
2439   int ret = setegid32 (gid16togid32 (gid));
2440   if (!ret)
2441     cygheap->user.real_gid = myself->gid;
2442   return ret;
2443 }
2444
2445 extern "C" int
2446 setregid32 (__gid32_t rgid, __gid32_t egid)
2447 {
2448   int ret = 0;
2449   bool tried = false;
2450   __gid32_t old_egid = myself->gid;
2451
2452   if (rgid != ILLEGAL_GID && cygheap->user.real_gid != rgid && egid != rgid)
2453     tried = !(ret = setegid32 (rgid));
2454   if (!ret && egid != ILLEGAL_GID)
2455     ret = setegid32 (egid);
2456   if (tried && (ret || egid == ILLEGAL_GID) && setegid32 (old_egid))
2457     system_printf ("Cannot restore original egid %u", old_egid);
2458   if (!ret && rgid != ILLEGAL_GID)
2459     cygheap->user.real_gid = rgid;
2460   debug_printf ("real: %u, effective: %u", cygheap->user.real_gid, myself->gid);
2461   return ret;
2462 }
2463
2464 extern "C" int
2465 setregid (__gid16_t rgid, __gid16_t egid)
2466 {
2467   return setregid32 (gid16togid32 (rgid), gid16togid32 (egid));
2468 }
2469
2470 /* chroot: privileged Unix system call.  */
2471 /* FIXME: Not privileged here. How should this be done? */
2472 extern "C" int
2473 chroot (const char *newroot)
2474 {
2475   path_conv path (newroot, PC_SYM_FOLLOW | PC_POSIX);
2476
2477   int ret = -1;
2478   if (path.error)
2479     set_errno (path.error);
2480   else if (!path.exists ())
2481     set_errno (ENOENT);
2482   else if (!path.isdir ())
2483     set_errno (ENOTDIR);
2484   else if (path.isspecial ())
2485     set_errno (EPERM);
2486   else
2487     {
2488       getwinenv("PATH="); /* Save the native PATH */
2489       cygheap->root.set (path.normalized_path, path);
2490       ret = 0;
2491     }
2492
2493   syscall_printf ("%d = chroot (%s)", ret ? get_errno () : 0,
2494                                       newroot ? newroot : "NULL");
2495   return ret;
2496 }
2497
2498 extern "C" int
2499 creat (const char *path, mode_t mode)
2500 {
2501   return open (path, O_WRONLY | O_CREAT | O_TRUNC, mode);
2502 }
2503
2504 extern "C" void
2505 __assertfail ()
2506 {
2507   exit (99);
2508 }
2509
2510 extern "C" int
2511 getw (FILE *fp)
2512 {
2513   int w, ret;
2514   ret = fread (&w, sizeof (int), 1, fp);
2515   return ret != 1 ? EOF : w;
2516 }
2517
2518 extern "C" int
2519 putw (int w, FILE *fp)
2520 {
2521   int ret;
2522   ret = fwrite (&w, sizeof (int), 1, fp);
2523   if (feof (fp) || ferror (fp))
2524     return -1;
2525   return 0;
2526 }
2527
2528 extern "C" int
2529 wcscmp (const wchar_t *s1, const wchar_t *s2)
2530 {
2531   while (*s1  && *s1 == *s2)
2532     {
2533       s1++;
2534       s2++;
2535     }
2536
2537   return (* (unsigned short *) s1) - (* (unsigned short *) s2);
2538 }
2539
2540 extern "C" size_t
2541 wcslen (const wchar_t *s1)
2542 {
2543   int l = 0;
2544   while (s1[l])
2545     l++;
2546   return l;
2547 }
2548
2549 /* FIXME: to do this right, maybe work out the usoft va_list machine
2550    and use wsvprintfW instead?
2551 */
2552 extern "C" int
2553 wprintf (const char *fmt, ...)
2554 {
2555   va_list ap;
2556   int ret;
2557
2558   va_start (ap, fmt);
2559   ret = vprintf (fmt, ap);
2560   va_end (ap);
2561   return ret;
2562 }
2563
2564 extern "C" int
2565 vhangup ()
2566 {
2567   set_errno (ENOSYS);
2568   return -1;
2569 }
2570
2571 extern "C" _PTR
2572 memccpy (_PTR out, const _PTR in, int c, size_t len)
2573 {
2574   const char *inc = (char *) in;
2575   char *outc = (char *) out;
2576
2577   while (len)
2578     {
2579       char x = *inc++;
2580       *outc++ = x;
2581       if (x == c)
2582         return outc;
2583       len --;
2584     }
2585   return 0;
2586 }
2587
2588 extern "C" int
2589 setpriority (int which, id_t who, int value)
2590 {
2591   DWORD prio = nice_to_winprio (value);
2592   int error = 0;
2593
2594   switch (which)
2595     {
2596     case PRIO_PROCESS:
2597       if (!who)
2598         who = myself->pid;
2599       if ((pid_t) who == myself->pid)
2600         {
2601           if (!SetPriorityClass (hMainProc, prio))
2602             {
2603               set_errno (EACCES);
2604               return -1;
2605             }
2606           myself->nice = value;
2607           debug_printf ("Set nice to %d", myself->nice);
2608           return 0;
2609         }
2610       break;
2611     case PRIO_PGRP:
2612       if (!who)
2613         who = myself->pgid;
2614       break;
2615     case PRIO_USER:
2616       if (!who)
2617         who = myself->uid;
2618       break;
2619     default:
2620       set_errno (EINVAL);
2621       return -1;
2622     }
2623   winpids pids ((DWORD) PID_MAP_RW);
2624   for (DWORD i = 0; i < pids.npids; ++i)
2625     {
2626       _pinfo *p = pids[i];
2627       if (p)
2628         {
2629           switch (which)
2630             {
2631             case PRIO_PROCESS:
2632               if ((pid_t) who != p->pid)
2633                 continue;
2634               break;
2635             case PRIO_PGRP:
2636               if ((pid_t) who != p->pgid)
2637                 continue;
2638               break;
2639             case PRIO_USER:
2640                 if ((__uid32_t) who != p->uid)
2641                 continue;
2642               break;
2643             }
2644           HANDLE proc_h = OpenProcess (PROCESS_SET_INFORMATION, FALSE,
2645                                        p->dwProcessId);
2646           if (!proc_h)
2647             error = EPERM;
2648           else
2649             {
2650               if (!SetPriorityClass (proc_h, prio))
2651                 error = EACCES;
2652               else
2653                 p->nice = value;
2654               CloseHandle (proc_h);
2655             }
2656         }
2657     }
2658   pids.reset ();
2659   if (error)
2660     {
2661       set_errno (error);
2662       return -1;
2663     }
2664   return 0;
2665 }
2666
2667 extern "C" int
2668 getpriority (int which, id_t who)
2669 {
2670   int nice = NZERO * 2; /* Illegal value */
2671
2672   switch (which)
2673     {
2674     case PRIO_PROCESS:
2675       if (!who)
2676         who = myself->pid;
2677       if ((pid_t) who == myself->pid)
2678         return myself->nice;
2679       break;
2680     case PRIO_PGRP:
2681       if (!who)
2682         who = myself->pgid;
2683       break;
2684     case PRIO_USER:
2685       if (!who)
2686         who = myself->uid;
2687       break;
2688     default:
2689       set_errno (EINVAL);
2690       return -1;
2691     }
2692   winpids pids ((DWORD) 0);
2693   for (DWORD i = 0; i < pids.npids; ++i)
2694     {
2695       _pinfo *p = pids[i];
2696       if (p)
2697         switch (which)
2698           {
2699           case PRIO_PROCESS:
2700             if ((pid_t) who == p->pid)
2701               {
2702                 nice = p->nice;
2703                 goto out;
2704               }
2705             break;
2706           case PRIO_PGRP:
2707             if ((pid_t) who == p->pgid && p->nice < nice)
2708               nice = p->nice;
2709             break;
2710           case PRIO_USER:
2711             if ((__uid32_t) who == p->uid && p->nice < nice)
2712               nice = p->nice;
2713               break;
2714           }
2715     }
2716 out:
2717   pids.reset ();
2718   if (nice == NZERO * 2)
2719     {
2720       set_errno (ESRCH);
2721       return -1;
2722     }
2723   return nice;
2724 }
2725
2726 extern "C" int
2727 nice (int incr)
2728 {
2729   return setpriority (PRIO_PROCESS, myself->pid, myself->nice + incr);
2730 }
2731
2732 /*
2733  * Find the first bit set in I.
2734  */
2735
2736 extern "C" int
2737 ffs (int i)
2738 {
2739   static const unsigned char table[] =
2740     {
2741       0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
2742       6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
2743       7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
2744       7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
2745       8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2746       8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2747       8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
2748       8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
2749     };
2750   unsigned long int a;
2751   unsigned long int x = i & -i;
2752
2753   a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ?  16 : 24);
2754
2755   return table[x >> a] + a;
2756 }
2757
2758 static void
2759 locked_append (int fd, const void * buf, size_t size)
2760 {
2761   struct __flock64 lock_buffer = {F_WRLCK, SEEK_SET, 0, 0, 0};
2762   int count = 0;
2763
2764   do
2765     if ((lock_buffer.l_start = lseek64 (fd, 0, SEEK_END)) != (_off64_t) -1
2766         && fcntl_worker (fd, F_SETLKW, &lock_buffer) != -1)
2767       {
2768         if (lseek64 (fd, 0, SEEK_END) != (_off64_t) -1)
2769           write (fd, buf, size);
2770         lock_buffer.l_type = F_UNLCK;
2771         fcntl_worker (fd, F_SETLK, &lock_buffer);
2772         break;
2773       }
2774   while (count++ < 1000
2775          && (errno == EACCES || errno == EAGAIN)
2776          && !usleep (1000));
2777 }
2778
2779 extern "C" void
2780 updwtmp (const char *wtmp_file, const struct utmp *ut)
2781 {
2782   int fd;
2783
2784   if ((fd = open (wtmp_file, O_WRONLY | O_BINARY, 0)) >= 0)
2785     {
2786       locked_append (fd, ut, sizeof *ut);
2787       close (fd);
2788     }
2789 }
2790
2791 static int utmp_fd = -1;
2792 static bool utmp_readonly = false;
2793 static char *utmp_file = (char *) _PATH_UTMP;
2794
2795 static void
2796 internal_setutent (bool force_readwrite)
2797 {
2798   if (force_readwrite && utmp_readonly)
2799     endutent ();
2800   if (utmp_fd < 0)
2801     {
2802       utmp_fd = open (utmp_file, O_RDWR | O_BINARY);
2803       /* If open fails, we assume an unprivileged process (who?).  In this
2804          case we try again for reading only unless the process calls
2805          pututline() (==force_readwrite) in which case opening just fails. */
2806       if (utmp_fd < 0 && !force_readwrite)
2807         {
2808           utmp_fd = open (utmp_file, O_RDONLY | O_BINARY);
2809           if (utmp_fd >= 0)
2810             utmp_readonly = true;
2811         }
2812     }
2813   else
2814     lseek (utmp_fd, 0, SEEK_SET);
2815 }
2816
2817 extern "C" void
2818 setutent ()
2819 {
2820   internal_setutent (false);
2821 }
2822
2823 extern "C" void
2824 endutent ()
2825 {
2826   if (utmp_fd >= 0)
2827     {
2828       close (utmp_fd);
2829       utmp_fd = -1;
2830       utmp_readonly = false;
2831     }
2832 }
2833
2834 extern "C" void
2835 utmpname (const char *file)
2836 {
2837   myfault efault;
2838   if (efault.faulted () || !*file)
2839     {
2840       debug_printf ("Invalid file");
2841       return;
2842     }
2843   endutent ();
2844   utmp_file = strdup (file);
2845   debug_printf ("New UTMP file: %s", utmp_file);
2846 }
2847 EXPORT_ALIAS (utmpname, utmpxname)
2848
2849 /* Note: do not make NO_COPY */
2850 static struct utmp utmp_data_buf[16];
2851 static unsigned utix = 0;
2852 #define nutdbuf (sizeof (utmp_data_buf) / sizeof (utmp_data_buf[0]))
2853 #define utmp_data ({ \
2854   if (utix > nutdbuf) \
2855     utix = 0; \
2856   utmp_data_buf + utix++; \
2857 })
2858
2859 static struct utmpx *
2860 copy_ut_to_utx (struct utmp *ut, struct utmpx *utx)
2861 {
2862   if (!ut)
2863     return NULL;
2864   memcpy (utx, ut, sizeof *ut);
2865   utx->ut_tv.tv_sec = ut->ut_time;
2866   utx->ut_tv.tv_usec = 0;
2867   return utx;
2868 }
2869
2870 extern "C" struct utmp *
2871 getutent ()
2872 {
2873   if (utmp_fd < 0)
2874     {
2875       internal_setutent (false);
2876       if (utmp_fd < 0)
2877         return NULL;
2878     }
2879
2880   utmp *ut = utmp_data;
2881   if (read (utmp_fd, ut, sizeof *ut) != sizeof *ut)
2882     return NULL;
2883   return ut;
2884 }
2885
2886 extern "C" struct utmp *
2887 getutid (struct utmp *id)
2888 {
2889   myfault efault;
2890   if (efault.faulted (EFAULT))
2891     return NULL;
2892   if (utmp_fd < 0)
2893     {
2894       internal_setutent (false);
2895       if (utmp_fd < 0)
2896         return NULL;
2897     }
2898
2899   utmp *ut = utmp_data;
2900   while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut)
2901     {
2902       switch (id->ut_type)
2903         {
2904         case RUN_LVL:
2905         case BOOT_TIME:
2906         case OLD_TIME:
2907         case NEW_TIME:
2908           if (id->ut_type == ut->ut_type)
2909             return ut;
2910           break;
2911         case INIT_PROCESS:
2912         case LOGIN_PROCESS:
2913         case USER_PROCESS:
2914         case DEAD_PROCESS:
2915            if (strncmp (id->ut_id, ut->ut_id, UT_IDLEN) == 0)
2916             return ut;
2917           break;
2918         default:
2919           return NULL;
2920         }
2921     }
2922   return NULL;
2923 }
2924
2925 extern "C" struct utmp *
2926 getutline (struct utmp *line)
2927 {
2928   myfault efault;
2929   if (efault.faulted (EFAULT))
2930     return NULL;
2931   if (utmp_fd < 0)
2932     {
2933       internal_setutent (false);
2934       if (utmp_fd < 0)
2935         return NULL;
2936     }
2937
2938   utmp *ut = utmp_data;
2939   while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut)
2940     if ((ut->ut_type == LOGIN_PROCESS ||
2941          ut->ut_type == USER_PROCESS) &&
2942         !strncmp (ut->ut_line, line->ut_line, sizeof (ut->ut_line)))
2943       return ut;
2944
2945   return NULL;
2946 }
2947
2948 extern "C" struct utmp *
2949 pututline (struct utmp *ut)
2950 {
2951   myfault efault;
2952   if (efault.faulted (EFAULT))
2953     return NULL;
2954   internal_setutent (true);
2955   if (utmp_fd < 0)
2956     {
2957       debug_printf ("error: utmp_fd %d", utmp_fd);
2958       return NULL;
2959     }
2960   debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n",
2961                 ut->ut_type, ut->ut_pid, ut->ut_line, ut->ut_id);
2962   debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n",
2963                 ut->ut_user, ut->ut_host);
2964
2965   struct utmp *u;
2966   if ((u = getutid (ut)))
2967     {
2968       lseek (utmp_fd, -sizeof *ut, SEEK_CUR);
2969       write (utmp_fd, ut, sizeof *ut);
2970     }
2971   else
2972     locked_append (utmp_fd, ut, sizeof *ut);
2973   return ut;
2974 }
2975
2976 extern "C" void
2977 setutxent ()
2978 {
2979   internal_setutent (false);
2980 }
2981
2982 extern "C" void
2983 endutxent ()
2984 {
2985   endutent ();
2986 }
2987
2988 extern "C" struct utmpx *
2989 getutxent ()
2990 {
2991   static struct utmpx utx;
2992   return copy_ut_to_utx (getutent (), &utx);
2993 }
2994
2995 extern "C" struct utmpx *
2996 getutxid (const struct utmpx *id)
2997 {
2998   static struct utmpx utx;
2999
3000   myfault efault;
3001   if (efault.faulted (EFAULT))
3002     return NULL;
3003   ((struct utmpx *)id)->ut_time = id->ut_tv.tv_sec;
3004   return copy_ut_to_utx (getutid ((struct utmp *) id), &utx);
3005 }
3006
3007 extern "C" struct utmpx *
3008 getutxline (const struct utmpx *line)
3009 {
3010   static struct utmpx utx;
3011
3012   myfault efault;
3013   if (efault.faulted (EFAULT))
3014     return NULL;
3015   ((struct utmpx *)line)->ut_time = line->ut_tv.tv_sec;
3016   return copy_ut_to_utx (getutline ((struct utmp *) line), &utx);
3017 }
3018
3019 extern "C" struct utmpx *
3020 pututxline (const struct utmpx *utmpx)
3021 {
3022   static struct utmpx utx;
3023
3024   myfault efault;
3025   if (efault.faulted (EFAULT))
3026     return NULL;
3027   ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec;
3028   return copy_ut_to_utx (pututline ((struct utmp *) utmpx), &utx);
3029 }
3030
3031 extern "C" void
3032 updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
3033 {
3034   ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec;
3035   updwtmp (wtmpx_file, (const struct utmp *) utmpx);
3036 }
3037
3038 extern "C"
3039 long gethostid (void)
3040 {
3041   unsigned data[13] = {0x92895012,
3042                        0x10293412,
3043                        0x29602018,
3044                        0x81928167,
3045                        0x34601329,
3046                        0x75630198,
3047                        0x89860395,
3048                        0x62897564,
3049                        0x00194362,
3050                        0x20548593,
3051                        0x96839102,
3052                        0x12219854,
3053                        0x00290012};
3054
3055   bool has_cpuid = false;
3056
3057   DWORD opmask = SetThreadAffinityMask (GetCurrentThread (), 1);
3058   if (!opmask)
3059     debug_printf ("SetThreadAffinityMask to 1 failed, %E");
3060
3061   if (!can_set_flag (0x00040000))
3062     debug_printf ("386 processor - no cpuid");
3063   else
3064     {
3065       debug_printf ("486 processor");
3066       if (can_set_flag (0x00200000))
3067         {
3068           debug_printf ("processor supports CPUID instruction");
3069           has_cpuid = true;
3070         }
3071       else
3072         debug_printf ("processor does not support CPUID instruction");
3073     }
3074   if (has_cpuid)
3075     {
3076       unsigned maxf, unused[3];
3077       cpuid (&maxf, &unused[0], &unused[1], &unused[2], 0);
3078       maxf &= 0xffff;
3079       if (maxf >= 1)
3080         {
3081           unsigned features;
3082           cpuid (&data[0], &unused[0], &unused[1], &features, 1);
3083           if (features & (1 << 18))
3084             {
3085               debug_printf ("processor has psn");
3086               if (maxf >= 3)
3087                 {
3088                   cpuid (&unused[0], &unused[1], &data[1], &data[2], 3);
3089                   debug_printf ("Processor PSN: %04x-%04x-%04x-%04x-%04x-%04x",
3090                                 data[0] >> 16, data[0] & 0xffff, data[2] >> 16, data[2] & 0xffff, data[1] >> 16, data[1] & 0xffff);
3091                 }
3092             }
3093           else
3094             debug_printf ("processor does not have psn");
3095         }
3096     }
3097
3098   UUID Uuid;
3099   RPC_STATUS status = UuidCreateSequential (&Uuid);
3100   if (GetLastError () == ERROR_PROC_NOT_FOUND)
3101     status = UuidCreate (&Uuid);
3102   if (status == RPC_S_OK)
3103     {
3104       data[4] = *(unsigned *)&Uuid.Data4[2];
3105       data[5] = *(unsigned short *)&Uuid.Data4[6];
3106       // Unfortunately Windows will sometimes pick a virtual Ethernet card
3107       // e.g. VMWare Virtual Ethernet Adaptor
3108       debug_printf ("MAC address of first Ethernet card: %02x:%02x:%02x:%02x:%02x:%02x",
3109                     Uuid.Data4[2], Uuid.Data4[3], Uuid.Data4[4],
3110                     Uuid.Data4[5], Uuid.Data4[6], Uuid.Data4[7]);
3111     }
3112   else
3113     {
3114       debug_printf ("no Ethernet card installed");
3115     }
3116
3117   reg_key key (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE", "Microsoft", "Windows", "CurrentVersion", NULL);
3118   key.get_string ("ProductId", (char *)&data[6], 24, "00000-000-0000000-00000");
3119   debug_printf ("Windows Product ID: %s", (char *)&data[6]);
3120
3121   /* Contrary to MSDN, NT4 requires the second argument
3122      or a STATUS_ACCESS_VIOLATION is generated */
3123   ULARGE_INTEGER availb;
3124   GetDiskFreeSpaceEx ("C:\\", &availb, (PULARGE_INTEGER) &data[11], NULL);
3125   if (GetLastError () == ERROR_PROC_NOT_FOUND)
3126     GetDiskFreeSpace ("C:\\", NULL, NULL, NULL, (DWORD *)&data[11]);
3127
3128   debug_printf ("hostid entropy: %08x %08x %08x %08x "
3129                                 "%08x %08x %08x %08x "
3130                                 "%08x %08x %08x %08x "
3131                                 "%08x",
3132                                 data[0], data[1],
3133                                 data[2], data[3],
3134                                 data[4], data[5],
3135                                 data[6], data[7],
3136                                 data[8], data[9],
3137                                 data[10], data[11],
3138                                 data[12]);
3139
3140   long hostid = 0x40291372;
3141   // a random hashing algorithm
3142   // dependancy on md5 is probably too costly
3143   for (int i=0;i<13;i++)
3144     hostid ^= ((data[i] << (i << 2)) | (data[i] >> (32 - (i << 2))));
3145
3146   if (opmask && !SetThreadAffinityMask (GetCurrentThread (), opmask))
3147     debug_printf ("SetThreadAffinityMask to %p failed, %E", opmask);
3148
3149   debug_printf ("hostid: %08x", hostid);
3150
3151   return hostid;
3152 }
3153
3154 #define ETC_SHELLS "/etc/shells"
3155 static int shell_index;
3156 static struct __sFILE64 *shell_fp;
3157
3158 extern "C" char *
3159 getusershell ()
3160 {
3161   /* List of default shells if no /etc/shells exists, defined as on Linux.
3162      FIXME: SunOS has a far longer list, containing all shells which
3163      might be shipped with the OS.  Should we do the same for the Cygwin
3164      distro, adding bash, tcsh, ksh, pdksh and zsh?  */
3165   static NO_COPY const char *def_shells[] = {
3166     "/bin/sh",
3167     "/bin/csh",
3168     "/usr/bin/sh",
3169     "/usr/bin/csh",
3170     NULL
3171   };
3172   static char buf[CYG_MAX_PATH];
3173   int ch, buf_idx;
3174
3175   if (!shell_fp && !(shell_fp = fopen64 (ETC_SHELLS, "rt")))
3176     {
3177       if (def_shells[shell_index])
3178         return strcpy (buf, def_shells[shell_index++]);
3179       return NULL;
3180     }
3181   /* Skip white space characters. */
3182   while ((ch = getc (shell_fp)) != EOF && isspace (ch))
3183     ;
3184   /* Get each non-whitespace character as part of the shell path as long as
3185      it fits in buf. */
3186   for (buf_idx = 0;
3187        ch != EOF && !isspace (ch) && buf_idx < CYG_MAX_PATH;
3188        buf_idx++, ch = getc (shell_fp))
3189     buf[buf_idx] = ch;
3190   /* Skip any trailing non-whitespace character not fitting in buf.  If the
3191      path is longer than CYG_MAX_PATH, it's invalid anyway. */
3192   while (ch != EOF && !isspace (ch))
3193     ch = getc (shell_fp);
3194   if (buf_idx)
3195     {
3196       buf[buf_idx] = '\0';
3197       return buf;
3198     }
3199   return NULL;
3200 }
3201
3202 extern "C" void
3203 setusershell ()
3204 {
3205   if (shell_fp)
3206     fseek (shell_fp, 0L, SEEK_SET);
3207   shell_index = 0;
3208 }
3209
3210 extern "C" void
3211 endusershell ()
3212 {
3213   if (shell_fp)
3214     {
3215       fclose (shell_fp);
3216       shell_fp = NULL;
3217     }
3218   shell_index = 0;
3219 }
3220
3221 extern "C" void
3222 flockfile (FILE *file)
3223 {
3224   _flockfile (file);
3225 }
3226
3227 extern "C" int
3228 ftrylockfile (FILE *file)
3229 {
3230   return _ftrylockfile (file);
3231 }
3232
3233 extern "C" void
3234 funlockfile (FILE *file)
3235 {
3236   _funlockfile (file);
3237 }
3238
3239 extern "C" FILE *
3240 popen (const char *command, const char *in_type)
3241 {
3242   const char *type = in_type;
3243   char rw = *type++;
3244
3245   if (*type == 'b' || *type == 't')
3246     type++;
3247   if ((rw != 'r' && rw != 'w') || (*type != '\0'))
3248     {
3249       set_errno (EINVAL);
3250       return NULL;
3251     }
3252
3253   int fd, other_fd, __stdin, __stdout, stdwhat;
3254
3255   int fds[2];
3256   if (pipe (fds) < 0)
3257     return NULL;
3258
3259   switch (rw)
3260     {
3261     case 'r':
3262       __stdin = -1;
3263       stdwhat = 1;
3264       other_fd = __stdout = fds[1];
3265       fd = fds[0];
3266       break;
3267     case 'w':
3268       __stdout = -1;
3269       stdwhat = 0;
3270       other_fd = __stdin = fds[0];
3271       fd = fds[1];
3272       break;
3273     default:
3274       return NULL;      /* avoid a compiler warning */
3275     }
3276
3277   FILE *fp = fdopen (fd, in_type);
3278   fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
3279
3280   if (!fp)
3281     goto err;
3282
3283   pid_t pid;
3284   const char *argv[4];
3285
3286   argv[0] = "/bin/sh";
3287   argv[1] = "-c";
3288   argv[2] = command;
3289   argv[3] = NULL;
3290
3291   {
3292     lock_process now;
3293     int state = fcntl (stdwhat, F_GETFD, 0);
3294     fcntl (stdwhat, F_SETFD, state | FD_CLOEXEC);
3295     pid = spawn_guts ("/bin/sh", argv, cur_environ (), _P_NOWAIT,
3296                       __stdin, __stdout);
3297     fcntl (stdwhat, F_SETFD, state);
3298   }
3299
3300   if (pid < 0)
3301     goto err;
3302   close (other_fd);
3303
3304   fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[fd];
3305   fh->set_popen_pid (pid);
3306
3307   return fp;
3308
3309 err:
3310   int save_errno = get_errno ();
3311   close (fds[0]);
3312   close (fds[1]);
3313   set_errno (save_errno);
3314   return NULL;
3315 }
3316
3317 int
3318 pclose (FILE *fp)
3319 {
3320   fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[fileno(fp)];
3321
3322   if (fh->get_device () != FH_PIPEW && fh->get_device () != FH_PIPER)
3323     {
3324       set_errno (EBADF);
3325       return -1;
3326     }
3327
3328   int pid = fh->get_popen_pid ();
3329   if (!pid)
3330     {
3331       set_errno (ECHILD);
3332       return -1;
3333     }
3334
3335   if (fclose (fp))
3336     return -1;
3337
3338   int status;
3339   while (1)
3340     if (waitpid (pid, &status, 0) == pid)
3341       break;
3342     else if (get_errno () == EINTR)
3343       continue;
3344     else
3345       return -1;
3346
3347   return status;
3348 }