OSDN Git Service

* exceptions.cc (set_signal_mask): Remove useless debugging output.
[pf3gnuchains/pf3gnuchains4x.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, 2008, 2009, 2010, 2011 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 <winnls.h>
28 #include "miscfuncs.h"
29 #include <sys/stat.h>
30 #include <sys/vfs.h> /* needed for statfs */
31 #include <sys/statvfs.h> /* needed for statvfs */
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 <ctype.h>
39 #include <wctype.h>
40 #include <unistd.h>
41 #include <sys/wait.h>
42 #include "ntdll.h"
43
44 #undef fstat
45 #undef lstat
46 #undef stat
47 #undef pread
48 #undef pwrite
49
50 #include <cygwin/version.h>
51 #include "cygerrno.h"
52 #include "perprocess.h"
53 #include "security.h"
54 #include "path.h"
55 #include "fhandler.h"
56 #include "dtable.h"
57 #include "sigproc.h"
58 #include "pinfo.h"
59 #include "shared_info.h"
60 #include "cygheap.h"
61 #include "pwdgrp.h"
62 #include "cpuid.h"
63 #include "registry.h"
64 #include "environ.h"
65 #include "tls_pbuf.h"
66 #include "sync.h"
67 #include "child_info.h"
68
69 #undef _close
70 #undef _lseek
71 #undef _open
72 #undef _read
73 #undef _write
74 #undef _open64
75 #undef _lseek64
76 #undef _fstat64
77
78 static int __stdcall mknod_worker (const char *, mode_t, mode_t, _major_t,
79                                    _minor_t);
80
81 /* Close all files and process any queued deletions.
82    Lots of unix style applications will open a tmp file, unlink it,
83    but never call close.  This function is called by _exit to
84    ensure we don't leave any such files lying around.  */
85
86 void __stdcall
87 close_all_files (bool norelease)
88 {
89   cygheap->fdtab.lock ();
90
91   semaphore::terminate ();
92
93   fhandler_base *fh;
94   HANDLE h = NULL;
95
96   for (int i = 0; i < (int) cygheap->fdtab.size; i++)
97     if ((fh = cygheap->fdtab[i]) != NULL)
98       {
99 #ifdef DEBUGGING
100         debug_printf ("closing fd %d", i);
101 #endif
102         if (i == 2)
103           DuplicateHandle (GetCurrentProcess (), fh->get_output_handle (),
104                            GetCurrentProcess (), &h,
105                            0, false, DUPLICATE_SAME_ACCESS);
106         fh->close_with_arch ();
107         if (!norelease)
108           cygheap->fdtab.release (i);
109       }
110
111   if (!have_execed && cygheap->ctty)
112     cygheap->close_ctty ();
113
114   fhandler_base_overlapped::flush_all_async_io ();
115   if (h)
116     SetStdHandle (STD_ERROR_HANDLE, h);
117   cygheap->fdtab.unlock ();
118 }
119
120 extern "C" int
121 dup (int fd)
122 {
123   int res = cygheap->fdtab.dup3 (fd, cygheap_fdnew (), 0);
124   syscall_printf ("%R = dup(%d)", res, fd);
125   return res;
126 }
127
128 extern "C" int
129 dup2 (int oldfd, int newfd)
130 {
131   int res;
132   if (newfd >= OPEN_MAX_MAX)
133     {
134       set_errno (EBADF);
135       res = -1;
136     }
137   else if (newfd == oldfd)
138     {
139       cygheap_fdget cfd (oldfd);
140       res = (cfd >= 0) ? oldfd : -1;
141     }
142   else
143     res = cygheap->fdtab.dup3 (oldfd, newfd, 0); 
144
145   syscall_printf ("%R = dup2(%d, %d)", res, oldfd, newfd);
146   return res;
147 }
148
149 extern "C" int
150 dup3 (int oldfd, int newfd, int flags)
151 {
152   int res;
153   if (newfd >= OPEN_MAX_MAX)
154     {
155       set_errno (EBADF);
156       res = -1;
157     }
158   else if (newfd == oldfd)
159     {
160       cygheap_fdget cfd (oldfd, false, false);
161       set_errno (cfd < 0 ? EBADF : EINVAL);
162       res = -1;
163     }
164   else
165     res = cygheap->fdtab.dup3 (oldfd, newfd, flags);
166   syscall_printf ("%R = dup2(%d, %d, %p)", res, oldfd, newfd, flags);
167   return res;
168 }
169
170 static inline void
171 start_transaction (HANDLE &old_trans, HANDLE &trans)
172 {
173   NTSTATUS status = NtCreateTransaction (&trans,
174                                 SYNCHRONIZE | TRANSACTION_ALL_ACCESS,
175                                 NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
176   if (NT_SUCCESS (status))
177     {
178       old_trans = RtlGetCurrentTransaction ();
179       RtlSetCurrentTransaction (trans);
180     }
181   else
182     {
183       debug_printf ("NtCreateTransaction failed, %p", status);
184       old_trans = trans = NULL;
185     }
186 }
187
188 static inline NTSTATUS
189 stop_transaction (NTSTATUS status, HANDLE old_trans, HANDLE trans)
190 {
191   RtlSetCurrentTransaction (old_trans);
192   if (NT_SUCCESS (status))
193     status = NtCommitTransaction (trans, TRUE);
194   else
195     status = NtRollbackTransaction (trans, TRUE);
196   NtClose (trans);
197   return status;
198 }
199
200 static char desktop_ini[] =
201   "[.ShellClassInfo]\r\nCLSID={645FF040-5081-101B-9F08-00AA002F954E}\r\n";
202 static BYTE info2[] =
203 {
204   0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205   0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
206 };
207
208 enum bin_status
209 {
210   dont_move,
211   move_to_bin,
212   has_been_moved
213 };
214
215 static bin_status
216 try_to_bin (path_conv &pc, HANDLE &fh, ACCESS_MASK access)
217 {
218   bin_status bin_stat = move_to_bin;
219   NTSTATUS status;
220   OBJECT_ATTRIBUTES attr;
221   IO_STATUS_BLOCK io;
222   HANDLE rootdir = NULL, recyclerdir = NULL, tmp_fh = NULL;
223   USHORT recycler_base_len = 0, recycler_user_len = 0;
224   UNICODE_STRING root, recycler, fname;
225   WCHAR recyclerbuf[NAME_MAX + 1]; /* Enough for recycler + SID + filename */
226   PFILE_NAME_INFORMATION pfni;
227   PFILE_INTERNAL_INFORMATION pfii;
228   PFILE_RENAME_INFORMATION pfri;
229   FILE_DISPOSITION_INFORMATION disp = { TRUE };
230
231   tmp_pathbuf tp;
232   PBYTE infobuf = (PBYTE) tp.w_get ();
233
234   pfni = (PFILE_NAME_INFORMATION) infobuf;
235   status = NtQueryInformationFile (fh, &io, pfni, 65536, FileNameInformation);
236   if (!NT_SUCCESS (status))
237     {
238       debug_printf ("NtQueryInformationFile (%S, FileNameInformation) "
239                     "failed, status = %p", pc.get_nt_native_path (), status);
240       goto out;
241     }
242   /* The filename could change, the parent dir not.  So we split both paths
243      and take the prefix.  However, there are two special cases:
244      - The handle refers to the root dir of the volume.
245      - The handle refers to the recycler or a subdir.
246      Both cases are handled by just returning and not even trying to move
247      them into the recycler. */
248   if (pfni->FileNameLength == 2) /* root dir. */
249     goto out;
250   /* Initialize recycler path. */
251   RtlInitEmptyUnicodeString (&recycler, recyclerbuf, sizeof recyclerbuf);
252   if (!pc.isremote ())
253     {
254       if (wincap.has_recycle_dot_bin ())        /* NTFS and FAT since Vista */
255         RtlAppendUnicodeToString (&recycler, L"\\$Recycle.Bin\\");
256       else if (pc.fs_is_ntfs ())        /* NTFS up to 2K3 */
257         RtlAppendUnicodeToString (&recycler, L"\\RECYCLER\\");
258       else if (pc.fs_is_fat ()) /* FAT up to 2K3 */
259         RtlAppendUnicodeToString (&recycler, L"\\Recycled\\");
260       else
261         goto out;
262       /* Is the file a subdir of the recycler? */
263       RtlInitCountedUnicodeString(&fname, pfni->FileName, pfni->FileNameLength);
264       if (RtlEqualUnicodePathPrefix (&fname, &recycler, TRUE))
265         goto out;
266       /* Is fname the recycler?  Temporarily hide trailing backslash. */
267       recycler.Length -= sizeof (WCHAR);
268       if (RtlEqualUnicodeString (&fname, &recycler, TRUE))
269         goto out;
270
271       /* Create root dir path from file name information. */
272       RtlSplitUnicodePath (&fname, &fname, NULL);
273       RtlSplitUnicodePath (pc.get_nt_native_path (), &root, NULL);
274       root.Length -= fname.Length - sizeof (WCHAR);
275
276       /* Open root directory.  All recycler bin ops are caseinsensitive. */
277       InitializeObjectAttributes (&attr, &root, OBJ_CASE_INSENSITIVE,
278                                   NULL, NULL);
279       status = NtOpenFile (&rootdir, FILE_TRAVERSE, &attr, &io,
280                            FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
281       if (!NT_SUCCESS (status))
282         {
283           debug_printf ("NtOpenFile (%S) failed, status = %p", &root, status);
284           goto out;
285         }
286
287       /* Strip leading backslash */
288       ++recycler.Buffer;
289       recycler.Length -= sizeof (WCHAR);
290       /* Store length of recycler base dir, if it's necessary to create it. */
291       recycler_base_len = recycler.Length;
292       /* On NTFS the recycler dir contains user specific subdirs, which are the
293          actual recycle bins per user.  The name if this dir is the string
294          representation of the user SID. */
295       if (pc.fs_is_ntfs ())
296         {
297           UNICODE_STRING sid;
298           WCHAR sidbuf[128];
299           /* Unhide trailing backslash. */
300           recycler.Length += sizeof (WCHAR);
301           RtlInitEmptyUnicodeString (&sid, sidbuf, sizeof sidbuf);
302           /* In contrast to what MSDN claims, this function is already available
303              since NT4. */
304           RtlConvertSidToUnicodeString (&sid, cygheap->user.sid (), FALSE);
305           RtlAppendUnicodeStringToString (&recycler, &sid);
306           recycler_user_len = recycler.Length;
307         }
308       RtlAppendUnicodeToString (&recycler, L"\\");
309     }
310   /* Create hopefully unique filename.
311      Since we have to stick to the current directory on remote shares, make
312      the new filename at least very unlikely to match by accident.  It starts
313      with ".cyg", with "cyg" transposed into the Unicode low surrogate area
314      starting at U+dc00.  Use plain ASCII chars on filesystems not supporting
315      Unicode.  The rest of the filename is the inode number in hex encoding
316      and a hash of the full NT path in hex.  The combination allows to remove
317      multiple hardlinks to the same file. */
318   RtlAppendUnicodeToString (&recycler,
319                             pc.fs_flags () & FILE_UNICODE_ON_DISK
320                             ? L".\xdc63\xdc79\xdc67" : L".cyg");
321   pfii = (PFILE_INTERNAL_INFORMATION) infobuf;
322   status = NtQueryInformationFile (fh, &io, pfii, 65536,
323                                    FileInternalInformation);
324   if (!NT_SUCCESS (status))
325     {
326       debug_printf ("NtQueryInformationFile (%S, FileInternalInformation) "
327                     "failed, status = %p", pc.get_nt_native_path (), status);
328       goto out;
329     }
330   RtlInt64ToHexUnicodeString (pfii->FileId.QuadPart, &recycler, TRUE);
331   RtlInt64ToHexUnicodeString (hash_path_name (0, pc.get_nt_native_path ()),
332                               &recycler, TRUE);
333   /* Shoot. */
334   pfri = (PFILE_RENAME_INFORMATION) infobuf;
335   pfri->ReplaceIfExists = TRUE;
336   pfri->RootDirectory = pc.isremote () ? NULL : rootdir;
337   pfri->FileNameLength = recycler.Length;
338   memcpy (pfri->FileName, recycler.Buffer, recycler.Length);
339   status = NtSetInformationFile (fh, &io, pfri, 65536, FileRenameInformation);
340   if (status == STATUS_OBJECT_PATH_NOT_FOUND && !pc.isremote ())
341     {
342       /* Ok, so the recycler and/or the recycler/SID directory don't exist.
343          First reopen root dir with permission to create subdirs. */
344       NtClose (rootdir);
345       status = NtOpenFile (&rootdir, FILE_ADD_SUBDIRECTORY, &attr, &io,
346                            FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT);
347       if (!NT_SUCCESS (status))
348         {
349           debug_printf ("NtOpenFile (%S) failed, status = %p",
350                         &recycler, status);
351           goto out;
352         }
353       /* Then check if recycler exists by opening and potentially creating it.
354          Yes, we can really do that.  Typically the recycle bin is created
355          by the first user actually using the bin.  The permissions are the
356          default permissions propagated from the root directory. */
357       InitializeObjectAttributes (&attr, &recycler, OBJ_CASE_INSENSITIVE,
358                                   rootdir, NULL);
359       recycler.Length = recycler_base_len;
360       status = NtCreateFile (&recyclerdir,
361                              READ_CONTROL
362                              | (pc.fs_is_ntfs () ? 0 : FILE_ADD_FILE),
363                              &attr, &io, NULL,
364                              FILE_ATTRIBUTE_DIRECTORY
365                              | FILE_ATTRIBUTE_SYSTEM
366                              | FILE_ATTRIBUTE_HIDDEN,
367                              FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF,
368                              FILE_DIRECTORY_FILE, NULL, 0);
369       if (!NT_SUCCESS (status))
370         {
371           debug_printf ("NtCreateFile (%S) failed, status = %p",
372                         &recycler, status);
373           goto out;
374         }
375       /* Next, if necessary, check if the recycler/SID dir exists and
376          create it if not. */
377       if (pc.fs_is_ntfs ())
378         {
379           NtClose (recyclerdir);
380           recycler.Length = recycler_user_len;
381           status = NtCreateFile (&recyclerdir, READ_CONTROL | FILE_ADD_FILE,
382                                  &attr, &io, NULL, FILE_ATTRIBUTE_DIRECTORY
383                                                    | FILE_ATTRIBUTE_SYSTEM
384                                                    | FILE_ATTRIBUTE_HIDDEN,
385                                  FILE_SHARE_VALID_FLAGS, FILE_OPEN_IF,
386                                  FILE_DIRECTORY_FILE, NULL, 0);
387           if (!NT_SUCCESS (status))
388             {
389               debug_printf ("NtCreateFile (%S) failed, status = %p",
390                             &recycler, status);
391               goto out;
392             }
393         }
394       /* The desktop.ini and INFO2 (pre-Vista) files are expected by
395          Windows Explorer.  Otherwise, the created bin is treated as
396          corrupted */
397       if (io.Information == FILE_CREATED)
398         {
399           RtlInitUnicodeString (&fname, L"desktop.ini");
400           InitializeObjectAttributes (&attr, &fname, OBJ_CASE_INSENSITIVE,
401                                       recyclerdir, NULL);
402           status = NtCreateFile (&tmp_fh, FILE_GENERIC_WRITE, &attr, &io, NULL,
403                                  FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
404                                  FILE_SHARE_VALID_FLAGS, FILE_CREATE,
405                                  FILE_SYNCHRONOUS_IO_NONALERT
406                                  | FILE_NON_DIRECTORY_FILE, NULL, 0);
407           if (!NT_SUCCESS (status))
408             debug_printf ("NtCreateFile (%S) failed, status = %p",
409                           &recycler, status);
410           else
411             {
412               status = NtWriteFile (tmp_fh, NULL, NULL, NULL, &io, desktop_ini,
413                                     sizeof desktop_ini - 1, NULL, NULL);
414               if (!NT_SUCCESS (status))
415                 debug_printf ("NtWriteFile (%S) failed, status = %p",
416                               &fname, status);
417               NtClose (tmp_fh);
418             }
419           if (!wincap.has_recycle_dot_bin ()) /* No INFO2 file since Vista */
420             {
421               RtlInitUnicodeString (&fname, L"INFO2");
422               status = NtCreateFile (&tmp_fh, FILE_GENERIC_WRITE, &attr, &io,
423                                      NULL, FILE_ATTRIBUTE_ARCHIVE
424                                            | FILE_ATTRIBUTE_HIDDEN,
425                                      FILE_SHARE_VALID_FLAGS, FILE_CREATE,
426                                      FILE_SYNCHRONOUS_IO_NONALERT
427                                      | FILE_NON_DIRECTORY_FILE, NULL, 0);
428                 if (!NT_SUCCESS (status))
429                   debug_printf ("NtCreateFile (%S) failed, status = %p",
430                                 &recycler, status);
431                 else
432                 {
433                   status = NtWriteFile (tmp_fh, NULL, NULL, NULL, &io, info2,
434                                         sizeof info2, NULL, NULL);
435                   if (!NT_SUCCESS (status))
436                     debug_printf ("NtWriteFile (%S) failed, status = %p",
437                                   &fname, status);
438                   NtClose (tmp_fh);
439                 }
440             }
441         }
442       NtClose (recyclerdir);
443       /* Shoot again. */
444       status = NtSetInformationFile (fh, &io, pfri, 65536,
445                                      FileRenameInformation);
446     }
447   if (!NT_SUCCESS (status))
448     {
449       debug_printf ("Move %S to %S failed, status = %p",
450                     pc.get_nt_native_path (), &recycler, status);
451       goto out;
452     }
453   /* Moving to the bin worked. */
454   bin_stat = has_been_moved;
455   /* Now we try to set the delete disposition.  If that worked, we're done.
456      We try this here first, as long as we still have the open handle.
457      Otherwise the below code closes the handle to allow replacing the file. */
458   status = NtSetInformationFile (fh, &io, &disp, sizeof disp,
459                                  FileDispositionInformation);
460   /* In case of success, restore R/O attribute to accommodate hardlinks.
461      That leaves potentially hardlinks around with the R/O bit suddenly
462      off if setting the delete disposition failed, but please, keep in
463      mind this is really a border case only. */
464   if ((access & FILE_WRITE_ATTRIBUTES) && NT_SUCCESS (status) && !pc.isdir ())
465     NtSetAttributesFile (fh, pc.file_attributes ());
466   NtClose (fh);
467   fh = NULL; /* So unlink_nt doesn't close the handle twice. */
468   /* On success or when trying to unlink a directory we just return here.
469      The below code only works for files. */
470   if (NT_SUCCESS (status) || pc.isdir ())
471     goto out;
472   /* The final trick.  We create a temporary file with delete-on-close
473      semantic and rename that file to the file just moved to the bin.
474      This typically overwrites the original file and we get rid of it,
475      even if neither setting the delete dispostion, nor setting
476      delete-on-close on the original file succeeds.  There are still
477      cases in which this fails, for instance, when trying to delete a
478      hardlink to a DLL used by the unlinking application itself. */
479   RtlAppendUnicodeToString (&recycler, L"X");
480   InitializeObjectAttributes (&attr, &recycler, 0, rootdir, NULL);
481   status = NtCreateFile (&tmp_fh, DELETE, &attr, &io, NULL,
482                          FILE_ATTRIBUTE_NORMAL, 0, FILE_SUPERSEDE,
483                          FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE,
484                          NULL, 0);
485   if (!NT_SUCCESS (status))
486     {
487       debug_printf ("Creating file for overwriting failed, status = %p",
488                     status);
489       goto out;
490     }
491   status = NtSetInformationFile (tmp_fh, &io, pfri, 65536,
492                                  FileRenameInformation);
493   NtClose (tmp_fh);
494   if (!NT_SUCCESS (status))
495     debug_printf ("Overwriting with another file failed, status = %p", status);
496
497 out:
498   if (rootdir)
499     NtClose (rootdir);
500   debug_printf ("%S, return status %d", pc.get_nt_native_path (), bin_stat);
501   return bin_stat;
502 }
503
504 static NTSTATUS
505 check_dir_not_empty (HANDLE dir, path_conv &pc)
506 {
507   IO_STATUS_BLOCK io;
508   const ULONG bufsiz = 3 * sizeof (FILE_NAMES_INFORMATION)
509                        + 3 * NAME_MAX * sizeof (WCHAR);
510   PFILE_NAMES_INFORMATION pfni = (PFILE_NAMES_INFORMATION)
511                                  alloca (bufsiz);
512   NTSTATUS status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni,
513                                           bufsiz, FileNamesInformation,
514                                           FALSE, NULL, TRUE);
515   if (!NT_SUCCESS (status))
516     {
517       debug_printf ("Checking if directory %S is empty failed, status = %p",
518                     pc.get_nt_native_path (), status);
519       return status;
520     }
521   int cnt = 1;
522   do
523     {
524       while (pfni->NextEntryOffset)
525         {
526           if (++cnt > 2)
527             {
528               UNICODE_STRING fname;
529               OBJECT_ATTRIBUTES attr;
530               FILE_BASIC_INFORMATION fbi;
531
532               pfni = (PFILE_NAMES_INFORMATION)
533                      ((caddr_t) pfni + pfni->NextEntryOffset);
534               RtlInitCountedUnicodeString(&fname, pfni->FileName,
535                                           pfni->FileNameLength);
536               InitializeObjectAttributes (&attr, &fname, 0, dir, NULL);
537               status = NtQueryAttributesFile (&attr, &fbi);
538               /* Intensive testing shows that sometimes directories, for which
539                  the delete disposition has already been set, and the deleting
540                  handle is already closed, can linger in the parent dir for a
541                  couple of ms for no apparent reason (Windows Defender or other
542                  real-time scanners are suspect).
543
544                  A fast rm -r is capable to exploit this problem.  Setting the
545                  delete disposition of the parent dir then fails with
546                  STATUS_DIRECTORY_NOT_EMPTY.  Examining the content of the
547                  affected dir can then show either that the dir is empty, or it
548                  can contain a lingering subdir.  Calling NtQueryAttributesFile
549                  on that subdir returns with STATUS_DELETE_PENDING, or it
550                  disappeared before that call.
551
552                  That's what we do here.  If NtQueryAttributesFile succeeded,
553                  or if the error code does not indicate an already deleted
554                  entry, STATUS_DIRECTORY_NOT_EMPTY is returned.
555
556                  Otherwise STATUS_SUCCESS is returned.  Read on in unlink_nt. */
557               if (status != STATUS_DELETE_PENDING
558                   && status != STATUS_OBJECT_NAME_NOT_FOUND
559                   && status != STATUS_OBJECT_PATH_NOT_FOUND)
560                 {
561                   debug_printf ("Directory %S not empty, found file <%S>, "
562                                  "query status = %p",
563                                 pc.get_nt_native_path (), &fname, status);
564                   return STATUS_DIRECTORY_NOT_EMPTY;
565                 }
566             }
567           pfni = (PFILE_NAMES_INFORMATION) ((caddr_t) pfni + pfni->NextEntryOffset);
568         }
569     }
570   while (NT_SUCCESS (NtQueryDirectoryFile (dir, NULL, NULL, 0, &io, pfni,
571                                            bufsiz, FileNamesInformation,
572                                            FALSE, NULL, FALSE)));
573   return STATUS_SUCCESS;
574 }
575
576 NTSTATUS
577 unlink_nt (path_conv &pc)
578 {
579   NTSTATUS status;
580   HANDLE fh, fh_ro = NULL;
581   OBJECT_ATTRIBUTES attr;
582   IO_STATUS_BLOCK io;
583   HANDLE old_trans = NULL, trans = NULL;
584   ULONG num_links = 1;
585   FILE_DISPOSITION_INFORMATION disp = { TRUE };
586   int reopened = 0;
587
588   bin_status bin_stat = dont_move;
589
590   syscall_printf ("Trying to delete %S, isdir = %d",
591                   pc.get_nt_native_path (), pc.isdir ());
592   ACCESS_MASK access = DELETE;
593   ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT;
594   /* Add the reparse point flag to native symlinks, otherwise we remove the
595      target, not the symlink. */
596   if (pc.is_rep_symlink ())
597     flags |= FILE_OPEN_REPARSE_POINT;
598
599   pc.get_object_attr (attr, sec_none_nih);
600   /* If the R/O attribute is set, we have to open the file with
601      FILE_WRITE_ATTRIBUTES to be able to remove this flags before trying
602      to delete it.  We do this separately because there are filesystems
603      out there (MVFS), which refuse a request to open a file for DELETE
604      if the DOS R/O attribute is set for the file.  After removing the R/O
605      attribute, just re-open the file for DELETE and go ahead. */
606   if (pc.file_attributes () & FILE_ATTRIBUTE_READONLY)
607     {
608       FILE_STANDARD_INFORMATION fsi;
609
610       /* If possible, hide the non-atomicity of the "remove R/O flag, remove
611          link to file" operation behind a transaction. */
612       if (wincap.has_transactions ()
613           && (pc.fs_flags () & FILE_SUPPORTS_TRANSACTIONS))
614         start_transaction (old_trans, trans);
615
616       status = NtOpenFile (&fh_ro, FILE_WRITE_ATTRIBUTES, &attr, &io,
617                            FILE_SHARE_VALID_FLAGS, flags);
618       if (NT_SUCCESS (status))
619         {
620           debug_printf ("Opening %S for removing R/O succeeded",
621                         pc.get_nt_native_path ());
622           NTSTATUS status2 = NtSetAttributesFile (fh_ro,
623                                                   pc.file_attributes ()
624                                                   & ~FILE_ATTRIBUTE_READONLY);
625           if (!NT_SUCCESS (status2))
626             debug_printf ("Removing R/O on %S failed, status = %p",
627                           pc.get_nt_native_path (), status2);
628           pc.init_reopen_attr (&attr, fh_ro);
629         }
630       else
631         debug_printf ("Opening %S for removing R/O failed, status = %p",
632                       pc.get_nt_native_path (), status);
633       if (pc.is_lnk_symlink ())
634         {
635           status = NtQueryInformationFile (fh_ro, &io, &fsi, sizeof fsi,
636                                            FileStandardInformation);
637           if (NT_SUCCESS (status))
638             num_links = fsi.NumberOfLinks;
639         }
640       access |= FILE_WRITE_ATTRIBUTES;
641     }
642   /* First try to open the file with only allowing sharing for delete.  If
643      the file has an open handle on it, other than just for deletion, this
644      will fail.  That indicates that the file has to be moved to the recycle
645      bin so that it actually disappears from its directory even though its
646      in use.  Otherwise, if opening doesn't fail, the file is not in use and
647      we can go straight to setting the delete disposition flag.
648      
649      NOTE: The missing sharing modes FILE_SHARE_READ and FILE_SHARE_WRITE do
650            NOT result in a STATUS_SHARING_VIOLATION, if another handle is
651            opened for reading/writing metadata only.  In other words, if
652            another handle is open, but does not have the file open with
653            FILE_READ_DATA or FILE_WRITE_DATA, the following NtOpenFile call
654            will succeed.  So, apparently there is no reliable way to find out
655            if a file is already open elsewhere for other purposes than
656            reading and writing data.  */
657   status = NtOpenFile (&fh, access, &attr, &io, FILE_SHARE_DELETE, flags);
658   if (status == STATUS_SHARING_VIOLATION || status == STATUS_LOCK_NOT_GRANTED)
659     {
660       /* STATUS_LOCK_NOT_GRANTED can be generated under not quite clear
661          circumstances when trying to open a file on NFS with FILE_SHARE_DELETE
662          only.  This has been observed with SFU 3.5 if the NFS share has been
663          mounted under a drive letter.  It's not generated for all files, but
664          only for some.  If it's generated once for a file, it will be
665          generated all the time.  It looks like wrong file state information
666          is stored within the NFS client, for no apparent reason, which never
667          times out.  Opening the file with FILE_SHARE_VALID_FLAGS will work,
668          though, and it is then possible to delete the file quite normally.
669
670          NFS implements its own mechanism to remove in-use files which
671          looks quite similar to what we do in try_to_bin for remote files.
672          That's why we don't call try_to_bin on NFS.
673
674          Netapp filesystems don't understand the "move and delete" method
675          at all and have all kinds of weird effects.  Just setting the delete
676          dispositon usually works fine, though. */
677       debug_printf ("Sharing violation when opening %S",
678                     pc.get_nt_native_path ());
679       if (!pc.fs_is_nfs () && !pc.fs_is_netapp ())
680         bin_stat = move_to_bin;
681       if (!pc.isdir () || pc.isremote ())
682         status = NtOpenFile (&fh, access, &attr, &io,
683                              FILE_SHARE_VALID_FLAGS, flags);
684       else
685         {
686           /* It's getting tricky.  The directory is opened in some process,
687              so we're supposed to move it to the recycler and mark it for
688              deletion.  But what if the directory is not empty?  The move
689              will work, but the subsequent delete will fail.  So we would
690              have to move it back.  That's bad, because the directory would
691              be moved around which results in a temporary inconsistent state.
692              So, what we do here is to test if the directory is empty.  If
693              not, we bail out with STATUS_DIRECTORY_NOT_EMPTY.  The below code
694              tests for at least three entries in the directory, ".", "..",
695              and another one.  Three entries means, not empty.  This doesn't
696              work for the root directory of a drive, but the root dir can
697              neither be deleted, nor moved anyway. */
698           status = NtOpenFile (&fh, access | FILE_LIST_DIRECTORY | SYNCHRONIZE,
699                                &attr, &io, FILE_SHARE_VALID_FLAGS,
700                                flags | FILE_SYNCHRONOUS_IO_NONALERT);
701           if (NT_SUCCESS (status))
702             {
703               status = check_dir_not_empty (fh, pc);
704               if (!NT_SUCCESS (status))
705                 {
706                   NtClose (fh);
707                   if (fh_ro)
708                     NtClose (fh_ro);
709                   goto out;
710                 }
711             }
712         }
713     }
714   if (fh_ro)
715     NtClose (fh_ro);
716   if (!NT_SUCCESS (status))
717     {
718       if (status == STATUS_DELETE_PENDING)
719         {
720           debug_printf ("Delete %S already pending", pc.get_nt_native_path ());
721           status = STATUS_SUCCESS;
722           goto out;
723         }
724       debug_printf ("Opening %S for delete failed, status = %p",
725                     pc.get_nt_native_path (), status);
726       goto out;
727     }
728   /* Try to move to bin if a sharing violation occured.  If that worked,
729      we're done. */
730   if (bin_stat == move_to_bin
731       && (bin_stat = try_to_bin (pc, fh, access)) == has_been_moved)
732     {
733       status = STATUS_SUCCESS;
734       goto out;
735     }
736
737 try_again:
738   /* Try to set delete disposition. */
739   status = NtSetInformationFile (fh, &io, &disp, sizeof disp,
740                                  FileDispositionInformation);
741   if (!NT_SUCCESS (status))
742     {
743       debug_printf ("Setting delete disposition on %S failed, status = %p",
744                     pc.get_nt_native_path (), status);
745       if (status == STATUS_DIRECTORY_NOT_EMPTY)
746         {
747           NTSTATUS status2 = STATUS_SUCCESS;
748
749           if (!reopened)
750             {
751               /* Have to close and reopen the file from scratch, otherwise
752                  we collide with the delete-only sharing mode. */
753               pc.get_object_attr (attr, sec_none_nih);
754               NtClose (fh);
755               status2 = NtOpenFile (&fh, access | FILE_LIST_DIRECTORY
756                                          | SYNCHRONIZE,
757                                     &attr, &io, FILE_SHARE_VALID_FLAGS,
758                                     flags | FILE_SYNCHRONOUS_IO_NONALERT);
759             }
760           if (NT_SUCCESS (status2) && reopened < 20)
761             {
762               /* Workaround rm -r problem:
763               
764                  Sometimes a deleted directory lingers in its parent dir
765                  after the deleting handle has already been closed.  This
766                  can break deleting the parent dir.  See the comment in
767                  check_dir_not_empty for more information.
768
769                  What we do here is this:  If check_dir_not_empty returns
770                  STATUS_SUCCESS, the dir is either empty, or only inhabited
771                  by already deleted entries.  If so, we try to move the dir
772                  into the bin.  This usually works.
773                  
774                  However, if we're on a filesystem which doesn't support
775                  the try_to_bin method, or if moving to the bin doesn't work
776                  for some reason, just try to delete the directory again,
777                  with a very short grace period to free the CPU for a while.
778                  This gives the OS time to clean up.  5ms is enough in my
779                  testing to make sure that we don't have to try more than
780                  once in practically all cases.
781                  While this is an extrem bordercase, we don't want to hang
782                  infinitely in case a file in the directory is in the "delete
783                  pending" state but an application holds an open handle to it
784                  for a longer time.  So we don't try this more than 20 times,
785                  which means a process time of 100-120ms. */
786               if (check_dir_not_empty (fh, pc) == STATUS_SUCCESS)
787                 {
788                   if (bin_stat == dont_move)
789                     {
790                       bin_stat = move_to_bin;
791                       if (!pc.fs_is_nfs () && !pc.fs_is_netapp ())
792                         {
793                           debug_printf ("Try-to-bin %S",
794                                         pc.get_nt_native_path ());
795                           bin_stat = try_to_bin (pc, fh, access);
796                         }
797                     }
798                   if (bin_stat == has_been_moved)
799                     status = STATUS_SUCCESS;
800                   else
801                     {
802                       debug_printf ("Try %S again", pc.get_nt_native_path ());
803                       ++reopened;
804                       Sleep (5L);
805                       goto try_again;
806                     }
807                 }
808             }
809           else
810             {
811               fh = NULL;
812               debug_printf ("Opening dir %S for check_dir_not_empty failed, "
813                             "status = %p", pc.get_nt_native_path (), status2);
814             }
815         }
816       /* Trying to delete a hardlink to a file in use by the system in some
817          way (for instance, font files) by setting the delete disposition fails
818          with STATUS_CANNOT_DELETE.  Strange enough, deleting these hardlinks
819          using delete-on-close semantic works... most of the time.
820
821          Don't use delete-on-close on remote shares.  If two processes
822          have open handles on a file and one of them calls unlink, the
823          file is removed from the remote share even though the other
824          process still has an open handle.  That process than gets Win32
825          error 59, ERROR_UNEXP_NET_ERR when trying to access the file.
826          Microsoft KB 837665 describes this problem as a bug in 2K3, but
827          I have reproduced it on other systems. */
828       else if (status == STATUS_CANNOT_DELETE
829                && (!pc.isremote () || pc.fs_is_ncfsd ()))
830         {
831           HANDLE fh2;
832
833           debug_printf ("Cannot delete %S, try delete-on-close",
834                         pc.get_nt_native_path ());
835           /* Re-open from handle so we open the correct file no matter if it
836              has been moved to the bin or not. */
837           pc.init_reopen_attr (&attr, fh);
838           status = NtOpenFile (&fh2, DELETE, &attr, &io,
839                                bin_stat == move_to_bin ? FILE_SHARE_VALID_FLAGS
840                                                        : FILE_SHARE_DELETE,
841                                flags | FILE_DELETE_ON_CLOSE);
842           if (!NT_SUCCESS (status))
843             {
844               debug_printf ("Setting delete-on-close on %S failed, status = %p",
845                             pc.get_nt_native_path (), status);
846               /* This is really the last chance.  If it hasn't been moved
847                  to the bin already, try it now.  If moving to the bin
848                  succeeds, we got rid of the file in some way, even if
849                  unlinking didn't work. */
850               if (bin_stat == dont_move)
851                 bin_stat = try_to_bin (pc, fh, access);
852               if (bin_stat == has_been_moved)
853                 status = STATUS_SUCCESS;
854             }
855           else
856             NtClose (fh2);
857         }
858     }
859   if (fh)
860     {
861       if (access & FILE_WRITE_ATTRIBUTES)
862         {
863           /* Restore R/O attribute if setting the delete dispostion failed. */
864           if (!NT_SUCCESS (status))
865             NtSetAttributesFile (fh, pc.file_attributes ());
866           /* If we succeeded, restore R/O attribute to accommodate hardlinks.
867              Only ever try to do this for our own winsymlinks, because there's
868              a problem with setting the delete disposition:
869              http://msdn.microsoft.com/en-us/library/ff545765%28VS.85%29.aspx
870              "Subsequently, the only legal operation by such a caller is
871              to close the open file handle."
872
873              FIXME? On Vista and later, we could use FILE_HARD_LINK_INFORMATION
874              to find all hardlinks and use one of them to restore the R/O bit,
875              after the NtClose, but before we stop the transaction.  This
876              avoids the aforementioned problem entirely . */
877           else if (pc.is_lnk_symlink () && num_links > 1)
878             NtSetAttributesFile (fh, pc.file_attributes ());
879         }
880
881       NtClose (fh);
882
883     }
884 out:
885   /* Stop transaction if we started one. */
886   if ((access & FILE_WRITE_ATTRIBUTES)
887       && wincap.has_transactions ()
888       && (pc.fs_flags () & FILE_SUPPORTS_TRANSACTIONS))
889     stop_transaction (status, old_trans, trans);
890
891   syscall_printf ("%S, return status = %p", pc.get_nt_native_path (), status);
892   return status;
893 }
894
895 extern "C" int
896 unlink (const char *ourname)
897 {
898   int res = -1;
899   DWORD devn;
900   NTSTATUS status;
901
902   path_conv win32_name (ourname, PC_SYM_NOFOLLOW, stat_suffixes);
903
904   if (win32_name.error)
905     {
906       set_errno (win32_name.error);
907       goto done;
908     }
909
910   devn = win32_name.get_devn ();
911   if (isproc_dev (devn))
912     {
913       set_errno (EROFS);
914       goto done;
915     }
916
917   if (!win32_name.exists ())
918     {
919       debug_printf ("unlinking a nonexistent file");
920       set_errno (ENOENT);
921       goto done;
922     }
923   else if (win32_name.isdir ())
924     {
925       debug_printf ("unlinking a directory");
926       set_errno (EPERM);
927       goto done;
928     }
929
930   status = unlink_nt (win32_name);
931   if (NT_SUCCESS (status))
932     res = 0;
933   else
934     __seterrno_from_nt_status (status);
935
936  done:
937   syscall_printf ("%R = unlink(%s)", res, ourname);
938   return res;
939 }
940
941 extern "C" int
942 _remove_r (struct _reent *, const char *ourname)
943 {
944   path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
945
946   if (win32_name.error)
947     {
948       set_errno (win32_name.error);
949       syscall_printf ("%R = remove(%s)",-1, ourname);
950       return -1;
951     }
952
953   return win32_name.isdir () ? rmdir (ourname) : unlink (ourname);
954 }
955
956 extern "C" int
957 remove (const char *ourname)
958 {
959   path_conv win32_name (ourname, PC_SYM_NOFOLLOW);
960
961   if (win32_name.error)
962     {
963       set_errno (win32_name.error);
964       syscall_printf ("-1 = remove (%s)", ourname);
965       return -1;
966     }
967
968   int res = win32_name.isdir () ? rmdir (ourname) : unlink (ourname);
969   syscall_printf ("%R = remove(%s)", res, ourname);
970   return res;
971 }
972
973 extern "C" pid_t
974 getpid ()
975 {
976   syscall_printf ("%d = getpid()", myself->pid);
977   return myself->pid;
978 }
979
980 extern "C" pid_t
981 _getpid_r (struct _reent *)
982 {
983   return getpid ();
984 }
985
986 /* getppid: POSIX 4.1.1.1 */
987 extern "C" pid_t
988 getppid ()
989 {
990   syscall_printf ("%d = getppid()", myself->ppid);
991   return myself->ppid;
992 }
993
994 /* setsid: POSIX 4.3.2.1 */
995 extern "C" pid_t
996 setsid (void)
997 {
998 #ifdef NEWVFORK
999   vfork_save *vf = vfork_storage.val ();
1000   /* This is a horrible, horrible kludge */
1001   if (vf && vf->pid < 0)
1002     {
1003       pid_t pid = fork ();
1004       if (pid > 0)
1005         {
1006           syscall_printf ("longjmping due to vfork");
1007           vf->restore_pid (pid);
1008         }
1009       /* assuming that fork was successful */
1010     }
1011 #endif
1012
1013   if (myself->pgid == myself->pid)
1014     syscall_printf ("hmm.  pgid %d pid %d", myself->pgid, myself->pid);
1015   else
1016     {
1017       myself->ctty = -1;
1018       cygheap->manage_console_count ("setsid", 0);
1019       myself->sid = getpid ();
1020       myself->pgid = getpid ();
1021       if (cygheap->ctty)
1022         cygheap->close_ctty ();
1023       syscall_printf ("sid %d, pgid %d, %s", myself->sid, myself->pgid, myctty ());
1024       return myself->sid;
1025     }
1026
1027   set_errno (EPERM);
1028   return -1;
1029 }
1030
1031 extern "C" pid_t
1032 getsid (pid_t pid)
1033 {
1034   pid_t res;
1035   if (!pid)
1036     res = myself->sid;
1037   else
1038     {
1039       pinfo p (pid);
1040       if (p)
1041         res = p->sid;
1042       else
1043         {
1044           set_errno (ESRCH);
1045           res = -1;
1046         }
1047     }
1048   syscall_printf ("%R = getsid(%d)", pid);
1049   return res;
1050 }
1051
1052 extern "C" ssize_t
1053 read (int fd, void *ptr, size_t len)
1054 {
1055   pthread_testcancel ();
1056
1057   myfault efault;
1058   if (efault.faulted (EFAULT))
1059     return -1;
1060
1061   size_t res = (size_t) -1;
1062
1063   cygheap_fdget cfd (fd);
1064   if (cfd < 0)
1065     goto done;
1066
1067   if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY)
1068     {
1069       set_errno (EBADF);
1070       goto done;
1071     }
1072
1073   /* Could block, so let user know we at least got here.  */
1074   syscall_printf ("read(%d, %p, %d) %sblocking",
1075                   fd, ptr, len, cfd->is_nonblocking () ? "non" : "");
1076
1077   cfd->read (ptr, res = len);
1078
1079 done:
1080   syscall_printf ("%R = read(%d, %p, %d)", res, fd, ptr, len);
1081   MALLOC_CHECK;
1082   return (ssize_t) res;
1083 }
1084
1085 EXPORT_ALIAS (read, _read)
1086
1087 extern "C" ssize_t
1088 readv (int fd, const struct iovec *const iov, const int iovcnt)
1089 {
1090   pthread_testcancel ();
1091
1092   myfault efault;
1093   if (efault.faulted (EFAULT))
1094     return -1;
1095
1096   ssize_t res = -1;
1097   const ssize_t tot = check_iovec_for_read (iov, iovcnt);
1098
1099   cygheap_fdget cfd (fd);
1100   if (cfd < 0)
1101     goto done;
1102
1103   if (tot <= 0)
1104     {
1105       res = tot;
1106       goto done;
1107     }
1108
1109   if ((cfd->get_flags () & O_ACCMODE) == O_WRONLY)
1110     {
1111       set_errno (EBADF);
1112       goto done;
1113     }
1114
1115   /* Could block, so let user know we at least got here.  */
1116   syscall_printf ("readv(%d, %p, %d) %sblocking",
1117                   fd, iov, iovcnt, cfd->is_nonblocking () ? "non" : "");
1118
1119   res = cfd->readv (iov, iovcnt, tot);
1120
1121 done:
1122   syscall_printf ("%R = readv(%d, %p, %d)", res, fd, iov, iovcnt);
1123   MALLOC_CHECK;
1124   return res;
1125 }
1126
1127 extern "C" ssize_t
1128 pread (int fd, void *ptr, size_t len, _off64_t off)
1129 {
1130   pthread_testcancel ();
1131
1132   ssize_t res;
1133   cygheap_fdget cfd (fd);
1134   if (cfd < 0)
1135     res = -1;
1136   else
1137     res = cfd->pread (ptr, len, off);
1138
1139   syscall_printf ("%R = pread(%d, %p, %d, %d)", res, fd, ptr, len, off);
1140   return res;
1141 }
1142
1143 extern "C" ssize_t
1144 write (int fd, const void *ptr, size_t len)
1145 {
1146   pthread_testcancel ();
1147
1148   myfault efault;
1149   if (efault.faulted (EFAULT))
1150     return -1;
1151
1152   int res = -1;
1153
1154   cygheap_fdget cfd (fd);
1155   if (cfd < 0)
1156     goto done;
1157
1158   if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
1159     {
1160       set_errno (EBADF);
1161       goto done;
1162     }
1163
1164   /* Could block, so let user know we at least got here.  */
1165   if (fd == 1 || fd == 2)
1166     paranoid_printf ("write(%d, %p, %d)", fd, ptr, len);
1167   else
1168     syscall_printf  ("write(%d, %p, %d)", fd, ptr, len);
1169
1170   res = cfd->write (ptr, len);
1171
1172 done:
1173   syscall_printf ("%R = write(%d, %p, %d)", res, fd, ptr, len);
1174
1175   MALLOC_CHECK;
1176   return res;
1177 }
1178
1179 EXPORT_ALIAS (write, _write)
1180
1181 extern "C" ssize_t
1182 writev (const int fd, const struct iovec *const iov, const int iovcnt)
1183 {
1184   pthread_testcancel ();
1185
1186   myfault efault;
1187   if (efault.faulted (EFAULT))
1188     return -1;
1189
1190   int res = -1;
1191   const ssize_t tot = check_iovec_for_write (iov, iovcnt);
1192
1193   cygheap_fdget cfd (fd);
1194   if (cfd < 0)
1195     goto done;
1196
1197   if (tot <= 0)
1198     {
1199       res = tot;
1200       goto done;
1201     }
1202
1203   if ((cfd->get_flags () & O_ACCMODE) == O_RDONLY)
1204     {
1205       set_errno (EBADF);
1206       goto done;
1207     }
1208
1209   /* Could block, so let user know we at least got here.  */
1210   if (fd == 1 || fd == 2)
1211     paranoid_printf ("writev(%d, %p, %d)", fd, iov, iovcnt);
1212   else
1213     syscall_printf  ("writev(%d, %p, %d)", fd, iov, iovcnt);
1214
1215   res = cfd->writev (iov, iovcnt, tot);
1216
1217 done:
1218   if (fd == 1 || fd == 2)
1219     paranoid_printf ("%R = writev(%d, %p, %d)", res, fd, iov, iovcnt);
1220   else
1221     syscall_printf ("%R = writev(%d, %p, %d)", res, fd, iov, iovcnt);
1222
1223   MALLOC_CHECK;
1224   return res;
1225 }
1226
1227 extern "C" ssize_t
1228 pwrite (int fd, void *ptr, size_t len, _off64_t off)
1229 {
1230   pthread_testcancel ();
1231
1232   ssize_t res;
1233   cygheap_fdget cfd (fd);
1234   if (cfd < 0)
1235     res = -1;
1236   else
1237     res = cfd->pwrite (ptr, len, off);
1238
1239   syscall_printf ("%R = pwrite(%d, %p, %d, %d)", res, fd, ptr, len, off);
1240   return res;
1241 }
1242
1243 /* _open */
1244 /* newlib's fcntl.h defines _open as taking variable args so we must
1245    correspond.  The third arg if it exists is: mode_t mode. */
1246 extern "C" int
1247 open (const char *unix_path, int flags, ...)
1248 {
1249   int res = -1;
1250   va_list ap;
1251   mode_t mode = 0;
1252
1253   syscall_printf ("open(%s, %p)", unix_path, flags);
1254   pthread_testcancel ();
1255   myfault efault;
1256   if (efault.faulted (EFAULT))
1257     /* errno already set */;
1258   else if (!*unix_path)
1259     set_errno (ENOENT);
1260   else
1261     {
1262       /* check for optional mode argument */
1263       va_start (ap, flags);
1264       mode = va_arg (ap, mode_t);
1265       va_end (ap);
1266
1267       fhandler_base *fh;
1268       cygheap_fdnew fd;
1269
1270       if (fd >= 0)
1271         {
1272           /* This is a temporary kludge until all utilities can catch up with
1273              a change in behavior that implements linux functionality:  opening
1274              a tty should not automatically cause it to become the controlling
1275              tty for the process.  */
1276           int opt = PC_OPEN | ((flags & (O_NOFOLLOW | O_EXCL))
1277                                ?  PC_SYM_NOFOLLOW : PC_SYM_FOLLOW);
1278           if (!(flags & O_NOCTTY)&& fd > 2)
1279             {
1280               flags |= O_NOCTTY;
1281               opt |= PC_CTTY;   /* flag that, if opened, this fhandler could
1282                                    later be capable of being a controlling
1283                                    terminal if /dev/tty is opened. */
1284             }
1285           if (!(fh = build_fh_name (unix_path, opt, stat_suffixes)))
1286             res = -1;           // errno already set
1287           else if ((flags & O_NOFOLLOW) && fh->issymlink ())
1288             {
1289               delete fh;
1290               res = -1;
1291               set_errno (ELOOP);
1292             }
1293           else if ((flags & O_DIRECTORY) && !fh->pc.isdir ())
1294             {
1295               delete fh;
1296               res = -1;
1297               set_errno (ENOTDIR);
1298             }
1299           else if (((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) && fh->exists ())
1300             {
1301               delete fh;
1302               res = -1;
1303               set_errno (EEXIST);
1304             }
1305           else if ((fh->is_fs_special () && fh->device_access_denied (flags))
1306                    || !fh->open_with_arch (flags, (mode & 07777) & ~cygheap->umask))
1307             {
1308               delete fh;
1309               res = -1;
1310             }
1311           else
1312             {
1313               fd = fh;
1314               if (fd <= 2)
1315                 set_std_handle (fd);
1316               res = fd;
1317             }
1318         }
1319     }
1320
1321   syscall_printf ("%R = open(%s, %p)", res, unix_path, flags);
1322   return res;
1323 }
1324
1325 EXPORT_ALIAS (open, _open )
1326 EXPORT_ALIAS (open, _open64 )
1327
1328 extern "C" _off64_t
1329 lseek64 (int fd, _off64_t pos, int dir)
1330 {
1331   _off64_t res;
1332
1333   if (dir != SEEK_SET && dir != SEEK_CUR && dir != SEEK_END)
1334     {
1335       set_errno (EINVAL);
1336       res = -1;
1337     }
1338   else
1339     {
1340       cygheap_fdget cfd (fd);
1341       if (cfd >= 0)
1342         res = cfd->lseek (pos, dir);
1343       else
1344         res = -1;
1345     }
1346   syscall_printf ("%R = lseek(%d, %D, %d)", res, fd, pos, dir);
1347
1348   return res;
1349 }
1350
1351 EXPORT_ALIAS (lseek64, _lseek64)
1352
1353 extern "C" _off_t
1354 lseek (int fd, _off_t pos, int dir)
1355 {
1356   return lseek64 (fd, (_off64_t) pos, dir);
1357 }
1358
1359 EXPORT_ALIAS (lseek, _lseek)
1360
1361 extern "C" int
1362 close (int fd)
1363 {
1364   int res;
1365
1366   syscall_printf ("close(%d)", fd);
1367
1368   pthread_testcancel ();
1369
1370   MALLOC_CHECK;
1371   cygheap_fdget cfd (fd, true);
1372   if (cfd < 0)
1373     res = -1;
1374   else
1375     {
1376       res = cfd->close_with_arch ();
1377       cfd.release ();
1378     }
1379
1380   syscall_printf ("%R = close(%d)", res, fd);
1381   MALLOC_CHECK;
1382   return res;
1383 }
1384
1385 EXPORT_ALIAS (close, _close)
1386
1387 extern "C" int
1388 isatty (int fd)
1389 {
1390   int res;
1391
1392   cygheap_fdget cfd (fd);
1393   if (cfd < 0)
1394     res = 0;
1395   else
1396     res = cfd->is_tty ();
1397   syscall_printf ("%R = isatty(%d)", res, fd);
1398   return res;
1399 }
1400 EXPORT_ALIAS (isatty, _isatty)
1401
1402 extern "C" int
1403 link (const char *oldpath, const char *newpath)
1404 {
1405   int res = -1;
1406   fhandler_base *fh;
1407
1408   if (!(fh = build_fh_name (oldpath, PC_SYM_NOFOLLOW | PC_KEEP_HANDLE,
1409                             stat_suffixes)))
1410     goto error;
1411
1412   if (fh->error ())
1413     {
1414       debug_printf ("got %d error from build_fh_name", fh->error ());
1415       set_errno (fh->error ());
1416     }
1417   else if (fh->pc.isdir ())
1418     set_errno (EPERM); /* We do not permit linking directories.  */
1419   else if (!fh->pc.exists ())
1420     set_errno (ENOENT);
1421   else
1422     res = fh->link (newpath);
1423
1424   delete fh;
1425  error:
1426   syscall_printf ("%R = link(%s, %s)", res, oldpath, newpath);
1427   return res;
1428 }
1429
1430 /* chown: POSIX 5.6.5.1 */
1431 /*
1432  * chown () is only implemented for Windows NT.  Under other operating
1433  * systems, it is only a stub that always returns zero.
1434  */
1435 static int
1436 chown_worker (const char *name, unsigned fmode, __uid32_t uid, __gid32_t gid)
1437 {
1438   int res = -1;
1439   fhandler_base *fh;
1440
1441   if (!(fh = build_fh_name (name, fmode, stat_suffixes)))
1442     goto error;
1443
1444   if (fh->error ())
1445     {
1446       debug_printf ("got %d error from build_fh_name", fh->error ());
1447       set_errno (fh->error ());
1448     }
1449   else
1450     res = fh->fchown (uid, gid);
1451
1452   delete fh;
1453  error:
1454   syscall_printf ("%R = %schown(%s,...)",
1455                   res, (fmode & PC_SYM_NOFOLLOW) ? "l" : "", name);
1456   return res;
1457 }
1458
1459 extern "C" int
1460 chown32 (const char * name, __uid32_t uid, __gid32_t gid)
1461 {
1462   return chown_worker (name, PC_SYM_FOLLOW, uid, gid);
1463 }
1464
1465 extern "C" int
1466 chown (const char * name, __uid16_t uid, __gid16_t gid)
1467 {
1468   return chown_worker (name, PC_SYM_FOLLOW,
1469                        uid16touid32 (uid), gid16togid32 (gid));
1470 }
1471
1472 extern "C" int
1473 lchown32 (const char * name, __uid32_t uid, __gid32_t gid)
1474 {
1475   return chown_worker (name, PC_SYM_NOFOLLOW, uid, gid);
1476 }
1477
1478 extern "C" int
1479 lchown (const char * name, __uid16_t uid, __gid16_t gid)
1480 {
1481   return chown_worker (name, PC_SYM_NOFOLLOW,
1482                        uid16touid32 (uid), gid16togid32 (gid));
1483 }
1484
1485 extern "C" int
1486 fchown32 (int fd, __uid32_t uid, __gid32_t gid)
1487 {
1488   cygheap_fdget cfd (fd);
1489   if (cfd < 0)
1490     {
1491       syscall_printf ("-1 = fchown (%d,...)", fd);
1492       return -1;
1493     }
1494
1495   int res = cfd->fchown (uid, gid);
1496
1497   syscall_printf ("%R = fchown(%s,...)", res, cfd->get_name ());
1498   return res;
1499 }
1500
1501 extern "C" int
1502 fchown (int fd, __uid16_t uid, __gid16_t gid)
1503 {
1504   return fchown32 (fd, uid16touid32 (uid), gid16togid32 (gid));
1505 }
1506
1507 /* umask: POSIX 5.3.3.1 */
1508 extern "C" mode_t
1509 umask (mode_t mask)
1510 {
1511   mode_t oldmask;
1512
1513   oldmask = cygheap->umask;
1514   cygheap->umask = mask & 0777;
1515   return oldmask;
1516 }
1517
1518 int
1519 chmod_device (path_conv& pc, mode_t mode)
1520 {
1521   return mknod_worker (pc.get_win32 (), pc.dev.mode & S_IFMT, mode, pc.dev.get_major (), pc.dev.get_minor ());
1522 }
1523
1524 #define FILTERED_MODE(m)        ((m) & (S_ISUID | S_ISGID | S_ISVTX \
1525                                         | S_IRWXU | S_IRWXG | S_IRWXO))
1526
1527 /* chmod: POSIX 5.6.4.1 */
1528 extern "C" int
1529 chmod (const char *path, mode_t mode)
1530 {
1531   int res = -1;
1532   fhandler_base *fh;
1533   if (!(fh = build_fh_name (path, PC_SYM_FOLLOW, stat_suffixes)))
1534     goto error;
1535
1536   if (fh->error ())
1537     {
1538       debug_printf ("got %d error from build_fh_name", fh->error ());
1539       set_errno (fh->error ());
1540     }
1541   else
1542     res = fh->fchmod (FILTERED_MODE (mode));
1543
1544   delete fh;
1545  error:
1546   syscall_printf ("%R = chmod(%s, %p)", res, path, mode);
1547   return res;
1548 }
1549
1550 /* fchmod: P96 5.6.4.1 */
1551
1552 extern "C" int
1553 fchmod (int fd, mode_t mode)
1554 {
1555   cygheap_fdget cfd (fd);
1556   if (cfd < 0)
1557     {
1558       syscall_printf ("-1 = fchmod (%d, 0%o)", fd, mode);
1559       return -1;
1560     }
1561
1562   return cfd->fchmod (FILTERED_MODE (mode));
1563 }
1564
1565 static void
1566 stat64_to_stat32 (struct __stat64 *src, struct __stat32 *dst)
1567 {
1568   dst->st_dev = ((src->st_dev >> 8) & 0xff00) | (src->st_dev & 0xff);
1569   dst->st_ino = ((unsigned) (src->st_ino >> 32)) | (unsigned) src->st_ino;
1570   dst->st_mode = src->st_mode;
1571   dst->st_nlink = src->st_nlink;
1572   dst->st_uid = src->st_uid;
1573   dst->st_gid = src->st_gid;
1574   dst->st_rdev = ((src->st_rdev >> 8) & 0xff00) | (src->st_rdev & 0xff);
1575   dst->st_size = src->st_size;
1576   dst->st_atim = src->st_atim;
1577   dst->st_mtim = src->st_mtim;
1578   dst->st_ctim = src->st_ctim;
1579   dst->st_blksize = src->st_blksize;
1580   dst->st_blocks = src->st_blocks;
1581 }
1582
1583 extern "C" int
1584 fstat64 (int fd, struct __stat64 *buf)
1585 {
1586   int res;
1587
1588   cygheap_fdget cfd (fd);
1589   if (cfd < 0)
1590     res = -1;
1591   else
1592     {
1593       memset (buf, 0, sizeof (struct __stat64));
1594       res = cfd->fstat (buf);
1595       if (!res)
1596         {
1597           if (!buf->st_ino)
1598             buf->st_ino = cfd->get_ino ();
1599           if (!buf->st_dev)
1600             buf->st_dev = cfd->get_device ();
1601           if (!buf->st_rdev)
1602             buf->st_rdev = buf->st_dev;
1603         }
1604     }
1605
1606   syscall_printf ("%R = fstat(%d, %p)", res, fd, buf);
1607   return res;
1608 }
1609
1610 extern "C" int
1611 _fstat64_r (struct _reent *ptr, int fd, struct __stat64 *buf)
1612 {
1613   int ret;
1614
1615   if ((ret = fstat64 (fd, buf)) == -1)
1616     ptr->_errno = get_errno ();
1617   return ret;
1618 }
1619
1620 extern "C" int
1621 fstat (int fd, struct __stat32 *buf)
1622 {
1623   struct __stat64 buf64;
1624   int ret = fstat64 (fd, &buf64);
1625   if (!ret)
1626     stat64_to_stat32 (&buf64, buf);
1627   return ret;
1628 }
1629
1630 extern "C" int
1631 _fstat_r (struct _reent *ptr, int fd, struct __stat32 *buf)
1632 {
1633   int ret;
1634
1635   if ((ret = fstat (fd, buf)) == -1)
1636     ptr->_errno = get_errno ();
1637   return ret;
1638 }
1639
1640 /* fsync: P96 6.6.1.1 */
1641 extern "C" int
1642 fsync (int fd)
1643 {
1644   pthread_testcancel ();
1645   cygheap_fdget cfd (fd);
1646   if (cfd < 0)
1647     {
1648       syscall_printf ("-1 = fsync (%d)", fd);
1649       return -1;
1650     }
1651   return cfd->fsync ();
1652 }
1653
1654 EXPORT_ALIAS (fsync, fdatasync)
1655
1656 static void
1657 sync_worker (HANDLE dir, USHORT len, LPCWSTR vol)
1658 {
1659   NTSTATUS status;
1660   HANDLE fh;
1661   IO_STATUS_BLOCK io;
1662   OBJECT_ATTRIBUTES attr;
1663   UNICODE_STRING uvol = { len, len, (WCHAR *) vol };
1664
1665   InitializeObjectAttributes (&attr, &uvol, OBJ_CASE_INSENSITIVE, dir, NULL);
1666   status = NtOpenFile (&fh, GENERIC_WRITE, &attr, &io,
1667                        FILE_SHARE_VALID_FLAGS, 0);
1668   if (!NT_SUCCESS (status))
1669     debug_printf ("NtOpenFile (%S), status %p", &uvol, status);
1670   else
1671     {
1672       status = NtFlushBuffersFile (fh, &io);
1673       if (!NT_SUCCESS (status))
1674         debug_printf ("NtFlushBuffersFile (%S), status %p", &uvol, status);
1675       NtClose (fh);
1676     }
1677 }
1678
1679 /* sync: SUSv3 */
1680 extern "C" void
1681 sync ()
1682 {
1683   OBJECT_ATTRIBUTES attr;
1684   NTSTATUS status;
1685   HANDLE devhdl;
1686   UNICODE_STRING device;
1687
1688   /* Open \Device object directory. */
1689   RtlInitUnicodeString (&device, L"\\Device");
1690   InitializeObjectAttributes (&attr, &device, OBJ_CASE_INSENSITIVE, NULL, NULL);
1691   status = NtOpenDirectoryObject (&devhdl, DIRECTORY_QUERY, &attr);
1692   if (!NT_SUCCESS (status))
1693     {
1694       debug_printf ("NtOpenDirectoryObject, status %p", status);
1695       return;
1696     }
1697   /* Traverse \Device directory ... */
1698   PDIRECTORY_BASIC_INFORMATION dbi = (PDIRECTORY_BASIC_INFORMATION)
1699                                      alloca (640);
1700   BOOLEAN restart = TRUE;
1701   ULONG context = 0;
1702   while (NT_SUCCESS (NtQueryDirectoryObject (devhdl, dbi, 640, TRUE, restart,
1703                                              &context, NULL)))
1704     {
1705       restart = FALSE;
1706       /* ... and call sync_worker for each HarddiskVolumeX entry. */
1707       if (dbi->ObjectName.Length >= 15 * sizeof (WCHAR)
1708           && !wcsncasecmp (dbi->ObjectName.Buffer, L"HarddiskVolume", 14)
1709           && iswdigit (dbi->ObjectName.Buffer[14]))
1710         sync_worker (devhdl, dbi->ObjectName.Length, dbi->ObjectName.Buffer);
1711     }
1712   NtClose (devhdl);
1713 }
1714
1715 /* Cygwin internal */
1716 int __stdcall
1717 stat_worker (path_conv &pc, struct __stat64 *buf)
1718 {
1719   int res = -1;
1720
1721   myfault efault;
1722   if (efault.faulted (EFAULT))
1723     goto error;
1724
1725   if (pc.error)
1726     {
1727       debug_printf ("got %d error from path_conv", pc.error);
1728       set_errno (pc.error);
1729     }
1730   else if (pc.exists ())
1731     {
1732       fhandler_base *fh;
1733
1734       if (!(fh = build_fh_pc (pc)))
1735         goto error;
1736
1737       debug_printf ("(%S, %p, %p), file_attributes %d",
1738                     pc.get_nt_native_path (), buf, fh, (DWORD) *fh);
1739       memset (buf, 0, sizeof (*buf));
1740       res = fh->fstat (buf);
1741       if (!res)
1742         {
1743           if (!buf->st_ino)
1744             buf->st_ino = fh->get_ino ();
1745           if (!buf->st_dev)
1746             buf->st_dev = fh->get_device ();
1747           if (!buf->st_rdev)
1748             buf->st_rdev = buf->st_dev;
1749         }
1750       delete fh;
1751     }
1752   else
1753     set_errno (ENOENT);
1754
1755  error:
1756   MALLOC_CHECK;
1757   syscall_printf ("%d = (%S,%p)", res, pc.get_nt_native_path (), buf);
1758   return res;
1759 }
1760
1761 extern "C" int
1762 stat64 (const char *name, struct __stat64 *buf)
1763 {
1764   syscall_printf ("entering");
1765   path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE,
1766                 stat_suffixes);
1767   return stat_worker (pc, buf);
1768 }
1769
1770 extern "C" int
1771 _stat64_r (struct _reent *ptr, const char *name, struct __stat64 *buf)
1772 {
1773   int ret;
1774
1775   if ((ret = stat64 (name, buf)) == -1)
1776     ptr->_errno = get_errno ();
1777   return ret;
1778 }
1779
1780 extern "C" int
1781 stat (const char *name, struct __stat32 *buf)
1782 {
1783   struct __stat64 buf64;
1784   int ret = stat64 (name, &buf64);
1785   if (!ret)
1786     stat64_to_stat32 (&buf64, buf);
1787   return ret;
1788 }
1789
1790 extern "C" int
1791 _stat_r (struct _reent *ptr, const char *name, struct __stat32 *buf)
1792 {
1793   int ret;
1794
1795   if ((ret = stat (name, buf)) == -1)
1796     ptr->_errno = get_errno ();
1797   return ret;
1798 }
1799
1800 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
1801 extern "C" int
1802 lstat64 (const char *name, struct __stat64 *buf)
1803 {
1804   syscall_printf ("entering");
1805   path_conv pc (name, PC_SYM_NOFOLLOW | PC_POSIX | PC_KEEP_HANDLE,
1806                 stat_suffixes);
1807   return stat_worker (pc, buf);
1808 }
1809
1810 /* lstat: Provided by SVR4 and 4.3+BSD, POSIX? */
1811 extern "C" int
1812 lstat (const char *name, struct __stat32 *buf)
1813 {
1814   struct __stat64 buf64;
1815   int ret = lstat64 (name, &buf64);
1816   if (!ret)
1817     stat64_to_stat32 (&buf64, buf);
1818   return ret;
1819 }
1820
1821 extern "C" int
1822 access (const char *fn, int flags)
1823 {
1824   // flags were incorrectly specified
1825   int res = -1;
1826   if (flags & ~(F_OK|R_OK|W_OK|X_OK))
1827     set_errno (EINVAL);
1828   else
1829     {
1830       fhandler_base *fh = build_fh_name (fn, PC_SYM_FOLLOW | PC_KEEP_HANDLE,
1831                                          stat_suffixes);
1832       if (fh)
1833         {
1834           res =  fh->fhaccess (flags, false);
1835           delete fh;
1836         }
1837     }
1838   debug_printf ("returning %d", res);
1839   return res;
1840 }
1841
1842 /* Linux provides this extension; it is basically a wrapper around the
1843    POSIX:2008 faccessat (AT_FDCWD, fn, flags, AT_EACCESS).  We also
1844    provide eaccess as an alias for this, in cygwin.din.  */
1845 extern "C" int
1846 euidaccess (const char *fn, int flags)
1847 {
1848   // flags were incorrectly specified
1849   int res = -1;
1850   if (flags & ~(F_OK|R_OK|W_OK|X_OK))
1851     set_errno (EINVAL);
1852   else
1853     {
1854       fhandler_base *fh = build_fh_name (fn, PC_SYM_FOLLOW | PC_KEEP_HANDLE,
1855                                          stat_suffixes);
1856       if (fh)
1857         {
1858           res =  fh->fhaccess (flags, true);
1859           delete fh;
1860         }
1861     }
1862   debug_printf ("returning %d", res);
1863   return res;
1864 }
1865
1866 static void
1867 rename_append_suffix (path_conv &pc, const char *path, size_t len,
1868                       const char *suffix)
1869 {
1870   char buf[len + 5];
1871
1872   if (ascii_strcasematch (path + len - 4, ".lnk")
1873       || ascii_strcasematch (path + len - 4, ".exe"))
1874     len -= 4;
1875   stpcpy (stpncpy (buf, path, len), suffix);
1876   pc.check (buf, PC_SYM_NOFOLLOW);
1877 }
1878
1879 /* This function tests if a filename has one of the "approved" executable
1880    suffix.  This list is probably not complete... */
1881 static inline bool
1882 nt_path_has_executable_suffix (PUNICODE_STRING upath)
1883 {
1884   static const PUNICODE_STRING blessed_executable_suffixes[] =
1885   {
1886     &ro_u_com,
1887     &ro_u_dll,  /* Messy, messy.  Per MSDN, the GetBinaryType function is
1888                    supposed to return with ERROR_BAD_EXE_FORMAT. if the file
1889                    is a DLL.  On 64-bit Windows, this works as expected for
1890                    32-bit and 64-bit DLLs.  On 32-bit Windows this only works
1891                    for 32-bit DLLs.  For 64-bit DLLs, 32-bit Windows returns
1892                    true with the type set to SCS_64BIT_BINARY. */
1893     &ro_u_exe,
1894     &ro_u_scr,
1895     &ro_u_sys,
1896     NULL
1897   };
1898
1899   USHORT pos = upath->Length / sizeof (WCHAR);
1900   PWCHAR path;
1901   UNICODE_STRING usuf;
1902   const PUNICODE_STRING *suf;
1903
1904   /* Too short for a native path? */
1905   if (pos < 8)
1906     return false;
1907   /* Assumption: All executable suffixes have a length of three. */
1908   path = upath->Buffer + pos - 4;
1909   if (*path != L'.')
1910     return false;
1911   RtlInitCountedUnicodeString (&usuf, path, 4 * sizeof (WCHAR));
1912   for (suf = blessed_executable_suffixes; *suf; ++suf)
1913     if (RtlEqualUnicodeString (&usuf, *suf, TRUE))
1914       return true;
1915   return false;
1916 }
1917
1918 extern "C" int
1919 rename (const char *oldpath, const char *newpath)
1920 {
1921   tmp_pathbuf tp;
1922   int res = -1;
1923   path_conv oldpc, newpc, new2pc, *dstpc, *removepc = NULL;
1924   bool old_dir_requested = false, new_dir_requested = false;
1925   bool old_explicit_suffix = false, new_explicit_suffix = false;
1926   size_t olen, nlen;
1927   bool equal_path;
1928   NTSTATUS status = STATUS_SUCCESS;
1929   HANDLE fh = NULL, nfh;
1930   HANDLE old_trans = NULL, trans = NULL;
1931   OBJECT_ATTRIBUTES attr;
1932   IO_STATUS_BLOCK io;
1933   ULONG size;
1934   FILE_STANDARD_INFORMATION ofsi;
1935   PFILE_RENAME_INFORMATION pfri;
1936
1937   myfault efault;
1938   if (efault.faulted (EFAULT))
1939     return -1;
1940
1941   if (!*oldpath || !*newpath)
1942     {
1943       /* Reject rename("","x"), rename("x","").  */
1944       set_errno (ENOENT);
1945       goto out;
1946     }
1947   if (has_dot_last_component (oldpath, true))
1948     {
1949       /* Reject rename("dir/.","x").  */
1950       oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1951       set_errno (oldpc.isdir () ? EINVAL : ENOTDIR);
1952       goto out;
1953     }
1954   if (has_dot_last_component (newpath, true))
1955     {
1956       /* Reject rename("dir","x/.").  */
1957       newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes);
1958       set_errno (!newpc.exists () ? ENOENT : newpc.isdir () ? EINVAL : ENOTDIR);
1959       goto out;
1960     }
1961
1962   /* A trailing slash requires that the pathname points to an existing
1963      directory.  If it's not, it's a ENOTDIR condition.  The same goes
1964      for newpath a bit further down this function. */
1965   olen = strlen (oldpath);
1966   if (isdirsep (oldpath[olen - 1]))
1967     {
1968       char *buf;
1969       char *p = stpcpy (buf = tp.c_get (), oldpath) - 1;
1970       oldpath = buf;
1971       while (p >= oldpath && isdirsep (*p))
1972         *p-- = '\0';
1973       olen = p + 1 - oldpath;
1974       if (!olen)
1975         {
1976           /* The root directory cannot be renamed.  This also rejects
1977              the corner case of rename("/","/"), even though it is the
1978              same file.  */
1979           set_errno (EINVAL);
1980           goto out;
1981         }
1982       old_dir_requested = true;
1983     }
1984   oldpc.check (oldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1985   if (oldpc.error)
1986     {
1987       set_errno (oldpc.error);
1988       goto out;
1989     }
1990   if (!oldpc.exists ())
1991     {
1992       set_errno (ENOENT);
1993       goto out;
1994     }
1995   if (oldpc.isspecial () && !oldpc.issocket () && !oldpc.is_fs_special ())
1996     {
1997       /* No renames from virtual FS */
1998       set_errno (EROFS);
1999       goto out;
2000     }
2001   if (oldpc.has_attribute (FILE_ATTRIBUTE_REPARSE_POINT) && !oldpc.issymlink ())
2002     {
2003       /* Volume mount point.  If we try to rename a volume mount point, NT
2004          returns STATUS_NOT_SAME_DEVICE ==> Win32 ERROR_NOT_SAME_DEVICE ==>
2005          errno EXDEV.  That's bad since mv(1) will now perform a cross-device
2006          move.  So what we do here is to treat the volume mount point just
2007          like Linux treats a mount point. */
2008       set_errno (EBUSY);
2009       goto out;
2010     }
2011   if (old_dir_requested && !oldpc.isdir ())
2012     {
2013       /* Reject rename("file/","x").  */
2014       set_errno (ENOTDIR);
2015       goto out;
2016     }
2017   if (oldpc.known_suffix
2018        && (ascii_strcasematch (oldpath + olen - 4, ".lnk")
2019            || ascii_strcasematch (oldpath + olen - 4, ".exe")))
2020     old_explicit_suffix = true;
2021
2022   nlen = strlen (newpath);
2023   if (isdirsep (newpath[nlen - 1]))
2024     {
2025       char *buf;
2026       char *p = stpcpy (buf = tp.c_get (), newpath) - 1;
2027       newpath = buf;
2028       while (p >= newpath && isdirsep (*p))
2029         *p-- = '\0';
2030       nlen = p + 1 - newpath;
2031       if (!nlen) /* The root directory is never empty.  */
2032         {
2033           set_errno (ENOTEMPTY);
2034           goto out;
2035         }
2036       new_dir_requested = true;
2037     }
2038   newpc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes);
2039   if (newpc.error)
2040     {
2041       set_errno (newpc.error);
2042       goto out;
2043     }
2044   if (newpc.isspecial () && !newpc.issocket ()) /* No renames to virtual FSes */
2045     {
2046       set_errno (EROFS);
2047       goto out;
2048     }
2049   if (new_dir_requested && !(newpc.exists ()
2050                              ? newpc.isdir () : oldpc.isdir ()))
2051     {
2052       /* Reject rename("file1","file2/"), but allow rename("dir","d/").  */
2053       set_errno (newpc.exists () ? ENOTDIR : ENOENT);
2054       goto out;
2055     }
2056   if (newpc.exists () && (oldpc.isdir () ? !newpc.isdir () : newpc.isdir ()))
2057     {
2058       /* Reject rename("file","dir") and rename("dir","file").  */
2059       set_errno (newpc.isdir () ? EISDIR : ENOTDIR);
2060       goto out;
2061     }
2062   if (newpc.known_suffix
2063       && (ascii_strcasematch (newpath + nlen - 4, ".lnk")
2064           || ascii_strcasematch (newpath + nlen - 4, ".exe")))
2065     new_explicit_suffix = true;
2066
2067   /* This test is necessary in almost every case, so just do it once here. */
2068   equal_path = RtlEqualUnicodeString (oldpc.get_nt_native_path (),
2069                                       newpc.get_nt_native_path (),
2070                                       oldpc.objcaseinsensitive ());
2071
2072   /* First check if oldpath and newpath only differ by case.  If so, it's
2073      just a request to change the case of the filename.  By simply setting
2074      the file attributes to INVALID_FILE_ATTRIBUTES (which translates to
2075      "file doesn't exist"), all later tests are skipped. */
2076   if (oldpc.objcaseinsensitive () && newpc.exists () && equal_path
2077       && old_explicit_suffix == new_explicit_suffix)
2078     {
2079       if (RtlEqualUnicodeString (oldpc.get_nt_native_path (),
2080                                  newpc.get_nt_native_path (),
2081                                  FALSE))
2082         {
2083           res = 0;
2084           goto out;
2085         }
2086       newpc.file_attributes (INVALID_FILE_ATTRIBUTES);
2087     }
2088   else if (oldpc.isdir ())
2089     {
2090       /* Check for newpath being identical or a subdir of oldpath. */
2091       if (RtlPrefixUnicodeString (oldpc.get_nt_native_path (),
2092                                   newpc.get_nt_native_path (),
2093                                   TRUE))
2094         {
2095           if (newpc.get_nt_native_path ()->Length
2096               == oldpc.get_nt_native_path ()->Length)
2097             {
2098               res = 0;
2099               goto out;
2100             }
2101           if (*(PWCHAR) ((PBYTE) newpc.get_nt_native_path ()->Buffer
2102                          + oldpc.get_nt_native_path ()->Length) == L'\\')
2103             {
2104               set_errno (EINVAL);
2105               goto out;
2106             }
2107         }
2108     }
2109   else if (!newpc.exists ())
2110     {
2111       if (equal_path && old_explicit_suffix != new_explicit_suffix)
2112         {
2113           newpc.check (newpath, PC_SYM_NOFOLLOW);
2114           if (RtlEqualUnicodeString (oldpc.get_nt_native_path (),
2115                                      newpc.get_nt_native_path (),
2116                                      oldpc.objcaseinsensitive ()))
2117             {
2118               res = 0;
2119               goto out;
2120             }
2121         }
2122       else if (oldpc.is_lnk_special ()
2123                && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
2124                                               &ro_u_lnk, TRUE))
2125         rename_append_suffix (newpc, newpath, nlen, ".lnk");
2126       else if (oldpc.is_binary () && !old_explicit_suffix
2127                && oldpc.known_suffix
2128                && !nt_path_has_executable_suffix (newpc.get_nt_native_path ()))
2129         /* Never append .exe suffix if oldpath had .exe suffix given
2130            explicitely, or if oldpath wasn't already a .exe file, or
2131            if the destination filename has one of the blessed executable
2132            suffixes.
2133            Note: To rename an executable foo.exe to bar-without-suffix,
2134            the .exe suffix must be given explicitly in oldpath. */
2135         rename_append_suffix (newpc, newpath, nlen, ".exe");
2136     }
2137   else
2138     {
2139       if (equal_path && old_explicit_suffix != new_explicit_suffix)
2140         {
2141           newpc.check (newpath, PC_SYM_NOFOLLOW);
2142           if (RtlEqualUnicodeString (oldpc.get_nt_native_path (),
2143                                      newpc.get_nt_native_path (),
2144                                      oldpc.objcaseinsensitive ()))
2145             {
2146               res = 0;
2147               goto out;
2148             }
2149         }
2150       else if (oldpc.is_lnk_special ())
2151         {
2152           if (!newpc.is_lnk_special ()
2153               && !RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
2154                                              &ro_u_lnk, TRUE))
2155             {
2156               rename_append_suffix (new2pc, newpath, nlen, ".lnk");
2157               removepc = &newpc;
2158             }
2159         }
2160       else if (oldpc.is_binary ())
2161         {
2162           /* Never append .exe suffix if oldpath had .exe suffix given
2163              explicitely, or if newfile is a binary (in which case the given
2164              name probably makes sesne as it is), or if the destination
2165              filename has one of the blessed executable suffixes. */
2166           if (!old_explicit_suffix && oldpc.known_suffix
2167               && !newpc.is_binary ()
2168               && !nt_path_has_executable_suffix (newpc.get_nt_native_path ()))
2169             {
2170               rename_append_suffix (new2pc, newpath, nlen, ".exe");
2171               removepc = &newpc;
2172             }
2173         }
2174       else
2175         {
2176           if ((RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
2177                                           &ro_u_lnk, TRUE)
2178                || RtlEqualUnicodePathSuffix (newpc.get_nt_native_path (),
2179                                              &ro_u_exe, TRUE))
2180               && !new_explicit_suffix)
2181             {
2182               new2pc.check (newpath, PC_SYM_NOFOLLOW, stat_suffixes);
2183               newpc.get_nt_native_path ()->Length -= 4 * sizeof (WCHAR);
2184               if (new2pc.is_binary () || new2pc.is_lnk_special ())
2185                 removepc = &new2pc;
2186             }
2187         }
2188     }
2189   dstpc = (removepc == &newpc) ? &new2pc : &newpc;
2190
2191   /* Opening the file must be part of the transaction.  It's not sufficient
2192      to call only NtSetInformationFile under the transaction.  Therefore we
2193      have to start the transaction here, if necessary. */
2194   if (wincap.has_transactions ()
2195       && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS)
2196       && (dstpc->isdir ()
2197           || (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY))))
2198     start_transaction (old_trans, trans);
2199
2200   int retry_count;
2201   retry_count = 0;
2202 retry:
2203   /* Talking about inconsistent behaviour...
2204      - DELETE is required to rename a file.  So far, so good.
2205      - At least one cifs FS (Tru64) needs FILE_READ_ATTRIBUTE, otherwise the
2206        FileRenameInformation call fails with STATUS_ACCESS_DENIED.  However,
2207        on NFS we get a STATUS_ACCESS_DENIED if FILE_READ_ATTRIBUTE is used
2208        and the file we try to rename is a symlink.  Urgh.
2209      - Samba (only some versions?) doesn't like the FILE_SHARE_DELETE mode if
2210        the file has the R/O attribute set and returns STATUS_ACCESS_DENIED in
2211        that case. */
2212   {
2213     ULONG access = DELETE | (oldpc.fs_is_cifs () ? FILE_READ_ATTRIBUTES : 0);
2214     ULONG sharing = FILE_SHARE_READ | FILE_SHARE_WRITE
2215                     | (oldpc.fs_is_samba () ? 0 : FILE_SHARE_DELETE);
2216     ULONG flags = FILE_OPEN_FOR_BACKUP_INTENT
2217                   | (oldpc.is_rep_symlink () ? FILE_OPEN_REPARSE_POINT : 0);
2218     status = NtOpenFile (&fh, access,
2219                          oldpc.get_object_attr (attr, sec_none_nih),
2220                          &io, sharing, flags);
2221   }
2222   if (!NT_SUCCESS (status))
2223     {
2224       debug_printf ("status %p", status);
2225       if (status == STATUS_SHARING_VIOLATION
2226           && WaitForSingleObject (signal_arrived, 10L) != WAIT_OBJECT_0)
2227         {
2228           /* Typical BLODA problem.  Some virus scanners check newly generated
2229              files and while doing that disallow DELETE access.  That's really
2230              bad because it breaks applications which copy files by creating
2231              a temporary filename and then rename the temp filename to the
2232              target filename.  This renaming fails due to the jealous virus
2233              scanner and the application fails to create the target file.
2234
2235              This kludge tries to work around that by yielding until the
2236              sharing violation goes away, or a signal arrived, or after
2237              about a second, give or take. */
2238           if (++retry_count < 40)
2239             {
2240               yield ();
2241               goto retry;
2242             }
2243         }
2244       __seterrno_from_nt_status (status);
2245       goto out;
2246     }
2247
2248   /* Renaming a dir to another, existing dir fails always, even if
2249      ReplaceIfExists is set to TRUE and the existing dir is empty.  So
2250      we have to remove the destination dir first.  This also covers the
2251      case that the destination directory is not empty.  In that case,
2252      unlink_nt returns with STATUS_DIRECTORY_NOT_EMPTY. */
2253   if (dstpc->isdir ())
2254     {
2255       status = unlink_nt (*dstpc);
2256       if (!NT_SUCCESS (status))
2257         {
2258           __seterrno_from_nt_status (status);
2259           goto out;
2260         }
2261     }
2262   /* You can't copy a file if the destination exists and has the R/O
2263      attribute set.  Remove the R/O attribute first.  But first check
2264      if a removepc exists.  If so, dstpc points to a non-existing file
2265      due to a mangled suffix. */
2266   else if (!removepc && dstpc->has_attribute (FILE_ATTRIBUTE_READONLY))
2267     {
2268       status = NtOpenFile (&nfh, FILE_WRITE_ATTRIBUTES,
2269                            dstpc->get_object_attr (attr, sec_none_nih),
2270                            &io, FILE_SHARE_VALID_FLAGS,
2271                            FILE_OPEN_FOR_BACKUP_INTENT
2272                            | (dstpc->is_rep_symlink ()
2273                               ? FILE_OPEN_REPARSE_POINT : 0));
2274       if (!NT_SUCCESS (status))
2275         {
2276           __seterrno_from_nt_status (status);
2277           goto out;
2278         }
2279       status = NtSetAttributesFile (nfh, dstpc->file_attributes ()
2280                                          & ~FILE_ATTRIBUTE_READONLY);
2281       NtClose (nfh);
2282       if (!NT_SUCCESS (status))
2283         {
2284           __seterrno_from_nt_status (status);
2285           goto out;
2286         }
2287     }
2288
2289   /* SUSv3: If the old argument and the new argument resolve to the same
2290      existing file, rename() shall return successfully and perform no
2291      other action.
2292      The test tries to be as quick as possible.  First it tests for identical
2293      volume serial numbers because that information is available anyway.
2294      Then it tests if oldpath has more than 1 hardlink, then it opens newpath
2295      and tests for identical file ids.  If so, oldpath and newpath refer to
2296      the same file. */
2297   if ((removepc || dstpc->exists ())
2298       && !oldpc.isdir ()
2299       && dstpc->fs_serial_number () == oldpc.fs_serial_number ()
2300       && NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofsi, sizeof ofsi,
2301                                              FileStandardInformation))
2302       && ofsi.NumberOfLinks > 1
2303       && NT_SUCCESS (NtOpenFile (&nfh, READ_CONTROL,
2304                      (removepc ?: dstpc)->get_object_attr (attr, sec_none_nih),
2305                      &io, FILE_SHARE_VALID_FLAGS,
2306                      FILE_OPEN_FOR_BACKUP_INTENT
2307                      | ((removepc ?: dstpc)->is_rep_symlink ()
2308                         ? FILE_OPEN_REPARSE_POINT : 0))))
2309     {
2310       FILE_INTERNAL_INFORMATION ofii, nfii;
2311
2312       if (NT_SUCCESS (NtQueryInformationFile (fh, &io, &ofii, sizeof ofii,
2313                                               FileInternalInformation))
2314           && NT_SUCCESS (NtQueryInformationFile (nfh, &io, &nfii, sizeof nfii,
2315                                                  FileInternalInformation))
2316           && ofii.FileId.QuadPart == nfii.FileId.QuadPart)
2317         {
2318           debug_printf ("%s and %s are the same file", oldpath, newpath);
2319           NtClose (nfh);
2320           res = 0;
2321           goto out;
2322         }
2323       NtClose (nfh);
2324     }
2325   size = sizeof (FILE_RENAME_INFORMATION)
2326          + dstpc->get_nt_native_path ()->Length;
2327   if (size > NT_MAX_PATH * sizeof (WCHAR)) /* Hopefully very seldom. */
2328     pfri = (PFILE_RENAME_INFORMATION) alloca (size);
2329   else
2330     pfri = (PFILE_RENAME_INFORMATION) tp.w_get ();
2331   pfri->ReplaceIfExists = TRUE;
2332   pfri->RootDirectory = NULL;
2333   pfri->FileNameLength = dstpc->get_nt_native_path ()->Length;
2334   memcpy (&pfri->FileName,  dstpc->get_nt_native_path ()->Buffer,
2335           pfri->FileNameLength);
2336   status = NtSetInformationFile (fh, &io, pfri, size, FileRenameInformation);
2337   /* This happens if the access rights don't allow deleting the destination.
2338      Even if the handle to the original file is opened with BACKUP
2339      and/or RECOVERY, these flags don't apply to the destination of the
2340      rename operation.  So, a privileged user can't rename a file to an
2341      existing file, if the permissions of the existing file aren't right.
2342      Like directories, we have to handle this separately by removing the
2343      destination before renaming. */
2344   if (status == STATUS_ACCESS_DENIED && dstpc->exists () && !dstpc->isdir ())
2345     {
2346       if (wincap.has_transactions ()
2347           && (dstpc->fs_flags () & FILE_SUPPORTS_TRANSACTIONS)
2348           && !trans)
2349         {
2350           start_transaction (old_trans, trans);
2351           /* As mentioned earlier, opening the file must be part of the
2352              transaction.  Therefore we have to reopen the file here if the
2353              transaction hasn't been started already.  Unfortunately we can't
2354              use the NT "reopen file from existing handle" feature.  In that
2355              case NtOpenFile returns STATUS_TRANSACTIONAL_CONFLICT.  We *have*
2356              to close the handle to the file first, *then* we can re-open it.
2357              Fortunately nothing has happened yet, so the atomicity of the
2358              rename functionality is not spoiled. */
2359           NtClose (fh);
2360           status = NtOpenFile (&fh, DELETE,
2361                                oldpc.get_object_attr (attr, sec_none_nih),
2362                                &io, FILE_SHARE_VALID_FLAGS,
2363                                FILE_OPEN_FOR_BACKUP_INTENT
2364                                | (oldpc.is_rep_symlink ()
2365                                   ? FILE_OPEN_REPARSE_POINT : 0));
2366           if (!NT_SUCCESS (status))
2367             {
2368               __seterrno_from_nt_status (status);
2369               goto out;
2370             }
2371         }
2372       if (NT_SUCCESS (status = unlink_nt (*dstpc)))
2373         status = NtSetInformationFile (fh, &io, pfri, size,
2374                                        FileRenameInformation);
2375     }
2376   if (NT_SUCCESS (status))
2377     {
2378       if (removepc)
2379         unlink_nt (*removepc);
2380       res = 0;
2381     }
2382   else
2383     __seterrno_from_nt_status (status);
2384
2385 out:
2386   if (fh)
2387     NtClose (fh);
2388   if (wincap.has_transactions () && trans)
2389     stop_transaction (status, old_trans, trans);
2390   syscall_printf ("%R = rename(%s, %s)", res, oldpath, newpath);
2391   return res;
2392 }
2393
2394 extern "C" int
2395 system (const char *cmdstring)
2396 {
2397   pthread_testcancel ();
2398
2399   myfault efault;
2400   if (efault.faulted (EFAULT))
2401     return -1;
2402
2403   int res;
2404   const char* command[4];
2405
2406   if (cmdstring == NULL)
2407     return 1;
2408
2409   command[0] = "sh";
2410   command[1] = "-c";
2411   command[2] = cmdstring;
2412   command[3] = (const char *) NULL;
2413
2414   if ((res = spawnvp (_P_SYSTEM, "/bin/sh", command)) == -1)
2415     {
2416       // when exec fails, return value should be as if shell
2417       // executed exit (127)
2418       res = 127;
2419     }
2420
2421   return res;
2422 }
2423
2424 extern "C" int
2425 setdtablesize (int size)
2426 {
2427   if (size <= (int)cygheap->fdtab.size || cygheap->fdtab.extend (size - cygheap->fdtab.size))
2428     return 0;
2429
2430   return -1;
2431 }
2432
2433 extern "C" int
2434 getdtablesize ()
2435 {
2436   return cygheap->fdtab.size > OPEN_MAX ? cygheap->fdtab.size : OPEN_MAX;
2437 }
2438
2439 extern "C" int
2440 getpagesize ()
2441 {
2442   return (size_t) wincap.allocation_granularity ();
2443 }
2444
2445 size_t
2446 getsystempagesize ()
2447 {
2448   return (size_t) wincap.page_size ();
2449 }
2450
2451 /* FIXME: not all values are correct... */
2452 extern "C" long int
2453 fpathconf (int fd, int v)
2454 {
2455   cygheap_fdget cfd (fd);
2456   if (cfd < 0)
2457     return -1;
2458   return cfd->fpathconf (v);
2459 }
2460
2461 extern "C" long int
2462 pathconf (const char *file, int v)
2463 {
2464   fhandler_base *fh;
2465   long ret = -1;
2466
2467   myfault efault;
2468   if (efault.faulted (EFAULT))
2469     return -1;
2470
2471   if (!*file)
2472     {
2473       set_errno (ENOENT);
2474       return -1;
2475     }
2476   if (!(fh = build_fh_name (file, PC_SYM_FOLLOW, stat_suffixes)))
2477     return -1;
2478   if (!fh->exists ())
2479     set_errno (ENOENT);
2480   else
2481     ret = fh->fpathconf (v);
2482   delete fh;
2483   return ret;
2484 }
2485
2486 extern "C" int
2487 ttyname_r (int fd, char *buf, size_t buflen)
2488 {
2489   int ret = 0;
2490   myfault efault;
2491   if (efault.faulted ())
2492     ret = EFAULT;
2493   else
2494     {
2495       cygheap_fdget cfd (fd, true);
2496       if (cfd < 0)
2497         ret = EBADF;
2498       else if (!cfd->is_tty ())
2499         ret = ENOTTY;
2500       else if (buflen < strlen (cfd->ttyname ()) + 1)
2501         ret = ERANGE;
2502       else
2503         strcpy (buf, cfd->ttyname ());
2504     }
2505   debug_printf ("returning %d tty: %s", ret, ret ? "NULL" : buf);
2506   return ret;
2507 }
2508
2509 extern "C" char *
2510 ttyname (int fd)
2511 {
2512   static char name[TTY_NAME_MAX];
2513   int ret = ttyname_r (fd, name, TTY_NAME_MAX);
2514   if (ret)
2515     {
2516       set_errno (ret);
2517       return NULL;
2518     }
2519   return name;
2520 }
2521
2522 extern "C" char *
2523 ctermid (char *str)
2524 {
2525   if (str == NULL)
2526     str = _my_tls.locals.ttybuf;
2527   if (myself->ctty < 0)
2528     strcpy (str, "no tty");
2529   else
2530     {
2531       device d;
2532       d.parse (myself->ctty);
2533       strcpy (str, d.name);
2534     }
2535   return str;
2536 }
2537
2538 /* Tells stdio if it should do the cr/lf conversion for this file */
2539 extern "C" int
2540 _cygwin_istext_for_stdio (int fd)
2541 {
2542   if (CYGWIN_VERSION_OLD_STDIO_CRLF_HANDLING)
2543     {
2544       syscall_printf ("fd %d: old API", fd);
2545       return 0; /* we do it for old apps, due to getc/putc macros */
2546     }
2547
2548   cygheap_fdget cfd (fd, false, false);
2549   if (cfd < 0)
2550     {
2551       syscall_printf ("fd %d: not open", fd);
2552       return 0;
2553     }
2554
2555 #if 0
2556   if (cfd->get_device () != FH_FS)
2557     {
2558       syscall_printf ("fd not disk file.  Defaulting to binary.");
2559       return 0;
2560     }
2561 #endif
2562
2563   if (cfd->wbinary () || cfd->rbinary ())
2564     {
2565       syscall_printf ("fd %d: opened as binary", fd);
2566       return 0;
2567     }
2568
2569   syscall_printf ("fd %d: defaulting to text", fd);
2570   return 1;
2571 }
2572
2573 /* internal newlib function */
2574 extern "C" int _fwalk (struct _reent *ptr, int (*function) (FILE *));
2575
2576 static int
2577 setmode_helper (FILE *f)
2578 {
2579   if (fileno (f) != _my_tls.locals.setmode_file)
2580     {
2581       syscall_printf ("improbable, but %d != %d", fileno (f), _my_tls.locals.setmode_file);
2582       return 0;
2583     }
2584   syscall_printf ("file was %s now %s", f->_flags & __SCLE ? "text" : "binary",
2585                   _my_tls.locals.setmode_mode & O_TEXT ? "text" : "binary");
2586   if (_my_tls.locals.setmode_mode & O_TEXT)
2587     f->_flags |= __SCLE;
2588   else
2589     f->_flags &= ~__SCLE;
2590   return 0;
2591 }
2592
2593 extern "C" int
2594 getmode (int fd)
2595 {
2596   cygheap_fdget cfd (fd);
2597   if (cfd < 0)
2598     return -1;
2599
2600   return cfd->get_flags () & (O_BINARY | O_TEXT);
2601 }
2602
2603 /* Set a file descriptor into text or binary mode, returning the
2604    previous mode.  */
2605
2606 extern "C" int
2607 setmode (int fd, int mode)
2608 {
2609   cygheap_fdget cfd (fd);
2610   if (cfd < 0)
2611     return -1;
2612   if (mode != O_BINARY  && mode != O_TEXT && mode != 0)
2613     {
2614       set_errno (EINVAL);
2615       return -1;
2616     }
2617
2618   /* Note that we have no way to indicate the case that writes are
2619      binary but not reads, or vice-versa.  These cases can arise when
2620      using the tty or console interface.  People using those
2621      interfaces should not use setmode.  */
2622
2623   int res;
2624   if (cfd->wbinary () && cfd->rbinary ())
2625     res = O_BINARY;
2626   else if (cfd->wbinset () && cfd->rbinset ())
2627     res = O_TEXT;       /* Specifically set O_TEXT */
2628   else
2629     res = 0;
2630
2631   if (!mode)
2632     cfd->reset_to_open_binmode ();
2633   else
2634     cfd->set_flags ((cfd->get_flags () & ~(O_TEXT | O_BINARY)) | mode);
2635
2636   syscall_printf ("(%d<%S>, %p) returning %s", fd,
2637                   cfd->pc.get_nt_native_path (), mode,
2638                   res & O_TEXT ? "text" : "binary");
2639   return res;
2640 }
2641
2642 extern "C" int
2643 cygwin_setmode (int fd, int mode)
2644 {
2645   int res = setmode (fd, mode);
2646   if (res != -1)
2647     {
2648       _my_tls.locals.setmode_file = fd;
2649       if (_cygwin_istext_for_stdio (fd))
2650         _my_tls.locals.setmode_mode = O_TEXT;
2651       else
2652         _my_tls.locals.setmode_mode = O_BINARY;
2653       _fwalk (_GLOBAL_REENT, setmode_helper);
2654     }
2655   return res;
2656 }
2657
2658 extern "C" int
2659 posix_fadvise (int fd, _off64_t offset, _off64_t len, int advice)
2660 {
2661   int res = -1;
2662   cygheap_fdget cfd (fd);
2663   if (cfd >= 0)
2664     res = cfd->fadvise (offset, len, advice);
2665   else
2666     set_errno (EBADF);
2667   syscall_printf ("%R = posix_fadvice(%d, %D, %D, %d)",
2668                   res, fd, offset, len, advice);
2669   return res;
2670 }
2671
2672 extern "C" int
2673 posix_fallocate (int fd, _off64_t offset, _off64_t len)
2674 {
2675   int res = -1;
2676   if (offset < 0 || len == 0)
2677     set_errno (EINVAL);
2678   else
2679     {
2680       cygheap_fdget cfd (fd);
2681       if (cfd >= 0)
2682         res = cfd->ftruncate (offset + len, false);
2683       else
2684         set_errno (EBADF);
2685     }
2686   syscall_printf ("%R = posix_fallocate(%d, %D, %D)", res, fd, offset, len);
2687   return res;
2688 }
2689
2690 extern "C" int
2691 ftruncate64 (int fd, _off64_t length)
2692 {
2693   int res = -1;
2694   cygheap_fdget cfd (fd);
2695   if (cfd >= 0)
2696     res = cfd->ftruncate (length, true);
2697   else
2698     set_errno (EBADF);
2699   syscall_printf ("%R = ftruncate(%d, %D)", res, fd, length);
2700   return res;
2701 }
2702
2703 /* ftruncate: P96 5.6.7.1 */
2704 extern "C" int
2705 ftruncate (int fd, _off_t length)
2706 {
2707   return ftruncate64 (fd, (_off64_t)length);
2708 }
2709
2710 /* truncate: Provided by SVR4 and 4.3+BSD.  Not part of POSIX.1 or XPG3 */
2711 extern "C" int
2712 truncate64 (const char *pathname, _off64_t length)
2713 {
2714   int fd;
2715   int res = -1;
2716
2717   fd = open (pathname, O_RDWR);
2718
2719   if (fd != -1)
2720     {
2721       res = ftruncate64 (fd, length);
2722       close (fd);
2723     }
2724   syscall_printf ("%R = truncate(%s, %D)", res, pathname, length);
2725
2726   return res;
2727 }
2728
2729 /* truncate: Provided by SVR4 and 4.3+BSD.  Not part of POSIX.1 or XPG3 */
2730 extern "C" int
2731 truncate (const char *pathname, _off_t length)
2732 {
2733   return truncate64 (pathname, (_off64_t)length);
2734 }
2735
2736 extern "C" long
2737 get_osfhandle (int fd)
2738 {
2739   long res;
2740
2741   cygheap_fdget cfd (fd);
2742   if (cfd >= 0)
2743     res = (long) cfd->get_handle ();
2744   else
2745     res = -1;
2746
2747   syscall_printf ("%R = get_osfhandle(%d)", res, fd);
2748   return res;
2749 }
2750
2751 extern "C" int
2752 fstatvfs (int fd, struct statvfs *sfs)
2753 {
2754   myfault efault;
2755   if (efault.faulted (EFAULT))
2756     return -1;
2757
2758   cygheap_fdget cfd (fd);
2759   if (cfd < 0)
2760     return -1;
2761   return cfd->fstatvfs (sfs);
2762 }
2763
2764 extern "C" int
2765 statvfs (const char *name, struct statvfs *sfs)
2766 {
2767   int res = -1;
2768   fhandler_base *fh = NULL;
2769
2770   myfault efault;
2771   if (efault.faulted (EFAULT))
2772     goto error;
2773
2774   if (!(fh = build_fh_name (name, PC_SYM_FOLLOW, stat_suffixes)))
2775     goto error;
2776
2777   if (fh->error ())
2778     {
2779       debug_printf ("got %d error from build_fh_name", fh->error ());
2780       set_errno (fh->error ());
2781     }
2782   else if (fh->exists ())
2783     {
2784       debug_printf ("(%s, %p), file_attributes %d", name, sfs, (DWORD) *fh);
2785       res = fh->fstatvfs (sfs);
2786     }
2787   else
2788     set_errno (ENOENT);
2789
2790   delete fh;
2791  error:
2792   MALLOC_CHECK;
2793   syscall_printf ("%R = statvfs(%s,%p)", res, name, sfs);
2794   return res;
2795 }
2796
2797 extern "C" int
2798 fstatfs (int fd, struct statfs *sfs)
2799 {
2800   struct statvfs vfs;
2801   int ret = fstatvfs (fd, &vfs);
2802   if (!ret)
2803     {
2804       sfs->f_type = vfs.f_flag;
2805       sfs->f_bsize = vfs.f_bsize;
2806       sfs->f_blocks = vfs.f_blocks;
2807       sfs->f_bavail = vfs.f_bavail;
2808       sfs->f_bfree = vfs.f_bfree;
2809       sfs->f_files = -1;
2810       sfs->f_ffree = -1;
2811       sfs->f_fsid = vfs.f_fsid;
2812       sfs->f_namelen = vfs.f_namemax;
2813     }
2814   return ret;
2815 }
2816
2817 extern "C" int
2818 statfs (const char *fname, struct statfs *sfs)
2819 {
2820   struct statvfs vfs;
2821   int ret = statvfs (fname, &vfs);
2822   if (!ret)
2823     {
2824       sfs->f_type = vfs.f_flag;
2825       sfs->f_bsize = vfs.f_bsize;
2826       sfs->f_blocks = vfs.f_blocks;
2827       sfs->f_bavail = vfs.f_bavail;
2828       sfs->f_bfree = vfs.f_bfree;
2829       sfs->f_files = -1;
2830       sfs->f_ffree = -1;
2831       sfs->f_fsid = vfs.f_fsid;
2832       sfs->f_namelen = vfs.f_namemax;
2833     }
2834   return ret;
2835 }
2836
2837 /* setpgid: POSIX 4.3.3.1 */
2838 extern "C" int
2839 setpgid (pid_t pid, pid_t pgid)
2840 {
2841   int res = -1;
2842   if (pid == 0)
2843     pid = getpid ();
2844   if (pgid == 0)
2845     pgid = pid;
2846
2847   if (pgid < 0)
2848     set_errno (EINVAL);
2849   else
2850     {
2851       pinfo p (pid, PID_MAP_RW);
2852       if (!p)
2853         set_errno (ESRCH);
2854       else if (p->pgid == pgid)
2855         res = 0;
2856       /* A process may only change the process group of itself and its children */
2857       else if (p != myself && p->ppid != myself->pid)
2858         set_errno (EPERM);
2859       else
2860         {
2861           p->pgid = pgid;
2862           if (p->pid != p->pgid)
2863             p->set_has_pgid_children (0);
2864           res = 0;
2865         }
2866     }
2867
2868   syscall_printf ("pid %d, pgid %d, res %d", pid, pgid, res);
2869   return res;
2870 }
2871
2872 extern "C" pid_t
2873 getpgid (pid_t pid)
2874 {
2875   if (pid == 0)
2876     pid = getpid ();
2877
2878   pinfo p (pid);
2879   if (p == 0)
2880     {
2881       set_errno (ESRCH);
2882       return -1;
2883     }
2884   return p->pgid;
2885 }
2886
2887 extern "C" int
2888 setpgrp (void)
2889 {
2890   return setpgid (0, 0);
2891 }
2892
2893 extern "C" pid_t
2894 getpgrp (void)
2895 {
2896   return getpgid (0);
2897 }
2898
2899 extern "C" char *
2900 ptsname (int fd)
2901 {
2902   static char buf[TTY_NAME_MAX];
2903   return ptsname_r (fd, buf, sizeof (buf)) == 0 ? buf : NULL;
2904 }
2905
2906 extern "C" int
2907 ptsname_r (int fd, char *buf, size_t buflen)
2908 {
2909   if (!buf)
2910     {
2911       set_errno (EINVAL);
2912       return EINVAL;
2913     }
2914
2915   cygheap_fdget cfd (fd);
2916   if (cfd < 0)
2917     return 0;
2918   return cfd->ptsname_r (buf, buflen);
2919 }
2920
2921 static int __stdcall
2922 mknod_worker (const char *path, mode_t type, mode_t mode, _major_t major,
2923               _minor_t minor)
2924 {
2925   char buf[sizeof (":\\00000000:00000000:00000000") + PATH_MAX];
2926   sprintf (buf, ":\\%x:%x:%x", major, minor,
2927            type | (mode & (S_IRWXU | S_IRWXG | S_IRWXO)));
2928   return symlink_worker (buf, path, true, true);
2929 }
2930
2931 extern "C" int
2932 mknod32 (const char *path, mode_t mode, __dev32_t dev)
2933 {
2934   myfault efault;
2935   if (efault.faulted (EFAULT))
2936     return -1;
2937   if (!*path)
2938     {
2939       set_errno (ENOENT);
2940       return -1;
2941     }
2942
2943   if (strlen (path) >= PATH_MAX)
2944     return -1;
2945
2946   path_conv w32path (path, PC_SYM_NOFOLLOW);
2947   if (w32path.exists ())
2948     {
2949       set_errno (EEXIST);
2950       return -1;
2951     }
2952
2953   mode_t type = mode & S_IFMT;
2954   _major_t major = _major (dev);
2955   _minor_t minor = _minor (dev);
2956   switch (type)
2957     {
2958     case S_IFCHR:
2959     case S_IFBLK:
2960       break;
2961
2962     case S_IFIFO:
2963       major = _major (FH_FIFO);
2964       minor = _minor (FH_FIFO);
2965       break;
2966
2967     case 0:
2968     case S_IFREG:
2969       {
2970         int fd = open (path, O_CREAT, mode);
2971         if (fd < 0)
2972           return -1;
2973         close (fd);
2974         return 0;
2975       }
2976
2977     default:
2978       set_errno (EINVAL);
2979       return -1;
2980     }
2981
2982   return mknod_worker (w32path.get_win32 (), type, mode, major, minor);
2983 }
2984
2985 extern "C" int
2986 mknod (const char *_path, mode_t mode, __dev16_t dev)
2987 {
2988   return mknod32 (_path, mode, (__dev32_t) dev);
2989 }
2990
2991 extern "C" int
2992 mkfifo (const char *path, mode_t mode)
2993 {
2994   return mknod32 (path, (mode & ~S_IFMT) | S_IFIFO, 0);
2995 }
2996
2997 /* seteuid: standards? */
2998 extern "C" int
2999 seteuid32 (__uid32_t uid)
3000 {
3001   debug_printf ("uid: %u myself->uid: %u myself->gid: %u",
3002                 uid, myself->uid, myself->gid);
3003
3004   /* Same uid as we're just running under is usually a no-op.
3005
3006      Except we have an external token which is a restricted token.  Or,
3007      the external token is NULL, but the current impersonation token is
3008      a restricted token.  This allows to restrict user rights temporarily
3009      like this:
3010
3011        cygwin_internal(CW_SET_EXTERNAL_TOKEN, restricted_token,
3012                        CW_TOKEN_RESTRICTED);
3013        setuid (getuid ());
3014        [...do stuff with restricted rights...]
3015        cygwin_internal(CW_SET_EXTERNAL_TOKEN, INVALID_HANDLE_VALUE,
3016                        CW_TOKEN_RESTRICTED);
3017        setuid (getuid ());
3018
3019     Note that using the current uid is a requirement!  Starting with Windows
3020     Vista, we have restricted tokens galore (UAC), so this is really just
3021     a special case to restict your own processes to lesser rights. */
3022   bool request_restricted_uid_switch = (uid == myself->uid
3023       && cygheap->user.ext_token_is_restricted);
3024   if (uid == myself->uid && !cygheap->user.groups.ischanged
3025       && !request_restricted_uid_switch)
3026     {
3027       debug_printf ("Nothing happens");
3028       return 0;
3029     }
3030
3031   cygsid usersid;
3032   user_groups &groups = cygheap->user.groups;
3033   HANDLE new_token = INVALID_HANDLE_VALUE;
3034   struct passwd * pw_new;
3035   bool token_is_internal, issamesid = false;
3036
3037   pw_new = internal_getpwuid (uid);
3038   if (!usersid.getfrompw (pw_new))
3039     {
3040       set_errno (EINVAL);
3041       return -1;
3042     }
3043
3044   cygheap->user.deimpersonate ();
3045
3046   /* Verify if the process token is suitable. */
3047   /* First of all, skip all checks if a switch to a restricted token has been
3048      requested, or if trying to switch back from it. */
3049   if (request_restricted_uid_switch)
3050     {
3051       if (cygheap->user.external_token != NO_IMPERSONATION)
3052         {
3053           debug_printf ("Switch to restricted token");
3054           new_token = cygheap->user.external_token;
3055         }
3056       else
3057         {
3058           debug_printf ("Switch back from restricted token");
3059           new_token = hProcToken;
3060           cygheap->user.ext_token_is_restricted = false;
3061         }
3062     }
3063   /* TODO, CV 2008-11-25: The check against saved_sid is a kludge and a
3064      shortcut.  We must check if it's really feasible in the long run.
3065      The reason to add this shortcut is this:  sshd switches back to the
3066      privileged user running sshd at least twice in the process of
3067      authentication.  It calls seteuid first, then setegid.  Due to this
3068      order, the setgroups group list is still active when calling seteuid
3069      and verify_token treats the original token of the privileged user as
3070      insufficient.  This in turn results in creating a new user token for
3071      the privileged user instead of using the orignal token.  This can have
3072      unfortunate side effects.  The created token has different group
3073      memberships, different user rights, and misses possible network
3074      credentials.
3075      Therefore we try this shortcut now.  When switching back to the
3076      privileged user, we probably always want a correct (aka original)
3077      user token for this privileged user, not only in sshd. */
3078   else if ((uid == cygheap->user.saved_uid
3079            && usersid == cygheap->user.saved_sid ())
3080            || verify_token (hProcToken, usersid, groups))
3081     new_token = hProcToken;
3082   /* Verify if the external token is suitable */
3083   else if (cygheap->user.external_token != NO_IMPERSONATION
3084            && verify_token (cygheap->user.external_token, usersid, groups))
3085     new_token = cygheap->user.external_token;
3086   /* Verify if the current token (internal or former external) is suitable */
3087   else if (cygheap->user.curr_primary_token != NO_IMPERSONATION
3088            && cygheap->user.curr_primary_token != cygheap->user.external_token
3089            && verify_token (cygheap->user.curr_primary_token, usersid, groups,
3090                             &token_is_internal))
3091     new_token = cygheap->user.curr_primary_token;
3092   /* Verify if the internal token is suitable */
3093   else if (cygheap->user.internal_token != NO_IMPERSONATION
3094            && cygheap->user.internal_token != cygheap->user.curr_primary_token
3095            && verify_token (cygheap->user.internal_token, usersid, groups,
3096                             &token_is_internal))
3097     new_token = cygheap->user.internal_token;
3098
3099   debug_printf ("Found token %d", new_token);
3100
3101   /* If no impersonation token is available, try to authenticate using
3102      LSA private data stored password, LSA authentication using our own
3103      LSA module, or, as last chance, NtCreateToken. */
3104   if (new_token == INVALID_HANDLE_VALUE)
3105     {
3106       new_token = lsaprivkeyauth (pw_new);
3107       if (new_token)
3108         {
3109           /* We have to verify this token since settings in /etc/group
3110              might render it unusable im terms of group membership. */
3111           if (!verify_token (new_token, usersid, groups))
3112             {
3113               CloseHandle (new_token);
3114               new_token = NULL;
3115             }
3116         }
3117       if (!new_token)
3118         {
3119           debug_printf ("lsaprivkeyauth failed, try lsaauth.");
3120           if (!(new_token = lsaauth (usersid, groups, pw_new)))
3121             {
3122               debug_printf ("lsaauth failed, try create_token.");
3123               new_token = create_token (usersid, groups, pw_new);
3124               if (new_token == INVALID_HANDLE_VALUE)
3125                 {
3126                   debug_printf ("create_token failed, bail out of here");
3127                   cygheap->user.reimpersonate ();
3128                   return -1;
3129                 }
3130             }
3131         }
3132
3133       /* Keep at most one internal token */
3134       if (cygheap->user.internal_token != NO_IMPERSONATION)
3135         CloseHandle (cygheap->user.internal_token);
3136       cygheap->user.internal_token = new_token;
3137     }
3138
3139   if (new_token != hProcToken)
3140     {
3141       NTSTATUS status;
3142
3143       if (!request_restricted_uid_switch)
3144         {
3145           /* Avoid having HKCU use default user */
3146           WCHAR name[128];
3147           load_registry_hive (usersid.string (name));
3148         }
3149
3150       /* Try setting owner to same value as user. */
3151       status = NtSetInformationToken (new_token, TokenOwner,
3152                                       &usersid, sizeof usersid);
3153       if (!NT_SUCCESS (status))
3154         debug_printf ("NtSetInformationToken (user.token, TokenOwner), %p",
3155                       status);
3156       /* Try setting primary group in token to current group */
3157       status = NtSetInformationToken (new_token, TokenPrimaryGroup,
3158                                       &groups.pgsid, sizeof (cygsid));
3159       if (!NT_SUCCESS (status))
3160         debug_printf ("NtSetInformationToken (user.token, TokenPrimaryGroup),"
3161                       "%p", status);
3162       /* Try setting default DACL */
3163       PACL dacl_buf = (PACL) alloca (MAX_DACL_LEN (5));
3164       if (sec_acl (dacl_buf, true, true, usersid))
3165         {
3166           TOKEN_DEFAULT_DACL tdacl = { dacl_buf };
3167           status = NtSetInformationToken (new_token, TokenDefaultDacl,
3168                                           &tdacl, sizeof (tdacl));
3169           if (!NT_SUCCESS (status))
3170             debug_printf ("NtSetInformationToken (TokenDefaultDacl), %p",
3171                           status);
3172         }
3173     }
3174
3175   issamesid = (usersid == cygheap->user.sid ());
3176   cygheap->user.set_sid (usersid);
3177   cygheap->user.curr_primary_token = new_token == hProcToken ? NO_IMPERSONATION
3178                                                         : new_token;
3179   cygheap->user.curr_token_is_restricted = false;
3180   cygheap->user.setuid_to_restricted = false;
3181   if (cygheap->user.curr_imp_token != NO_IMPERSONATION)
3182     {
3183       CloseHandle (cygheap->user.curr_imp_token);
3184       cygheap->user.curr_imp_token = NO_IMPERSONATION;
3185     }
3186   if (cygheap->user.curr_primary_token != NO_IMPERSONATION)
3187     {
3188       /* HANDLE_FLAG_INHERIT may be missing in external token.  */
3189       if (!SetHandleInformation (cygheap->user.curr_primary_token,
3190                                  HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)
3191           || !DuplicateTokenEx (cygheap->user.curr_primary_token,
3192                                 MAXIMUM_ALLOWED, &sec_none,
3193                                 SecurityImpersonation, TokenImpersonation,
3194                                 &cygheap->user.curr_imp_token))
3195         {
3196           __seterrno ();
3197           cygheap->user.curr_primary_token = NO_IMPERSONATION;
3198           return -1;
3199         }
3200       cygheap->user.curr_token_is_restricted = request_restricted_uid_switch;
3201       set_cygwin_privileges (cygheap->user.curr_primary_token);
3202       set_cygwin_privileges (cygheap->user.curr_imp_token);
3203     }
3204   if (!cygheap->user.reimpersonate ())
3205     {
3206       __seterrno ();
3207       return -1;
3208     }
3209
3210   cygheap->user.set_name (pw_new->pw_name);
3211   myself->uid = uid;
3212   groups.ischanged = FALSE;
3213   if (!issamesid)
3214     /* Recreate and fill out the user shared region for a new user. */
3215     user_info::create (true);
3216   return 0;
3217 }
3218
3219 extern "C" int
3220 seteuid (__uid16_t uid)
3221 {
3222   return seteuid32 (uid16touid32 (uid));
3223 }
3224
3225 /* setuid: POSIX 4.2.2.1 */
3226 extern "C" int
3227 setuid32 (__uid32_t uid)
3228 {
3229   int ret = seteuid32 (uid);
3230   if (!ret)
3231     {
3232       cygheap->user.real_uid = myself->uid;
3233       /* If restricted token, forget original privileges on exec ().  */
3234       cygheap->user.setuid_to_restricted = cygheap->user.curr_token_is_restricted;
3235     }
3236   debug_printf ("real: %d, effective: %d", cygheap->user.real_uid, myself->uid);
3237   return ret;
3238 }
3239
3240 extern "C" int
3241 setuid (__uid16_t uid)
3242 {
3243   return setuid32 (uid16touid32 (uid));
3244 }
3245
3246 extern "C" int
3247 setreuid32 (__uid32_t ruid, __uid32_t euid)
3248 {
3249   int ret = 0;
3250   bool tried = false;
3251   __uid32_t old_euid = myself->uid;
3252
3253   if (ruid != ILLEGAL_UID && cygheap->user.real_uid != ruid && euid != ruid)
3254     tried = !(ret = seteuid32 (ruid));
3255   if (!ret && euid != ILLEGAL_UID)
3256     ret = seteuid32 (euid);
3257   if (tried && (ret || euid == ILLEGAL_UID) && seteuid32 (old_euid))
3258     system_printf ("Cannot restore original euid %u", old_euid);
3259   if (!ret && ruid != ILLEGAL_UID)
3260     cygheap->user.real_uid = ruid;
3261   debug_printf ("real: %u, effective: %u", cygheap->user.real_uid, myself->uid);
3262   return ret;
3263 }
3264
3265 extern "C" int
3266 setreuid (__uid16_t ruid, __uid16_t euid)
3267 {
3268   return setreuid32 (uid16touid32 (ruid), uid16touid32 (euid));
3269 }
3270
3271 /* setegid: from System V.  */
3272 extern "C" int
3273 setegid32 (__gid32_t gid)
3274 {
3275   debug_printf ("new egid: %u current: %u", gid, myself->gid);
3276
3277   if (gid == myself->gid)
3278     {
3279       myself->gid = gid;
3280       return 0;
3281     }
3282
3283   NTSTATUS status;
3284   user_groups * groups = &cygheap->user.groups;
3285   cygsid gsid;
3286   struct __group32 * gr = internal_getgrgid (gid);
3287
3288   if (!gsid.getfromgr (gr))
3289     {
3290       set_errno (EINVAL);
3291       return -1;
3292     }
3293   myself->gid = gid;
3294
3295   groups->update_pgrp (gsid);
3296   if (cygheap->user.issetuid ())
3297     {
3298       /* If impersonated, update impersonation token... */
3299       status = NtSetInformationToken (cygheap->user.primary_token (),
3300                                       TokenPrimaryGroup, &gsid, sizeof gsid);
3301       if (!NT_SUCCESS (status))
3302         debug_printf ("NtSetInformationToken (primary_token, "
3303                       "TokenPrimaryGroup), %p", status);
3304       status = NtSetInformationToken (cygheap->user.imp_token (),
3305                                       TokenPrimaryGroup, &gsid, sizeof gsid);
3306       if (!NT_SUCCESS (status))
3307         debug_printf ("NtSetInformationToken (token, TokenPrimaryGroup), %p",
3308                       status);
3309     }
3310   cygheap->user.deimpersonate ();
3311   status = NtSetInformationToken (hProcToken, TokenPrimaryGroup,
3312                                   &gsid, sizeof gsid);
3313   if (!NT_SUCCESS (status))
3314     debug_printf ("NtSetInformationToken (hProcToken, TokenPrimaryGroup), %p",
3315                   status);
3316   clear_procimptoken ();
3317   cygheap->user.reimpersonate ();
3318   return 0;
3319 }
3320
3321 extern "C" int
3322 setegid (__gid16_t gid)
3323 {
3324   return setegid32 (gid16togid32 (gid));
3325 }
3326
3327 /* setgid: POSIX 4.2.2.1 */
3328 extern "C" int
3329 setgid32 (__gid32_t gid)
3330 {
3331   int ret = setegid32 (gid);
3332   if (!ret)
3333     cygheap->user.real_gid = myself->gid;
3334   return ret;
3335 }
3336
3337 extern "C" int
3338 setgid (__gid16_t gid)
3339 {
3340   int ret = setegid32 (gid16togid32 (gid));
3341   if (!ret)
3342     cygheap->user.real_gid = myself->gid;
3343   return ret;
3344 }
3345
3346 extern "C" int
3347 setregid32 (__gid32_t rgid, __gid32_t egid)
3348 {
3349   int ret = 0;
3350   bool tried = false;
3351   __gid32_t old_egid = myself->gid;
3352
3353   if (rgid != ILLEGAL_GID && cygheap->user.real_gid != rgid && egid != rgid)
3354     tried = !(ret = setegid32 (rgid));
3355   if (!ret && egid != ILLEGAL_GID)
3356     ret = setegid32 (egid);
3357   if (tried && (ret || egid == ILLEGAL_GID) && setegid32 (old_egid))
3358     system_printf ("Cannot restore original egid %u", old_egid);
3359   if (!ret && rgid != ILLEGAL_GID)
3360     cygheap->user.real_gid = rgid;
3361   debug_printf ("real: %u, effective: %u", cygheap->user.real_gid, myself->gid);
3362   return ret;
3363 }
3364
3365 extern "C" int
3366 setregid (__gid16_t rgid, __gid16_t egid)
3367 {
3368   return setregid32 (gid16togid32 (rgid), gid16togid32 (egid));
3369 }
3370
3371 /* chroot: privileged Unix system call.  */
3372 /* FIXME: Not privileged here. How should this be done? */
3373 extern "C" int
3374 chroot (const char *newroot)
3375 {
3376   path_conv path (newroot, PC_SYM_FOLLOW | PC_POSIX);
3377
3378   int ret = -1;
3379   if (path.error)
3380     set_errno (path.error);
3381   else if (!path.exists ())
3382     set_errno (ENOENT);
3383   else if (!path.isdir ())
3384     set_errno (ENOTDIR);
3385   else if (path.isspecial ())
3386     set_errno (EPERM);
3387   else
3388     {
3389       getwinenv("PATH="); /* Save the native PATH */
3390       cygheap->root.set (path.normalized_path, path.get_win32 (),
3391                          !!path.objcaseinsensitive ());
3392       ret = 0;
3393     }
3394
3395   syscall_printf ("%R = chroot(%s)", ret, newroot ?: "NULL");
3396   return ret;
3397 }
3398
3399 extern "C" int
3400 creat (const char *path, mode_t mode)
3401 {
3402   return open (path, O_WRONLY | O_CREAT | O_TRUNC, mode);
3403 }
3404
3405 extern "C" void
3406 __assertfail ()
3407 {
3408   exit (99);
3409 }
3410
3411 extern "C" int
3412 vhangup ()
3413 {
3414   set_errno (ENOSYS);
3415   return -1;
3416 }
3417
3418 extern "C" int
3419 setpriority (int which, id_t who, int value)
3420 {
3421   DWORD prio = nice_to_winprio (value);
3422   int error = 0;
3423
3424   switch (which)
3425     {
3426     case PRIO_PROCESS:
3427       if (!who)
3428         who = myself->pid;
3429       if ((pid_t) who == myself->pid)
3430         {
3431           if (!SetPriorityClass (GetCurrentProcess (), prio))
3432             {
3433               set_errno (EACCES);
3434               return -1;
3435             }
3436           myself->nice = value;
3437           debug_printf ("Set nice to %d", myself->nice);
3438           return 0;
3439         }
3440       break;
3441     case PRIO_PGRP:
3442       if (!who)
3443         who = myself->pgid;
3444       break;
3445     case PRIO_USER:
3446       if (!who)
3447         who = myself->uid;
3448       break;
3449     default:
3450       set_errno (EINVAL);
3451       return -1;
3452     }
3453   winpids pids ((DWORD) PID_MAP_RW);
3454   for (DWORD i = 0; i < pids.npids; ++i)
3455     {
3456       _pinfo *p = pids[i];
3457       if (p)
3458         {
3459           switch (which)
3460             {
3461             case PRIO_PROCESS:
3462               if ((pid_t) who != p->pid)
3463                 continue;
3464               break;
3465             case PRIO_PGRP:
3466               if ((pid_t) who != p->pgid)
3467                 continue;
3468               break;
3469             case PRIO_USER:
3470                 if ((__uid32_t) who != p->uid)
3471                 continue;
3472               break;
3473             }
3474           HANDLE proc_h = OpenProcess (PROCESS_SET_INFORMATION, FALSE,
3475                                        p->dwProcessId);
3476           if (!proc_h)
3477             error = EPERM;
3478           else
3479             {
3480               if (!SetPriorityClass (proc_h, prio))
3481                 error = EACCES;
3482               else
3483                 p->nice = value;
3484               CloseHandle (proc_h);
3485             }
3486         }
3487     }
3488   pids.reset ();
3489   if (error)
3490     {
3491       set_errno (error);
3492       return -1;
3493     }
3494   return 0;
3495 }
3496
3497 extern "C" int
3498 getpriority (int which, id_t who)
3499 {
3500   int nice = NZERO * 2; /* Illegal value */
3501
3502   switch (which)
3503     {
3504     case PRIO_PROCESS:
3505       if (!who)
3506         who = myself->pid;
3507       if ((pid_t) who == myself->pid)
3508         return myself->nice;
3509       break;
3510     case PRIO_PGRP:
3511       if (!who)
3512         who = myself->pgid;
3513       break;
3514     case PRIO_USER:
3515       if (!who)
3516         who = myself->uid;
3517       break;
3518     default:
3519       set_errno (EINVAL);
3520       return -1;
3521     }
3522   winpids pids ((DWORD) 0);
3523   for (DWORD i = 0; i < pids.npids; ++i)
3524     {
3525       _pinfo *p = pids[i];
3526       if (p)
3527         switch (which)
3528           {
3529           case PRIO_PROCESS:
3530             if ((pid_t) who == p->pid)
3531               {
3532                 nice = p->nice;
3533                 goto out;
3534               }
3535             break;
3536           case PRIO_PGRP:
3537             if ((pid_t) who == p->pgid && p->nice < nice)
3538               nice = p->nice;
3539             break;
3540           case PRIO_USER:
3541             if ((__uid32_t) who == p->uid && p->nice < nice)
3542               nice = p->nice;
3543               break;
3544           }
3545     }
3546 out:
3547   pids.reset ();
3548   if (nice == NZERO * 2)
3549     {
3550       set_errno (ESRCH);
3551       return -1;
3552     }
3553   return nice;
3554 }
3555
3556 extern "C" int
3557 nice (int incr)
3558 {
3559   return setpriority (PRIO_PROCESS, myself->pid, myself->nice + incr);
3560 }
3561
3562 /*
3563  * Find the first bit set in I.
3564  */
3565
3566 extern "C" int
3567 ffs (int i)
3568 {
3569   static const unsigned char table[] =
3570     {
3571       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,
3572       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,
3573       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,
3574       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,
3575       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,
3576       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,
3577       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,
3578       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
3579     };
3580   unsigned long int a;
3581   unsigned long int x = i & -i;
3582
3583   a = x <= 0xffff ? (x <= 0xff ? 0 : 8) : (x <= 0xffffff ?  16 : 24);
3584
3585   return table[x >> a] + a;
3586 }
3587
3588 static void
3589 locked_append (int fd, const void * buf, size_t size)
3590 {
3591   struct __flock64 lock_buffer = {F_WRLCK, SEEK_SET, 0, 0, 0};
3592   int count = 0;
3593
3594   do
3595     if ((lock_buffer.l_start = lseek64 (fd, 0, SEEK_END)) != (_off64_t) -1
3596         && fcntl64 (fd, F_SETLKW, &lock_buffer) != -1)
3597       {
3598         if (lseek64 (fd, 0, SEEK_END) != (_off64_t) -1)
3599           write (fd, buf, size);
3600         lock_buffer.l_type = F_UNLCK;
3601         fcntl64 (fd, F_SETLK, &lock_buffer);
3602         break;
3603       }
3604   while (count++ < 1000
3605          && (errno == EACCES || errno == EAGAIN)
3606          && !usleep (1000));
3607 }
3608
3609 extern "C" void
3610 updwtmp (const char *wtmp_file, const struct utmp *ut)
3611 {
3612   int fd;
3613
3614   if ((fd = open (wtmp_file, O_WRONLY | O_BINARY, 0)) >= 0)
3615     {
3616       locked_append (fd, ut, sizeof *ut);
3617       close (fd);
3618     }
3619 }
3620
3621 static int utmp_fd = -1;
3622 static bool utmp_readonly = false;
3623 static char *utmp_file = (char *) _PATH_UTMP;
3624
3625 static void
3626 internal_setutent (bool force_readwrite)
3627 {
3628   if (force_readwrite && utmp_readonly)
3629     endutent ();
3630   if (utmp_fd < 0)
3631     {
3632       utmp_fd = open (utmp_file, O_RDWR | O_BINARY);
3633       /* If open fails, we assume an unprivileged process (who?).  In this
3634          case we try again for reading only unless the process calls
3635          pututline() (==force_readwrite) in which case opening just fails. */
3636       if (utmp_fd < 0 && !force_readwrite)
3637         {
3638           utmp_fd = open (utmp_file, O_RDONLY | O_BINARY);
3639           if (utmp_fd >= 0)
3640             utmp_readonly = true;
3641         }
3642     }
3643   else
3644     lseek (utmp_fd, 0, SEEK_SET);
3645 }
3646
3647 extern "C" void
3648 setutent ()
3649 {
3650   internal_setutent (false);
3651 }
3652
3653 extern "C" void
3654 endutent ()
3655 {
3656   if (utmp_fd >= 0)
3657     {
3658       close (utmp_fd);
3659       utmp_fd = -1;
3660       utmp_readonly = false;
3661     }
3662 }
3663
3664 extern "C" void
3665 utmpname (const char *file)
3666 {
3667   myfault efault;
3668   if (efault.faulted () || !*file)
3669     {
3670       debug_printf ("Invalid file");
3671       return;
3672     }
3673   endutent ();
3674   utmp_file = strdup (file);
3675   debug_printf ("New UTMP file: %s", utmp_file);
3676 }
3677
3678 EXPORT_ALIAS (utmpname, utmpxname)
3679
3680 /* Note: do not make NO_COPY */
3681 static struct utmp utmp_data_buf[16];
3682 static unsigned utix = 0;
3683 #define nutdbuf (sizeof (utmp_data_buf) / sizeof (utmp_data_buf[0]))
3684 #define utmp_data ({ \
3685   if (utix >= nutdbuf) \
3686     utix = 0; \
3687   utmp_data_buf + utix++; \
3688 })
3689
3690 static struct utmpx *
3691 copy_ut_to_utx (struct utmp *ut, struct utmpx *utx)
3692 {
3693   if (!ut)
3694     return NULL;
3695   memcpy (utx, ut, sizeof *ut);
3696   utx->ut_tv.tv_sec = ut->ut_time;
3697   utx->ut_tv.tv_usec = 0;
3698   return utx;
3699 }
3700
3701 extern "C" struct utmp *
3702 getutent ()
3703 {
3704   if (utmp_fd < 0)
3705     {
3706       internal_setutent (false);
3707       if (utmp_fd < 0)
3708         return NULL;
3709     }
3710
3711   utmp *ut = utmp_data;
3712   if (read (utmp_fd, ut, sizeof *ut) != sizeof *ut)
3713     return NULL;
3714   return ut;
3715 }
3716
3717 extern "C" struct utmp *
3718 getutid (const struct utmp *id)
3719 {
3720   myfault efault;
3721   if (efault.faulted (EFAULT))
3722     return NULL;
3723   if (utmp_fd < 0)
3724     {
3725       internal_setutent (false);
3726       if (utmp_fd < 0)
3727         return NULL;
3728     }
3729
3730   utmp *ut = utmp_data;
3731   while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut)
3732     {
3733       switch (id->ut_type)
3734         {
3735         case RUN_LVL:
3736         case BOOT_TIME:
3737         case OLD_TIME:
3738         case NEW_TIME:
3739           if (id->ut_type == ut->ut_type)
3740             return ut;
3741           break;
3742         case INIT_PROCESS:
3743         case LOGIN_PROCESS:
3744         case USER_PROCESS:
3745         case DEAD_PROCESS:
3746            if (strncmp (id->ut_id, ut->ut_id, UT_IDLEN) == 0)
3747             return ut;
3748           break;
3749         default:
3750           return NULL;
3751         }
3752     }
3753   return NULL;
3754 }
3755
3756 extern "C" struct utmp *
3757 getutline (const struct utmp *line)
3758 {
3759   myfault efault;
3760   if (efault.faulted (EFAULT))
3761     return NULL;
3762   if (utmp_fd < 0)
3763     {
3764       internal_setutent (false);
3765       if (utmp_fd < 0)
3766         return NULL;
3767     }
3768
3769   utmp *ut = utmp_data;
3770   while (read (utmp_fd, ut, sizeof *ut) == sizeof *ut)
3771     if ((ut->ut_type == LOGIN_PROCESS ||
3772          ut->ut_type == USER_PROCESS) &&
3773         !strncmp (ut->ut_line, line->ut_line, sizeof (ut->ut_line)))
3774       return ut;
3775
3776   return NULL;
3777 }
3778
3779 extern "C" struct utmp *
3780 pututline (const struct utmp *ut)
3781 {
3782   myfault efault;
3783   if (efault.faulted (EFAULT))
3784     return NULL;
3785   internal_setutent (true);
3786   if (utmp_fd < 0)
3787     {
3788       debug_printf ("error: utmp_fd %d", utmp_fd);
3789       return NULL;
3790     }
3791   debug_printf ("ut->ut_type %d, ut->ut_pid %d, ut->ut_line '%s', ut->ut_id '%s'\n",
3792                 ut->ut_type, ut->ut_pid, ut->ut_line, ut->ut_id);
3793   debug_printf ("ut->ut_user '%s', ut->ut_host '%s'\n",
3794                 ut->ut_user, ut->ut_host);
3795
3796   struct utmp *u;
3797   if ((u = getutid (ut)))
3798     {
3799       lseek (utmp_fd, -sizeof *ut, SEEK_CUR);
3800       write (utmp_fd, ut, sizeof *ut);
3801     }
3802   else
3803     locked_append (utmp_fd, ut, sizeof *ut);
3804   /* The documentation says to return a pointer to this which implies that
3805      this has to be cast from a const.  That doesn't seem right but the
3806      documentation seems pretty clear on this.  */
3807   return (struct utmp *) ut;
3808 }
3809
3810 extern "C" void
3811 setutxent ()
3812 {
3813   internal_setutent (false);
3814 }
3815
3816 extern "C" void
3817 endutxent ()
3818 {
3819   endutent ();
3820 }
3821
3822 extern "C" struct utmpx *
3823 getutxent ()
3824 {
3825   /* UGH.  Not thread safe. */
3826   static struct utmpx utx;
3827   return copy_ut_to_utx (getutent (), &utx);
3828 }
3829
3830 extern "C" struct utmpx *
3831 getutxid (const struct utmpx *id)
3832 {
3833   /* UGH.  Not thread safe. */
3834   static struct utmpx utx;
3835
3836   myfault efault;
3837   if (efault.faulted (EFAULT))
3838     return NULL;
3839   ((struct utmpx *)id)->ut_time = id->ut_tv.tv_sec;
3840   return copy_ut_to_utx (getutid ((struct utmp *) id), &utx);
3841 }
3842
3843 extern "C" struct utmpx *
3844 getutxline (const struct utmpx *line)
3845 {
3846   /* UGH.  Not thread safe. */
3847   static struct utmpx utx;
3848
3849   myfault efault;
3850   if (efault.faulted (EFAULT))
3851     return NULL;
3852   ((struct utmpx *)line)->ut_time = line->ut_tv.tv_sec;
3853   return copy_ut_to_utx (getutline ((struct utmp *) line), &utx);
3854 }
3855
3856 extern "C" struct utmpx *
3857 pututxline (const struct utmpx *utmpx)
3858 {
3859   /* UGH.  Not thread safe. */
3860   static struct utmpx utx;
3861
3862   myfault efault;
3863   if (efault.faulted (EFAULT))
3864     return NULL;
3865   ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec;
3866   return copy_ut_to_utx (pututline ((struct utmp *) utmpx), &utx);
3867 }
3868
3869 extern "C" void
3870 updwtmpx (const char *wtmpx_file, const struct utmpx *utmpx)
3871 {
3872   ((struct utmpx *)utmpx)->ut_time = utmpx->ut_tv.tv_sec;
3873   updwtmp (wtmpx_file, (const struct utmp *) utmpx);
3874 }
3875
3876 extern "C" long
3877 gethostid (void)
3878 {
3879   unsigned data[13] = {0x92895012,
3880                        0x10293412,
3881                        0x29602018,
3882                        0x81928167,
3883                        0x34601329,
3884                        0x75630198,
3885                        0x89860395,
3886                        0x62897564,
3887                        0x00194362,
3888                        0x20548593,
3889                        0x96839102,
3890                        0x12219854,
3891                        0x00290012};
3892
3893   bool has_cpuid = false;
3894
3895   DWORD opmask = SetThreadAffinityMask (GetCurrentThread (), 1);
3896   if (!opmask)
3897     debug_printf ("SetThreadAffinityMask to 1 failed, %E");
3898
3899   if (!can_set_flag (0x00040000))
3900     debug_printf ("386 processor - no cpuid");
3901   else
3902     {
3903       debug_printf ("486 processor");
3904       if (can_set_flag (0x00200000))
3905         {
3906           debug_printf ("processor supports CPUID instruction");
3907           has_cpuid = true;
3908         }
3909       else
3910         debug_printf ("processor does not support CPUID instruction");
3911     }
3912   if (has_cpuid)
3913     {
3914       unsigned maxf, unused[3];
3915       cpuid (&maxf, &unused[0], &unused[1], &unused[2], 0);
3916       maxf &= 0xffff;
3917       if (maxf >= 1)
3918         {
3919           unsigned features;
3920           cpuid (&data[0], &unused[0], &unused[1], &features, 1);
3921           if (features & (1 << 18))
3922             {
3923               debug_printf ("processor has psn");
3924               if (maxf >= 3)
3925                 {
3926                   cpuid (&unused[0], &unused[1], &data[1], &data[2], 3);
3927                   debug_printf ("Processor PSN: %04x-%04x-%04x-%04x-%04x-%04x",
3928                                 data[0] >> 16, data[0] & 0xffff, data[2] >> 16, data[2] & 0xffff, data[1] >> 16, data[1] & 0xffff);
3929                 }
3930             }
3931           else
3932             debug_printf ("processor does not have psn");
3933         }
3934     }
3935
3936   LARGE_INTEGER u1;
3937   ULONG u2, u3;
3938   union {
3939     UCHAR mac[6];
3940     struct {
3941       ULONG m1;
3942       USHORT m2;
3943     };
3944   } u4;
3945   NTSTATUS status = NtAllocateUuids (&u1, &u2, &u3, u4.mac);
3946   if (NT_SUCCESS (status))
3947     {
3948       data[4] = u4.m1;
3949       data[5] = u4.m2;
3950       // Unfortunately Windows will sometimes pick a virtual Ethernet card
3951       // e.g. VMWare Virtual Ethernet Adaptor
3952       debug_printf ("MAC address of first Ethernet card: "
3953                     "%02x:%02x:%02x:%02x:%02x:%02x",
3954                     u4.mac[0], u4.mac[1], u4.mac[2],
3955                     u4.mac[3], u4.mac[4], u4.mac[5]);
3956     }
3957   else
3958     debug_printf ("no Ethernet card installed");
3959
3960   WCHAR wdata[24];
3961   reg_key key (HKEY_LOCAL_MACHINE, KEY_READ, L"SOFTWARE", L"Microsoft",
3962                L"Windows NT", L"CurrentVersion", NULL);
3963   key.get_string (L"ProductId", wdata, 24, L"00000-000-0000000-00000");
3964   sys_wcstombs ((char *)&data[6], 24, wdata, 24);
3965   debug_printf ("Windows Product ID: %s", (char *)&data[6]);
3966
3967   GetDiskFreeSpaceEx ("C:\\", NULL, (PULARGE_INTEGER) &data[11], NULL);
3968
3969   debug_printf ("hostid entropy: %08x %08x %08x %08x "
3970                                 "%08x %08x %08x %08x "
3971                                 "%08x %08x %08x %08x "
3972                                 "%08x",
3973                                 data[0], data[1],
3974                                 data[2], data[3],
3975                                 data[4], data[5],
3976                                 data[6], data[7],
3977                                 data[8], data[9],
3978                                 data[10], data[11],
3979                                 data[12]);
3980
3981   long hostid = 0x40291372;
3982   // a random hashing algorithm
3983   // dependancy on md5 is probably too costly
3984   for (int i=0;i<13;i++)
3985     hostid ^= ((data[i] << (i << 2)) | (data[i] >> (32 - (i << 2))));
3986
3987   if (opmask && !SetThreadAffinityMask (GetCurrentThread (), opmask))
3988     debug_printf ("SetThreadAffinityMask to %p failed, %E", opmask);
3989
3990   debug_printf ("hostid: %08x", hostid);
3991
3992   return hostid;
3993 }
3994
3995 #define ETC_SHELLS "/etc/shells"
3996 static int shell_index;
3997 static struct __sFILE64 *shell_fp;
3998
3999 extern "C" char *
4000 getusershell ()
4001 {
4002   /* List of default shells if no /etc/shells exists, defined as on Linux.
4003      FIXME: SunOS has a far longer list, containing all shells which
4004      might be shipped with the OS.  Should we do the same for the Cygwin
4005      distro, adding bash, tcsh, ksh, pdksh and zsh?  */
4006   static NO_COPY const char *def_shells[] = {
4007     "/bin/sh",
4008     "/bin/csh",
4009     "/usr/bin/sh",
4010     "/usr/bin/csh",
4011     NULL
4012   };
4013   static char buf[PATH_MAX];
4014   int ch, buf_idx;
4015
4016   if (!shell_fp && !(shell_fp = fopen64 (ETC_SHELLS, "rt")))
4017     {
4018       if (def_shells[shell_index])
4019         return strcpy (buf, def_shells[shell_index++]);
4020       return NULL;
4021     }
4022   /* Skip white space characters. */
4023   while ((ch = getc (shell_fp)) != EOF && isspace (ch))
4024     ;
4025   /* Get each non-whitespace character as part of the shell path as long as
4026      it fits in buf. */
4027   for (buf_idx = 0;
4028        ch != EOF && !isspace (ch) && buf_idx < PATH_MAX;
4029        buf_idx++, ch = getc (shell_fp))
4030     buf[buf_idx] = ch;
4031   /* Skip any trailing non-whitespace character not fitting in buf.  If the
4032      path is longer than PATH_MAX, it's invalid anyway. */
4033   while (ch != EOF && !isspace (ch))
4034     ch = getc (shell_fp);
4035   if (buf_idx)
4036     {
4037       buf[buf_idx] = '\0';
4038       return buf;
4039     }
4040   return NULL;
4041 }
4042
4043 extern "C" void
4044 setusershell ()
4045 {
4046   if (shell_fp)
4047     fseek (shell_fp, 0L, SEEK_SET);
4048   shell_index = 0;
4049 }
4050
4051 extern "C" void
4052 endusershell ()
4053 {
4054   if (shell_fp)
4055     {
4056       fclose (shell_fp);
4057       shell_fp = NULL;
4058     }
4059   shell_index = 0;
4060 }
4061
4062 extern "C" void
4063 flockfile (FILE *file)
4064 {
4065   _flockfile (file);
4066 }
4067
4068 extern "C" int
4069 ftrylockfile (FILE *file)
4070 {
4071   return _ftrylockfile (file);
4072 }
4073
4074 extern "C" void
4075 funlockfile (FILE *file)
4076 {
4077   _funlockfile (file);
4078 }
4079
4080 extern "C" FILE *
4081 popen (const char *command, const char *in_type)
4082 {
4083   const char *type = in_type;
4084   char rw = *type++;
4085
4086   /* Sanity check in_type */
4087   if (*type == 'b' || *type == 't')
4088     type++;
4089   if ((rw != 'r' && rw != 'w') || (*type != '\0'))
4090     {
4091       set_errno (EINVAL);
4092       return NULL;
4093     }
4094
4095   int fds[2];
4096   if (pipe (fds) < 0)
4097     return NULL;
4098
4099   int myix = rw == 'r' ? 0 : 1;
4100
4101   lock_process now;
4102   FILE *fp = fdopen (fds[myix], in_type);
4103   if (fp)
4104     {
4105       /* If fds are in the range of stdin/stdout/stderr, move them
4106          out of the way (possibly temporarily).  Otherwise, spawn_guts
4107          will be confused.  We do this here rather than adding logic to
4108          spawn_guts because spawn_guts is likely to be a more frequently
4109          used routine and having stdin/stdout/stderr closed and reassigned
4110          to pipe handles is an unlikely event. */
4111       int orig_fds[2] = {fds[0], fds[1]};
4112       for (int i = 0; i < 2; i++)
4113         if (fds[i] <= 2)
4114           {
4115             cygheap_fdnew newfd(3);
4116             cygheap->fdtab.move_fd (fds[i], newfd);
4117             fds[i] = newfd;
4118           }
4119
4120       int myfd = fds[myix];     /* myfd - convenience variable for manipulation
4121                                    of the "parent" end of the pipe. */
4122       int stdchild = myix ^ 1;  /* stdchild denotes the index into fd for the
4123                                    handle which will be redirected to
4124                                    stdin/stdout */
4125       int __std[2];
4126       __std[myix] = -1;         /* -1 means don't pass this fd to the child
4127                                    process */
4128       __std[stdchild] = fds[stdchild]; /* Do pass this as the std handle */
4129
4130       const char *argv[4] =
4131         {
4132           "/bin/sh",
4133           "-c",
4134           command,
4135           NULL
4136         };
4137
4138       /* Don't pass our end of the pipe to the child process */
4139       int fd_state = fcntl64 (myfd, F_GETFD, 0);
4140       fcntl64 (myfd, F_SETFD, fd_state | FD_CLOEXEC);
4141
4142       /* Also don't pass the file handle currently associated with stdin/stdout
4143          to the child.  This function may actually fail if the stdchild fd
4144          is closed.  But that's ok. */
4145       int stdchild_state = fcntl64 (stdchild, F_GETFD, 0);
4146       fcntl64 (stdchild, F_SETFD, stdchild_state | FD_CLOEXEC);
4147
4148       /* Start a shell process to run the given command without forking. */
4149       pid_t pid = ch_spawn.worker ("/bin/sh", argv, cur_environ (), _P_NOWAIT,
4150                                    __std[0], __std[1]);
4151
4152       /* Reinstate the close-on-exec state */
4153       fcntl64 (stdchild, F_SETFD, stdchild_state);
4154
4155       /* If pid >= 0 then spawn_guts succeeded.  */
4156       if (pid >= 0)
4157         {
4158           close (fds[stdchild]);        /* Close the child end of the pipe. */
4159           /* Move the fd back to its original slot if it has been moved since
4160              we're always supposed to open the lowest numbered available fd
4161              and, if fds[mix] != orig_fds[myix] then orig_fds[myix] is
4162              presumably lower. */
4163           if (fds[myix] != orig_fds[myix])
4164             cygheap->fdtab.move_fd (fds[myix], myfd = orig_fds[myix]);
4165           fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[myfd];
4166           /* Flag that this handle is associated with popen and then reset
4167              the handle's original close-on-exec state. */
4168           fh->set_popen_pid (pid);
4169           fcntl64 (myfd, F_SETFD, fd_state);
4170           return fp;
4171         }
4172     }
4173
4174   /* If we reach here we've seen an error but the pipe handles are open.
4175      Close them and return NULL. */
4176   int save_errno = get_errno ();
4177   close (fds[0]);
4178   close (fds[1]);
4179   set_errno (save_errno);
4180   return NULL;
4181 }
4182
4183 int
4184 pclose (FILE *fp)
4185 {
4186   fhandler_pipe *fh = (fhandler_pipe *) cygheap->fdtab[fileno(fp)];
4187
4188   if (fh->get_device () != FH_PIPEW && fh->get_device () != FH_PIPER)
4189     {
4190       set_errno (EBADF);
4191       return -1;
4192     }
4193
4194   int pid = fh->get_popen_pid ();
4195   if (!pid)
4196     {
4197       set_errno (ECHILD);
4198       return -1;
4199     }
4200
4201   if (fclose (fp))
4202     return -1;
4203
4204   int status;
4205   while (1)
4206     if (waitpid (pid, &status, 0) == pid)
4207       break;
4208     else if (get_errno () == EINTR)
4209       continue;
4210     else
4211       return -1;
4212
4213   return status;
4214 }
4215
4216 /* Preliminary(?) implementation of the openat family of functions. */
4217
4218 static int
4219 gen_full_path_at (char *path_ret, int dirfd, const char *pathname,
4220                   bool null_pathname_allowed = false)
4221 {
4222   /* Set null_pathname_allowed to true to allow GLIBC compatible behaviour
4223      for NULL pathname.  Only used by futimesat. */
4224   if (!pathname && !null_pathname_allowed)
4225     {
4226       set_errno (EFAULT);
4227       return -1;
4228     }
4229   if (pathname)
4230     {
4231       if (!*pathname)
4232         {
4233           set_errno (ENOENT);
4234           return -1;
4235         }
4236       if (strlen (pathname) >= PATH_MAX)
4237         {
4238           set_errno (ENAMETOOLONG);
4239           return -1;
4240         }
4241     }
4242   if (pathname && isabspath (pathname))
4243     stpcpy (path_ret, pathname);
4244   else
4245     {
4246       char *p;
4247
4248       if (dirfd == AT_FDCWD)
4249         {
4250           cwdstuff::cwd_lock.acquire ();
4251           p = stpcpy (path_ret, cygheap->cwd.get_posix ());
4252           cwdstuff::cwd_lock.release ();
4253         }
4254       else
4255         {
4256           cygheap_fdget cfd (dirfd);
4257           if (cfd < 0)
4258             return -1;
4259           if (!cfd->pc.isdir ())
4260             {
4261               set_errno (ENOTDIR);
4262               return -1;
4263             }
4264           p = stpcpy (path_ret, cfd->get_name ());
4265         }
4266       if (!p)
4267         {
4268           set_errno (ENOTDIR);
4269           return -1;
4270         }
4271       if (pathname)
4272         {
4273           if (p[-1] != '/')
4274             *p++ = '/';
4275           stpcpy (p, pathname);
4276         }
4277     }
4278   return 0;
4279 }
4280
4281 extern "C" int
4282 openat (int dirfd, const char *pathname, int flags, ...)
4283 {
4284   tmp_pathbuf tp;
4285   myfault efault;
4286   if (efault.faulted (EFAULT))
4287     return -1;
4288   char *path = tp.c_get ();
4289   if (gen_full_path_at (path, dirfd, pathname))
4290     return -1;
4291
4292   va_list ap;
4293   mode_t mode;
4294
4295   va_start (ap, flags);
4296   mode = va_arg (ap, mode_t);
4297   va_end (ap);
4298   return open (path, flags, mode);
4299 }
4300
4301 extern "C" int
4302 faccessat (int dirfd, const char *pathname, int mode, int flags)
4303 {
4304   tmp_pathbuf tp;
4305   myfault efault;
4306   if (efault.faulted (EFAULT))
4307     return -1;
4308
4309   int res = -1;
4310   char *path = tp.c_get ();
4311   if (!gen_full_path_at (path, dirfd, pathname))
4312     {
4313       if ((mode & ~(F_OK|R_OK|W_OK|X_OK))
4314           || (flags & ~(AT_SYMLINK_NOFOLLOW|AT_EACCESS)))
4315         set_errno (EINVAL);
4316       else
4317         {
4318           fhandler_base *fh = build_fh_name (path, (flags & AT_SYMLINK_NOFOLLOW
4319                                                     ? PC_SYM_NOFOLLOW
4320                                                     : PC_SYM_FOLLOW)
4321                                                    | PC_KEEP_HANDLE,
4322                                              stat_suffixes);
4323           if (fh)
4324             {
4325               res =  fh->fhaccess (mode, !!(flags & AT_EACCESS));
4326               delete fh;
4327             }
4328         }
4329     }
4330   debug_printf ("returning %d", res);
4331   return res;
4332 }
4333
4334 extern "C" int
4335 fchmodat (int dirfd, const char *pathname, mode_t mode, int flags)
4336 {
4337   tmp_pathbuf tp;
4338   myfault efault;
4339   if (efault.faulted (EFAULT))
4340     return -1;
4341   if (flags)
4342     {
4343       /* BSD has lchmod, but Linux does not.  POSIX says
4344          AT_SYMLINK_NOFOLLOW is allowed to fail on symlinks; but Linux
4345          blindly fails even for non-symlinks.  */
4346       set_errno ((flags & ~AT_SYMLINK_NOFOLLOW) ? EINVAL : EOPNOTSUPP);
4347       return -1;
4348     }
4349   char *path = tp.c_get ();
4350   if (gen_full_path_at (path, dirfd, pathname))
4351     return -1;
4352   return chmod (path, mode);
4353 }
4354
4355 extern "C" int
4356 fchownat (int dirfd, const char *pathname, __uid32_t uid, __gid32_t gid,
4357          int flags)
4358 {
4359   tmp_pathbuf tp;
4360   myfault efault;
4361   if (efault.faulted (EFAULT))
4362     return -1;
4363   if (flags & ~AT_SYMLINK_NOFOLLOW)
4364     {
4365       set_errno (EINVAL);
4366       return -1;
4367     }
4368   char *path = tp.c_get ();
4369   if (gen_full_path_at (path, dirfd, pathname))
4370     return -1;
4371   return chown_worker (path, (flags & AT_SYMLINK_NOFOLLOW)
4372                              ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW, uid, gid);
4373 }
4374
4375 extern "C" int
4376 fstatat (int dirfd, const char *pathname, struct __stat64 *st, int flags)
4377 {
4378   tmp_pathbuf tp;
4379   myfault efault;
4380   if (efault.faulted (EFAULT))
4381     return -1;
4382   if (flags & ~AT_SYMLINK_NOFOLLOW)
4383     {
4384       set_errno (EINVAL);
4385       return -1;
4386     }
4387   char *path = tp.c_get ();
4388   if (gen_full_path_at (path, dirfd, pathname))
4389     return -1;
4390   path_conv pc (path, ((flags & AT_SYMLINK_NOFOLLOW)
4391                        ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW)
4392                       | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes);
4393   return stat_worker (pc, st);
4394 }
4395
4396 extern int utimens_worker (path_conv &, const struct timespec *);
4397
4398 extern "C" int
4399 utimensat (int dirfd, const char *pathname, const struct timespec *times,
4400            int flags)
4401 {
4402   tmp_pathbuf tp;
4403   myfault efault;
4404   if (efault.faulted (EFAULT))
4405     return -1;
4406   char *path = tp.c_get ();
4407   if (flags & ~AT_SYMLINK_NOFOLLOW)
4408     {
4409       set_errno (EINVAL);
4410       return -1;
4411     }
4412   if (gen_full_path_at (path, dirfd, pathname))
4413     return -1;
4414   path_conv win32 (path, PC_POSIX | ((flags & AT_SYMLINK_NOFOLLOW)
4415                                      ? PC_SYM_NOFOLLOW : PC_SYM_FOLLOW),
4416                    stat_suffixes);
4417   return utimens_worker (win32, times);
4418 }
4419
4420 extern "C" int
4421 futimesat (int dirfd, const char *pathname, const struct timeval *times)
4422 {
4423   tmp_pathbuf tp;
4424   myfault efault;
4425   if (efault.faulted (EFAULT))
4426     return -1;
4427   char *path = tp.c_get ();
4428   if (gen_full_path_at (path, dirfd, pathname, true))
4429     return -1;
4430   return utimes (path, times);
4431 }
4432
4433 extern "C" int
4434 linkat (int olddirfd, const char *oldpathname,
4435         int newdirfd, const char *newpathname,
4436         int flags)
4437 {
4438   tmp_pathbuf tp;
4439   myfault efault;
4440   if (efault.faulted (EFAULT))
4441     return -1;
4442   if (flags & ~AT_SYMLINK_FOLLOW)
4443     {
4444       set_errno (EINVAL);
4445       return -1;
4446     }
4447   char *oldpath = tp.c_get ();
4448   if (gen_full_path_at (oldpath, olddirfd, oldpathname))
4449     return -1;
4450   char *newpath = tp.c_get ();
4451   if (gen_full_path_at (newpath, newdirfd, newpathname))
4452     return -1;
4453   if (flags & AT_SYMLINK_FOLLOW)
4454     {
4455       path_conv old_name (oldpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
4456       if (old_name.error)
4457         {
4458           set_errno (old_name.error);
4459           return -1;
4460         }
4461       strcpy (oldpath, old_name.normalized_path);
4462     }
4463   return link (oldpath, newpath);
4464 }
4465
4466 extern "C" int
4467 mkdirat (int dirfd, const char *pathname, mode_t mode)
4468 {
4469   tmp_pathbuf tp;
4470   myfault efault;
4471   if (efault.faulted (EFAULT))
4472     return -1;
4473   char *path = tp.c_get ();
4474   if (gen_full_path_at (path, dirfd, pathname))
4475     return -1;
4476   return mkdir (path, mode);
4477 }
4478
4479 extern "C" int
4480 mkfifoat (int dirfd, const char *pathname, mode_t mode)
4481 {
4482   tmp_pathbuf tp;
4483   myfault efault;
4484   if (efault.faulted (EFAULT))
4485     return -1;
4486   char *path = tp.c_get ();
4487   if (gen_full_path_at (path, dirfd, pathname))
4488     return -1;
4489   return mkfifo (path, mode);
4490 }
4491
4492 extern "C" int
4493 mknodat (int dirfd, const char *pathname, mode_t mode, __dev32_t dev)
4494 {
4495   tmp_pathbuf tp;
4496   myfault efault;
4497   if (efault.faulted (EFAULT))
4498     return -1;
4499   char *path = tp.c_get ();
4500   if (gen_full_path_at (path, dirfd, pathname))
4501     return -1;
4502   return mknod32 (path, mode, dev);
4503 }
4504
4505 extern "C" ssize_t
4506 readlinkat (int dirfd, const char *pathname, char *buf, size_t bufsize)
4507 {
4508   tmp_pathbuf tp;
4509   myfault efault;
4510   if (efault.faulted (EFAULT))
4511     return -1;
4512   char *path = tp.c_get ();
4513   if (gen_full_path_at (path, dirfd, pathname))
4514     return -1;
4515   return readlink (path, buf, bufsize);
4516 }
4517
4518 extern "C" int
4519 renameat (int olddirfd, const char *oldpathname,
4520           int newdirfd, const char *newpathname)
4521 {
4522   tmp_pathbuf tp;
4523   myfault efault;
4524   if (efault.faulted (EFAULT))
4525     return -1;
4526   char *oldpath = tp.c_get ();
4527   if (gen_full_path_at (oldpath, olddirfd, oldpathname))
4528     return -1;
4529   char *newpath = tp.c_get ();
4530   if (gen_full_path_at (newpath, newdirfd, newpathname))
4531     return -1;
4532   return rename (oldpath, newpath);
4533 }
4534
4535 extern "C" int
4536 symlinkat (const char *oldpath, int newdirfd, const char *newpathname)
4537 {
4538   tmp_pathbuf tp;
4539   myfault efault;
4540   if (efault.faulted (EFAULT))
4541     return -1;
4542   char *newpath = tp.c_get ();
4543   if (gen_full_path_at (newpath, newdirfd, newpathname))
4544     return -1;
4545   return symlink (oldpath, newpath);
4546 }
4547
4548 extern "C" int
4549 unlinkat (int dirfd, const char *pathname, int flags)
4550 {
4551   tmp_pathbuf tp;
4552   myfault efault;
4553   if (efault.faulted (EFAULT))
4554     return -1;
4555   if (flags & ~AT_REMOVEDIR)
4556     {
4557       set_errno (EINVAL);
4558       return -1;
4559     }
4560   char *path = tp.c_get ();
4561   if (gen_full_path_at (path, dirfd, pathname))
4562     return -1;
4563   return (flags & AT_REMOVEDIR) ? rmdir (path) : unlink (path);
4564 }