OSDN Git Service

* select.cc (select_stuff::wait): Temporarily disallow APCS.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / path.cc
1 /* path.cc: path support.
2
3      Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4      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   /* This module's job is to
13      - convert between POSIX and Win32 style filenames,
14      - support the `mount' functionality,
15      - support symlinks for files and directories
16
17      Pathnames are handled as follows:
18
19      - A \ or : in a path denotes a pure windows spec.
20      - Paths beginning with // (or \\) are not translated (i.e. looked
21        up in the mount table) and are assumed to be UNC path names.
22
23      The goal in the above set of rules is to allow both POSIX and Win32
24      flavors of pathnames without either interfering.  The rules are
25      intended to be as close to a superset of both as possible.
26
27      Note that you can have more than one path to a file.  The mount
28      table is always prefered when translating Win32 paths to POSIX
29      paths.  Win32 paths in mount table entries may be UNC paths or
30      standard Win32 paths starting with <drive-letter>:
31
32      Text vs Binary issues are not considered here in path style
33      decisions, although the appropriate flags are retrieved and
34      stored in various structures.
35
36      Removing mounted filesystem support would simplify things greatly,
37      but having it gives us a mechanism of treating disk that lives on a
38      UNIX machine as having UNIX semantics [it allows one to edit a text
39      file on that disk and not have cr's magically appear and perhaps
40      break apps running on UNIX boxes].  It also useful to be able to
41      layout a hierarchy without changing the underlying directories.
42
43      The semantics of mounting file systems is not intended to precisely
44      follow normal UNIX systems.
45
46      Each DOS drive is defined to have a current directory.  Supporting
47      this would complicate things so for now things are defined so that
48      c: means c:\.
49   */
50
51 #include "winsup.h"
52 #include "miscfuncs.h"
53 #include <ctype.h>
54 #include <winioctl.h>
55 #include <wingdi.h>
56 #include <winuser.h>
57 #include <winnetwk.h>
58 #include <winnls.h>
59 #include <shlobj.h>
60 #include <sys/cygwin.h>
61 #include "cygerrno.h"
62 #include "security.h"
63 #include "path.h"
64 #include "fhandler.h"
65 #include "dtable.h"
66 #include "cygheap.h"
67 #include "shared_info.h"
68 #include "cygtls.h"
69 #include "tls_pbuf.h"
70 #include "environ.h"
71 #include <assert.h>
72 #include <ntdll.h>
73 #include <wchar.h>
74 #include <wctype.h>
75
76 bool dos_file_warning = true;
77
78 suffix_info stat_suffixes[] =
79 {
80   suffix_info ("", 1),
81   suffix_info (".exe", 1),
82   suffix_info (NULL)
83 };
84
85 struct symlink_info
86 {
87   char contents[SYMLINK_MAX + 1];
88   char *ext_here;
89   int extn;
90   unsigned pflags;
91   DWORD fileattr;
92   int issymlink;
93   bool ext_tacked_on;
94   int error;
95   bool isdevice;
96   _major_t major;
97   _minor_t minor;
98   _mode_t mode;
99   int check (char *path, const suffix_info *suffixes, fs_info &fs,
100              path_conv_handle &conv_hdl);
101   int set (char *path);
102   bool parse_device (const char *);
103   int check_sysfile (HANDLE h);
104   int check_shortcut (HANDLE h);
105   int check_reparse_point (HANDLE h);
106   int check_nfs_symlink (HANDLE h);
107   int posixify (char *srcbuf);
108   bool set_error (int);
109 };
110
111 muto NO_COPY cwdstuff::cwd_lock;
112
113 static const GUID GUID_shortcut
114                         = { 0x00021401L, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
115
116 enum {
117   WSH_FLAG_IDLIST = 0x01,       /* Contains an ITEMIDLIST. */
118   WSH_FLAG_FILE = 0x02,         /* Contains a file locator element. */
119   WSH_FLAG_DESC = 0x04,         /* Contains a description. */
120   WSH_FLAG_RELPATH = 0x08,      /* Contains a relative path. */
121   WSH_FLAG_WD = 0x10,           /* Contains a working dir. */
122   WSH_FLAG_CMDLINE = 0x20,      /* Contains command line args. */
123   WSH_FLAG_ICON = 0x40          /* Contains a custom icon. */
124 };
125
126 struct win_shortcut_hdr
127   {
128     DWORD size;         /* Header size in bytes.  Must contain 0x4c. */
129     GUID magic;         /* GUID of shortcut files. */
130     DWORD flags;        /* Content flags.  See above. */
131
132     /* The next fields from attr to icon_no are always set to 0 in Cygwin
133        and U/Win shortcuts. */
134     DWORD attr; /* Target file attributes. */
135     FILETIME ctime;     /* These filetime items are never touched by the */
136     FILETIME mtime;     /* system, apparently. Values don't matter. */
137     FILETIME atime;
138     DWORD filesize;     /* Target filesize. */
139     DWORD icon_no;      /* Icon number. */
140
141     DWORD run;          /* Values defined in winuser.h. Use SW_NORMAL. */
142     DWORD hotkey;       /* Hotkey value. Set to 0.  */
143     DWORD dummy[2];     /* Future extension probably. Always 0. */
144   };
145
146 /* Return non-zero if PATH1 is a prefix of PATH2.
147    Both are assumed to be of the same path style and / vs \ usage.
148    Neither may be "".
149    LEN1 = strlen (PATH1).  It's passed because often it's already known.
150
151    Examples:
152    /foo/ is a prefix of /foo  <-- may seem odd, but desired
153    /foo is a prefix of /foo/
154    / is a prefix of /foo/bar
155    / is not a prefix of foo/bar
156    foo/ is a prefix foo/bar
157    /foo is not a prefix of /foobar
158 */
159
160 int
161 path_prefix_p (const char *path1, const char *path2, int len1,
162                bool caseinsensitive)
163 {
164   /* Handle case where PATH1 has trailing '/' and when it doesn't.  */
165   if (len1 > 0 && isdirsep (path1[len1 - 1]))
166     len1--;
167
168   if (len1 == 0)
169     return isdirsep (path2[0]) && !isdirsep (path2[1]);
170
171   if (isdirsep (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':')
172     return caseinsensitive ? strncasematch (path1, path2, len1)
173                            : !strncmp (path1, path2, len1);
174
175   return 0;
176 }
177
178 /* Return non-zero if paths match in first len chars.
179    Check is dependent of the case sensitivity setting. */
180 int
181 pathnmatch (const char *path1, const char *path2, int len, bool caseinsensitive)
182 {
183   return caseinsensitive
184          ? strncasematch (path1, path2, len) : !strncmp (path1, path2, len);
185 }
186
187 /* Return non-zero if paths match. Check is dependent of the case
188    sensitivity setting. */
189 int
190 pathmatch (const char *path1, const char *path2, bool caseinsensitive)
191 {
192   return caseinsensitive
193          ? strcasematch (path1, path2) : !strcmp (path1, path2);
194 }
195
196 /* TODO: This function is used in mkdir and rmdir to generate correct
197    error messages in case of paths ending in /. or /.. components.
198    Right now, normalize_posix_path will just normalize
199    those components away, which changes the semantics.  */
200 bool
201 has_dot_last_component (const char *dir, bool test_dot_dot)
202 {
203   /* SUSv3: . and .. are not allowed as last components in various system
204      calls.  Don't test for backslash path separator since that's a Win32
205      path following Win32 rules. */
206   const char *last_comp = strchr (dir, '\0');
207
208   if (last_comp == dir)
209     return false;       /* Empty string.  Probably shouldn't happen here? */
210
211   /* Detect run of trailing slashes */
212   while (last_comp > dir && *--last_comp == '/')
213     continue;
214
215   /* Detect just a run of slashes or a path that does not end with a slash. */
216   if (*last_comp != '.')
217     return false;
218
219   /* We know we have a trailing dot here.  Check that it really is a standalone "."
220      path component by checking that it is at the beginning of the string or is
221      preceded by a "/" */
222   if (last_comp == dir || *--last_comp == '/')
223     return true;
224
225   /* If we're not checking for '..' we're done.  Ditto if we're now pointing to
226      a non-dot. */
227   if (!test_dot_dot || *last_comp != '.')
228     return false;               /* either not testing for .. or this was not '..' */
229
230   /* Repeat previous test for standalone or path component. */
231   return last_comp == dir || last_comp[-1] == '/';
232 }
233
234 /* Normalize a POSIX path.
235    All duplicate /'s, except for 2 leading /'s, are deleted.
236    The result is 0 for success, or an errno error value.  */
237
238 int
239 normalize_posix_path (const char *src, char *dst, char *&tail)
240 {
241   const char *in_src = src;
242   char *dst_start = dst;
243   syscall_printf ("src %s", src);
244
245   if ((isdrive (src) && isdirsep (src[2])) || *src == '\\')
246     goto win32_path;
247
248   tail = dst;
249   if (!isslash (src[0]))
250     {
251       if (!cygheap->cwd.get (dst))
252         return get_errno ();
253       tail = strchr (tail, '\0');
254       if (isslash (dst[0]) && isslash (dst[1]))
255         ++dst_start;
256       if (*src == '.')
257         {
258           if (tail == dst_start + 1 && *dst_start == '/')
259              tail--;
260           goto sawdot;
261         }
262       if (tail > dst && !isslash (tail[-1]))
263         *tail++ = '/';
264     }
265   /* Two leading /'s?  If so, preserve them.  */
266   else if (isslash (src[1]) && !isslash (src[2]))
267     {
268       *tail++ = *src++;
269       ++dst_start;
270     }
271
272   while (*src)
273     {
274       if (*src == '\\')
275         goto win32_path;
276       /* Strip runs of /'s.  */
277       if (!isslash (*src))
278         *tail++ = *src++;
279       else
280         {
281           while (*++src)
282             {
283               if (isslash (*src))
284                 continue;
285
286               if (*src != '.')
287                 break;
288
289             sawdot:
290               if (src[1] != '.')
291                 {
292                   if (!src[1])
293                     {
294                       *tail++ = '/';
295                       goto done;
296                     }
297                   if (!isslash (src[1]))
298                     break;
299                 }
300               else if (src[2] && !isslash (src[2]))
301                 break;
302               else
303                 {
304                   while (tail > dst_start && !isslash (*--tail))
305                     continue;
306                   src++;
307                 }
308             }
309
310           *tail++ = '/';
311         }
312         if ((tail - dst) >= NT_MAX_PATH)
313           {
314             debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
315             return ENAMETOOLONG;
316           }
317     }
318
319 done:
320   *tail = '\0';
321
322   debug_printf ("%s = normalize_posix_path (%s)", dst, in_src);
323   return 0;
324
325 win32_path:
326   int err = normalize_win32_path (in_src, dst, tail);
327   if (!err)
328     for (char *p = dst; (p = strchr (p, '\\')); p++)
329       *p = '/';
330   return err ?: -1;
331 }
332
333 inline void
334 path_conv::add_ext_from_sym (symlink_info &sym)
335 {
336   if (sym.ext_here && *sym.ext_here)
337     {
338       known_suffix = path + sym.extn;
339       if (sym.ext_tacked_on)
340         strcpy ((char *) known_suffix, sym.ext_here);
341     }
342 }
343
344 static void __stdcall mkrelpath (char *dst, bool caseinsensitive)
345   __attribute__ ((regparm (2)));
346
347 static void __stdcall
348 mkrelpath (char *path, bool caseinsensitive)
349 {
350   tmp_pathbuf tp;
351   char *cwd_win32 = tp.c_get ();
352   if (!cygheap->cwd.get (cwd_win32, 0))
353     return;
354
355   unsigned cwdlen = strlen (cwd_win32);
356   if (!path_prefix_p (cwd_win32, path, cwdlen, caseinsensitive))
357     return;
358
359   size_t n = strlen (path);
360   if (n < cwdlen)
361     return;
362
363   char *tail = path;
364   if (n == cwdlen)
365     tail += cwdlen;
366   else
367     tail += isdirsep (cwd_win32[cwdlen - 1]) ? cwdlen : cwdlen + 1;
368
369   memmove (path, tail, strlen (tail) + 1);
370   if (!*path)
371     strcpy (path, ".");
372 }
373
374 void
375 path_conv::set_normalized_path (const char *path_copy)
376 {
377   if (path_copy)
378     {
379       size_t n = strlen (path_copy) + 1;
380       char *p = (char *) crealloc_abort ((void *) normalized_path, n);
381       normalized_path = (const char *) memcpy (p, path_copy, n);
382     }
383 }
384
385 static inline void
386 str2uni_cat (UNICODE_STRING &tgt, const char *srcstr)
387 {
388   int len = sys_mbstowcs (tgt.Buffer + tgt.Length / sizeof (WCHAR),
389                           (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR),
390                           srcstr);
391   if (len)
392     tgt.Length += (len - 1) * sizeof (WCHAR);
393 }
394
395 PUNICODE_STRING
396 get_nt_native_path (const char *path, UNICODE_STRING& upath, bool dos)
397 {
398   upath.Length = 0;
399   if (path[0] == '/')           /* special path w/o NT path representation. */
400     str2uni_cat (upath, path);
401   else if (path[0] != '\\')     /* X:\...  or relative path. */
402     {
403       if (path[1] == ':')       /* X:\... */
404         {
405           RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
406           str2uni_cat (upath, path);
407           /* The drive letter must be upper case. */
408           upath.Buffer[4] = towupper (upath.Buffer[4]);
409         }
410       else
411         str2uni_cat (upath, path);
412       transform_chars (&upath, 7);
413     }
414   else if (path[1] != '\\')     /* \Device\... */
415     str2uni_cat (upath, path);
416   else if ((path[2] != '.' && path[2] != '?')
417            || path[3] != '\\')  /* \\server\share\... */
418     {
419       RtlAppendUnicodeStringToString (&upath, &ro_u_uncp);
420       str2uni_cat (upath, path + 2);
421       transform_chars (&upath, 8);
422     }
423   else                          /* \\.\device or \\?\foo */
424     {
425       RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
426       str2uni_cat (upath, path + 4);
427     }
428   if (dos)
429     {
430       /* Unfortunately we can't just use transform_chars with the tfx_rev_chars
431          table since only leading and trailing spaces and dots are affected.
432          So we step to every backslash and fix surrounding dots and spaces.
433          That makes these broken filesystems a bit slower, but, hey. */
434       PWCHAR cp = upath.Buffer + 7;
435       PWCHAR cend = upath.Buffer + upath.Length / sizeof (WCHAR);
436       while (++cp < cend)
437         if (*cp == L'\\')
438           {
439             PWCHAR ccp = cp - 1;
440             while (*ccp == L'.' || *ccp == L' ')
441               *ccp-- |= 0xf000;
442             while (cp[1] == L' ')
443               *++cp |= 0xf000;
444           }
445       while (*--cp == L'.' || *cp == L' ')
446         *cp |= 0xf000;
447     }
448   return &upath;
449 }
450
451 PUNICODE_STRING
452 path_conv::get_nt_native_path ()
453 {
454   PUNICODE_STRING res;
455   if (wide_path)
456     res = &uni_path;
457   else if (!path)
458     res = NULL;
459   else
460     {
461       uni_path.Length = 0;
462       uni_path.MaximumLength = (strlen (path) + 10) * sizeof (WCHAR);
463       wide_path = (PWCHAR) cmalloc_abort (HEAP_STR, uni_path.MaximumLength);
464       uni_path.Buffer = wide_path;
465       ::get_nt_native_path (path, uni_path, has_dos_filenames_only ());
466       res = &uni_path;
467     }
468   return res;
469 }
470
471 PWCHAR
472 path_conv::get_wide_win32_path (PWCHAR wc)
473 {
474   get_nt_native_path ();
475   if (!wide_path)
476     return NULL;
477   wcpcpy (wc, wide_path);
478   if (wc[1] == L'?')
479     wc[1] = L'\\';
480   return wc;
481 }
482
483 void
484 warn_msdos (const char *src)
485 {
486   if (user_shared->warned_msdos || !dos_file_warning || !cygwin_finished_initializing)
487     return;
488   tmp_pathbuf tp;
489   char *posix_path = tp.c_get ();
490   small_printf ("cygwin warning:\n");
491   if (cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, src,
492                         posix_path, NT_MAX_PATH))
493     small_printf ("  MS-DOS style path detected: %ls\n  POSIX equivalent preferred.\n",
494                   src);
495   else
496     small_printf ("  MS-DOS style path detected: %ls\n  Preferred POSIX equivalent is: %ls\n",
497                   src, posix_path);
498   small_printf ("  CYGWIN environment variable option \"nodosfilewarning\" turns off this warning.\n"
499                 "  Consult the user's guide for more details about POSIX paths:\n"
500                 "    http://cygwin.com/cygwin-ug-net/using.html#using-pathnames\n");
501   user_shared->warned_msdos = true;
502 }
503
504 static DWORD
505 getfileattr (const char *path, bool caseinsensitive) /* path has to be always absolute. */
506 {
507   tmp_pathbuf tp;
508   UNICODE_STRING upath;
509   OBJECT_ATTRIBUTES attr;
510   FILE_BASIC_INFORMATION fbi;
511   NTSTATUS status;
512   IO_STATUS_BLOCK io;
513
514   tp.u_get (&upath);
515   InitializeObjectAttributes (&attr, &upath,
516                               caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
517                               NULL, NULL);
518   get_nt_native_path (path, upath, false);
519
520   status = NtQueryAttributesFile (&attr, &fbi);
521   if (NT_SUCCESS (status))
522     return fbi.FileAttributes;
523
524   if (status != STATUS_OBJECT_NAME_NOT_FOUND
525       && status != STATUS_NO_SUCH_FILE) /* File not found on 9x share */
526     {
527       /* File exists but access denied.  Try to get attribute through
528          directory query. */
529       UNICODE_STRING dirname, basename;
530       HANDLE dir;
531       FILE_BOTH_DIRECTORY_INFORMATION fdi;
532
533       RtlSplitUnicodePath (&upath, &dirname, &basename);
534       InitializeObjectAttributes (&attr, &dirname,
535                                   caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
536                                   NULL, NULL);
537       status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
538                            &attr, &io, FILE_SHARE_VALID_FLAGS,
539                            FILE_SYNCHRONOUS_IO_NONALERT
540                            | FILE_OPEN_FOR_BACKUP_INTENT
541                            | FILE_DIRECTORY_FILE);
542       if (NT_SUCCESS (status))
543         {
544           status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io,
545                                          &fdi, sizeof fdi,
546                                          FileBothDirectoryInformation,
547                                          TRUE, &basename, TRUE);
548           NtClose (dir);
549           if (NT_SUCCESS (status) || status == STATUS_BUFFER_OVERFLOW)
550             return fdi.FileAttributes;
551         }
552     }
553   SetLastError (RtlNtStatusToDosError (status));
554   return INVALID_FILE_ATTRIBUTES;
555 }
556
557 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
558    passing to Win32 API routines.
559
560    If an error occurs, `error' is set to the errno value.
561    Otherwise it is set to 0.
562
563    follow_mode values:
564         SYMLINK_FOLLOW      - convert to PATH symlink points to
565         SYMLINK_NOFOLLOW    - convert to PATH of symlink itself
566         SYMLINK_IGNORE      - do not check PATH for symlinks
567         SYMLINK_CONTENTS    - just return symlink contents
568 */
569
570 /* TODO: This implementation is only preliminary.  For internal
571    purposes it's necessary to have a path_conv::check function which
572    takes a UNICODE_STRING src path, otherwise we waste a lot of time
573    for converting back and forth.  The below implementation does
574    realy nothing but converting to char *, until path_conv handles
575    wide-char paths directly. */
576 void
577 path_conv::check (const UNICODE_STRING *src, unsigned opt,
578                   const suffix_info *suffixes)
579 {
580   tmp_pathbuf tp;
581   char *path = tp.c_get ();
582
583   user_shared->warned_msdos = true;
584   sys_wcstombs (path, NT_MAX_PATH, src->Buffer, src->Length / sizeof (WCHAR));
585   path_conv::check (path, opt, suffixes);
586 }
587
588 void
589 path_conv::check (const char *src, unsigned opt,
590                   const suffix_info *suffixes)
591 {
592   /* The tmp_buf array is used when expanding symlinks.  It is NT_MAX_PATH * 2
593      in length so that we can hold the expanded symlink plus a trailer.  */
594   tmp_pathbuf tp;
595   char *path_copy = tp.c_get ();
596   char *pathbuf = tp.c_get ();
597   char *tmp_buf = tp.t_get ();
598   char *THIS_path = tp.c_get ();
599   symlink_info sym;
600   bool need_directory = 0;
601   bool saw_symlinks = 0;
602   bool add_ext = false;
603   bool is_relpath;
604   char *tail, *path_end;
605
606 #if 0
607   static path_conv last_path_conv;
608   static char last_src[CYG_MAX_PATH];
609
610   if (*last_src && strcmp (last_src, src) == 0)
611     {
612       *this = last_path_conv;
613       return;
614     }
615 #endif
616
617   myfault efault;
618   if (efault.faulted ())
619     {
620       error = EFAULT;
621       return;
622     }
623   int loop = 0;
624   path_flags = 0;
625   known_suffix = NULL;
626   fileattr = INVALID_FILE_ATTRIBUTES;
627   caseinsensitive = OBJ_CASE_INSENSITIVE;
628   if (wide_path)
629     cfree (wide_path);
630   wide_path = NULL;
631   if (path)
632     {
633       cfree (modifiable_path ());
634       path = NULL;
635     }
636   close_conv_handle ();
637   memset (&dev, 0, sizeof (dev));
638   fs.clear ();
639   if (normalized_path)
640     {
641       cfree ((void *) normalized_path);
642       normalized_path = NULL;
643     }
644   int component = 0;            // Number of translated components
645
646   if (!(opt & PC_NULLEMPTY))
647     error = 0;
648   else if (!*src)
649     {
650       error = ENOENT;
651       return;
652     }
653
654   bool is_msdos = false;
655   /* This loop handles symlink expansion.  */
656   for (;;)
657     {
658       MALLOC_CHECK;
659       assert (src);
660
661       is_relpath = !isabspath (src);
662       error = normalize_posix_path (src, path_copy, tail);
663       if (error > 0)
664         return;
665       if (error < 0)
666         {
667           if (component == 0)
668             is_msdos = true;
669           error = 0;
670         }
671
672       /* Detect if the user was looking for a directory.  We have to strip the
673          trailing slash initially while trying to add extensions but take it
674          into account during processing */
675       if (tail > path_copy + 2 && isslash (tail[-1]))
676         {
677           need_directory = 1;
678           *--tail = '\0';
679         }
680       path_end = tail;
681
682       /* Scan path_copy from right to left looking either for a symlink
683          or an actual existing file.  If an existing file is found, just
684          return.  If a symlink is found, exit the for loop.
685          Also: be careful to preserve the errno returned from
686          symlink.check as the caller may need it. */
687       /* FIXME: Do we have to worry about multiple \'s here? */
688       component = 0;            // Number of translated components
689       sym.contents[0] = '\0';
690
691       int symlen = 0;
692
693       for (unsigned pflags_or = opt & (PC_NO_ACCESS_CHECK | PC_KEEP_HANDLE);
694            ;
695            pflags_or = 0)
696         {
697           const suffix_info *suff;
698           char *full_path;
699
700           /* Don't allow symlink.check to set anything in the path_conv
701              class if we're working on an inner component of the path */
702           if (component)
703             {
704               suff = NULL;
705               full_path = pathbuf;
706             }
707           else
708             {
709               suff = suffixes;
710               full_path = THIS_path;
711             }
712
713           /* Convert to native path spec sans symbolic link info. */
714           error = mount_table->conv_to_win32_path (path_copy, full_path, dev,
715                                                    &sym.pflags);
716
717           if (error)
718             return;
719
720           sym.pflags |= pflags_or;
721
722           if (dev.get_major () == DEV_CYGDRIVE_MAJOR)
723             {
724               if (!component)
725                 fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY;
726               else
727                 {
728                   fileattr = getfileattr (THIS_path,
729                                           sym.pflags & MOUNT_NOPOSIX);
730                   dev = FH_FS;
731                 }
732               goto out;
733             }
734           else if (dev == FH_DEV)
735             {
736               dev = FH_FS;
737 #if 0
738               fileattr = getfileattr (THIS_path, sym.pflags & MOUNT_NOPOSIX);
739               if (!component && fileattr == INVALID_FILE_ATTRIBUTES)
740                 {
741                   fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY;
742                   goto out;
743                 }
744 #endif
745             }
746           else if (isvirtual_dev (dev))
747             {
748               /* FIXME: Calling build_fhandler here is not the right way to handle this. */
749               fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy);
750               virtual_ftype_t file_type = fh->exists ();
751               if (file_type == virt_symlink)
752                 {
753                   fh->fill_filebuf ();
754                   symlen = sym.set (fh->get_filebuf ());
755                 }
756               delete fh;
757               switch (file_type)
758                 {
759                   case virt_directory:
760                   case virt_rootdir:
761                     if (component == 0)
762                       fileattr = FILE_ATTRIBUTE_DIRECTORY;
763                     break;
764                   case virt_file:
765                     if (component == 0)
766                       fileattr = 0;
767                     break;
768                   case virt_symlink:
769                     goto is_virtual_symlink;
770                   case virt_pipe:
771                     if (component == 0)
772                       {
773                         fileattr = 0;
774                         dev.parse (FH_PIPE);
775                       }
776                     break;
777                   case virt_socket:
778                     if (component == 0)
779                       {
780                         fileattr = 0;
781                         dev.parse (FH_TCP);
782                       }
783                     break;
784                   case virt_fsdir:
785                   case virt_fsfile:
786                     /* Access to real file or directory via block device
787                        entry in /proc/sys.  Convert to real file and go with
788                        the flow. */
789                     dev.parse (FH_FS);
790                     goto is_fs_via_procsys;
791                   case virt_blk:
792                     /* Block special device.  If the trailing slash has been
793                        requested, the target is the root directory of the
794                        filesystem on this block device.  So we convert this to
795                        a real file and attach the backslash. */
796                     if (component == 0 && need_directory)
797                       {
798                         dev.parse (FH_FS);
799                         strcat (full_path, "\\");
800                         fileattr = FILE_ATTRIBUTE_DIRECTORY
801                                    | FILE_ATTRIBUTE_DEVICE;
802                         goto out;
803                       }
804                     /*FALLTHRU*/
805                   case virt_chr:
806                     if (component == 0)
807                       fileattr = FILE_ATTRIBUTE_DEVICE;
808                     break;
809                   default:
810                     if (component == 0)
811                       fileattr = INVALID_FILE_ATTRIBUTES;
812                     goto virtual_component_retry;
813                 }
814               if (component == 0 || dev != FH_NETDRIVE)
815                 path_flags |= PATH_RO;
816               goto out;
817             }
818           /* devn should not be a device.  If it is, then stop parsing now. */
819           else if (dev != FH_FS)
820             {
821               fileattr = 0;
822               path_flags = sym.pflags;
823               if (component)
824                 {
825                   error = ENOTDIR;
826                   return;
827                 }
828               goto out;         /* Found a device.  Stop parsing. */
829             }
830
831           /* If path is only a drivename, Windows interprets it as the
832              current working directory on this drive instead of the root
833              dir which is what we want. So we need the trailing backslash
834              in this case. */
835           if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
836             {
837               full_path[2] = '\\';
838               full_path[3] = '\0';
839             }
840
841           /* If the incoming path was given in DOS notation, always treat
842              it as caseinsensitive,noacl path.  This must be set before
843              calling sym.check, otherwise the path is potentially treated
844              casesensitive. */
845           if (is_msdos)
846             sym.pflags |= PATH_NOPOSIX | PATH_NOACL;
847
848 is_fs_via_procsys:
849
850           symlen = sym.check (full_path, suff, fs, conv_handle);
851
852 is_virtual_symlink:
853
854           if (sym.isdevice)
855             {
856               if (component)
857                 {
858                   error = ENOTDIR;
859                   return;
860                 }
861               dev.parse (sym.major, sym.minor);
862               dev.setfs (1);
863               dev.mode = sym.mode;
864               fileattr = sym.fileattr;
865               goto out;
866             }
867
868           if (sym.pflags & PATH_SOCKET)
869             {
870               if (component)
871                 {
872                   error = ENOTDIR;
873                   return;
874                 }
875               fileattr = sym.fileattr;
876               dev.parse (FH_UNIX);
877               dev.setfs (1);
878               goto out;
879             }
880
881           if (!component)
882             {
883               fileattr = sym.fileattr;
884               path_flags = sym.pflags;
885             }
886
887           /* If symlink.check found an existing non-symlink file, then
888              it sets the appropriate flag.  It also sets any suffix found
889              into `ext_here'. */
890           if (!sym.issymlink && sym.fileattr != INVALID_FILE_ATTRIBUTES)
891             {
892               error = sym.error;
893               if (component == 0)
894                 add_ext = true;
895               else if (!(sym.fileattr & FILE_ATTRIBUTE_DIRECTORY))
896                 {
897                   error = ENOTDIR;
898                   goto out;
899                 }
900               goto out; // file found
901             }
902           /* Found a symlink if symlen > 0.  If component == 0, then the
903              src path itself was a symlink.  If !follow_mode then
904              we're done.  Otherwise we have to insert the path found
905              into the full path that we are building and perform all of
906              these operations again on the newly derived path. */
907           else if (symlen > 0)
908             {
909               saw_symlinks = 1;
910               if (component == 0 && !need_directory
911                   && (!(opt & PC_SYM_FOLLOW)
912                       || (is_rep_symlink () && (opt & PC_SYM_NOFOLLOW_REP))))
913                 {
914                   set_symlink (symlen); // last component of path is a symlink.
915                   if (opt & PC_SYM_CONTENTS)
916                     {
917                       strcpy (THIS_path, sym.contents);
918                       goto out;
919                     }
920                   add_ext = true;
921                   goto out;
922                 }
923               /* Following a symlink we can't trust the collected filesystem
924                  information any longer. */
925               fs.clear ();
926               /* Close handle, if we have any.  Otherwise we're collecting
927                  handles while following symlinks. */
928               conv_handle.close ();
929               break;
930             }
931           else if (sym.error && sym.error != ENOENT)
932             {
933               error = sym.error;
934               goto out;
935             }
936           /* No existing file found. */
937
938 virtual_component_retry:
939           /* Find the new "tail" of the path, e.g. in '/for/bar/baz',
940              /baz is the tail. */
941           if (tail != path_end)
942             *tail = '/';
943           while (--tail > path_copy + 1 && *tail != '/') {}
944           /* Exit loop if there is no tail or we are at the
945              beginning of a UNC path */
946           if (tail <= path_copy + 1)
947             goto out;   // all done
948
949           /* Haven't found an existing pathname component yet.
950              Pinch off the tail and try again. */
951           *tail = '\0';
952           component++;
953         }
954
955       /* Arrive here if above loop detected a symlink. */
956       if (++loop > SYMLOOP_MAX)
957         {
958           error = ELOOP;   // Eep.
959           return;
960         }
961
962       MALLOC_CHECK;
963
964
965       /* Place the link content, possibly with head and/or tail, in tmp_buf */
966
967       char *headptr;
968       if (isabspath (sym.contents))
969         headptr = tmp_buf;      /* absolute path */
970       else
971         {
972           /* Copy the first part of the path (with ending /) and point to the end. */
973           char *prevtail = tail;
974           while (--prevtail > path_copy  && *prevtail != '/') {}
975           int headlen = prevtail - path_copy + 1;;
976           memcpy (tmp_buf, path_copy, headlen);
977           headptr = &tmp_buf[headlen];
978         }
979
980       /* Make sure there is enough space */
981       if (headptr + symlen >= tmp_buf + (2 * NT_MAX_PATH))
982         {
983         too_long:
984           error = ENAMETOOLONG;
985           set_path ("::ENAMETOOLONG::");
986           return;
987         }
988
989      /* Copy the symlink contents to the end of tmp_buf.
990         Convert slashes. */
991       for (char *p = sym.contents; *p; p++)
992         *headptr++ = *p == '\\' ? '/' : *p;
993       *headptr = '\0';
994
995       /* Copy any tail component (with the 0) */
996       if (tail++ < path_end)
997         {
998           /* Add a slash if needed. There is space. */
999           if (*(headptr - 1) != '/')
1000             *headptr++ = '/';
1001           int taillen = path_end - tail + 1;
1002           if (headptr + taillen > tmp_buf + (2 * NT_MAX_PATH))
1003             goto too_long;
1004           memcpy (headptr, tail, taillen);
1005         }
1006
1007       /* Evaluate everything all over again. */
1008       src = tmp_buf;
1009     }
1010
1011   if (!(opt & PC_SYM_CONTENTS))
1012     add_ext = true;
1013
1014 out:
1015   set_path (THIS_path);
1016   if (add_ext)
1017     add_ext_from_sym (sym);
1018   if (dev == FH_NETDRIVE && component)
1019     {
1020       /* This case indicates a non-existant resp. a non-retrievable
1021          share.  This happens for instance if the share is a printer.
1022          In this case the path must not be treated like a FH_NETDRIVE,
1023          but like a FH_FS instead, so the usual open call for files
1024          is used on it. */
1025       dev.parse (FH_FS);
1026     }
1027   else if (isproc_dev (dev) && fileattr == INVALID_FILE_ATTRIBUTES)
1028     {
1029       /* FIXME: Usually we don't set error to ENOENT if a file doesn't
1030          exist.  This is typically indicated by the fileattr content.
1031          So, why here?  The downside is that cygwin_conv_path just gets
1032          an error for these paths so it reports the error back to the
1033          application.  Unlike in all other cases of non-existant files,
1034          for which check doesn't set error, so cygwin_conv_path just
1035          returns the path, as intended. */
1036       error = ENOENT;
1037       return;
1038     }
1039   else if (!need_directory || error)
1040     /* nothing to do */;
1041   else if (fileattr == INVALID_FILE_ATTRIBUTES)
1042     strcat (modifiable_path (), "\\"); /* Reattach trailing dirsep in native path. */
1043   else if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
1044     path_flags &= ~PATH_SYMLINK;
1045   else
1046     {
1047       debug_printf ("%s is a non-directory", path);
1048       error = ENOTDIR;
1049       return;
1050     }
1051
1052   if (dev.isfs ())
1053     {
1054       if (strncmp (path, "\\\\.\\", 4))
1055         {
1056           if (!tail || tail == path)
1057             /* nothing */;
1058           else if (tail[-1] != '\\')
1059             *tail = '\0';
1060           else
1061             {
1062               error = ENOENT;
1063               return;
1064             }
1065         }
1066
1067       /* If FS hasn't been checked already in symlink_info::check, do so now. */
1068       if (fs.inited ()|| fs.update (get_nt_native_path (), NULL))
1069         {
1070           /* Incoming DOS paths are treated like DOS paths in native
1071              Windows applications.  No ACLs, just default settings. */
1072           if (is_msdos)
1073             fs.has_acls (false);
1074           debug_printf ("this->path(%s), has_acls(%d)", path, fs.has_acls ());
1075           /* CV: We could use this->has_acls() but I want to make sure that
1076              we don't forget that the PATH_NOACL flag must be taken into
1077              account here. */
1078           if (!(path_flags & PATH_NOACL) && fs.has_acls ())
1079             set_exec (0);  /* We really don't know if this is executable or not here
1080                               but set it to not executable since it will be figured out
1081                               later by anything which cares about this. */
1082         }
1083       /* If the FS has been found to have unrelibale inodes, note
1084          that in path_flags. */
1085       if (!fs.hasgood_inode ())
1086         path_flags |= PATH_IHASH;
1087       /* If the OS is caseinsensitive or the FS is caseinsensitive,
1088          don't handle path casesensitive. */
1089       if (cygwin_shared->obcaseinsensitive || fs.caseinsensitive ())
1090         path_flags |= PATH_NOPOSIX;
1091       caseinsensitive = (path_flags & PATH_NOPOSIX)
1092                         ? OBJ_CASE_INSENSITIVE : 0;
1093       if (exec_state () != dont_know_if_executable)
1094         /* ok */;
1095       else if (isdir ())
1096         set_exec (1);
1097       else if (issymlink () || issocket ())
1098         set_exec (0);
1099     }
1100
1101   if (opt & PC_NOFULL)
1102     {
1103       if (is_relpath)
1104         {
1105           mkrelpath (this->modifiable_path (), !!caseinsensitive);
1106           /* Invalidate wide_path so that wide relpath can be created
1107              in later calls to get_nt_native_path or get_wide_win32_path. */
1108           if (wide_path)
1109             cfree (wide_path);
1110           wide_path = NULL;
1111         }
1112       if (need_directory)
1113         {
1114           size_t n = strlen (this->path);
1115           /* Do not add trailing \ to UNC device names like \\.\a: */
1116           if (this->path[n - 1] != '\\' &&
1117               (strncmp (this->path, "\\\\.\\", 4) != 0))
1118             {
1119               this->modifiable_path ()[n] = '\\';
1120               this->modifiable_path ()[n + 1] = '\0';
1121             }
1122         }
1123     }
1124
1125   if (saw_symlinks)
1126     set_has_symlinks ();
1127
1128   if (opt & PC_OPEN)
1129     path_flags |= PATH_OPEN;
1130
1131   if (opt & PC_CTTY)
1132     path_flags |= PATH_CTTY;
1133
1134   if ((opt & PC_POSIX))
1135     {
1136       if (tail < path_end && tail > path_copy + 1)
1137         *tail = '/';
1138       set_normalized_path (path_copy);
1139       if (is_msdos && !(opt & PC_NOWARN))
1140         warn_msdos (src);
1141     }
1142
1143 #if 0
1144   if (!error)
1145     {
1146       last_path_conv = *this;
1147       strcpy (last_src, src);
1148     }
1149 #endif
1150 }
1151
1152 path_conv::~path_conv ()
1153 {
1154   if (normalized_path)
1155     {
1156       cfree ((void *) normalized_path);
1157       normalized_path = NULL;
1158     }
1159   if (path)
1160     {
1161       cfree (modifiable_path ());
1162       path = NULL;
1163     }
1164   if (wide_path)
1165     {
1166       cfree (wide_path);
1167       wide_path = NULL;
1168     }
1169   close_conv_handle ();
1170 }
1171
1172 bool
1173 path_conv::is_binary ()
1174 {
1175   tmp_pathbuf tp;
1176   PWCHAR bintest = tp.w_get ();
1177   DWORD bin;
1178
1179   return GetBinaryTypeW (get_wide_win32_path (bintest), &bin)
1180          && (bin == SCS_32BIT_BINARY || bin == SCS_64BIT_BINARY);
1181 }
1182
1183 /* Normalize a Win32 path.
1184    /'s are converted to \'s in the process.
1185    All duplicate \'s, except for 2 leading \'s, are deleted.
1186
1187    The result is 0 for success, or an errno error value.
1188    FIXME: A lot of this should be mergeable with the POSIX critter.  */
1189 int
1190 normalize_win32_path (const char *src, char *dst, char *&tail)
1191 {
1192   const char *src_start = src;
1193   bool beg_src_slash = isdirsep (src[0]);
1194
1195   tail = dst;
1196   /* Skip long path name prefixes in Win32 or NT syntax. */
1197   if (beg_src_slash && (src[1] == '?' || isdirsep (src[1]))
1198       && src[2] == '?' && isdirsep (src[3]))
1199     {
1200       src += 4;
1201       if (src[1] != ':') /* native UNC path */
1202         src += 2; /* Fortunately the first char is not copied... */
1203       else
1204         beg_src_slash = false;
1205     }
1206   if (beg_src_slash && isdirsep (src[1]))
1207     {
1208       if (isdirsep (src[2]))
1209         {
1210           /* More than two slashes are just folded into one. */
1211           src += 2;
1212           while (isdirsep (src[1]))
1213             ++src;
1214         }
1215       else
1216         {
1217           /* Two slashes start a network or device path. */
1218           *tail++ = '\\';
1219           src++;
1220           if (src[1] == '.' && isdirsep (src[2]))
1221             {
1222               *tail++ = '\\';
1223               *tail++ = '.';
1224               src += 2;
1225             }
1226         }
1227     }
1228   if (tail == dst)
1229     {
1230       if (isdrive (src))
1231         /* Always convert drive letter to uppercase for case sensitivity. */
1232         *tail++ = cyg_toupper (*src++);
1233       else if (*src != '/')
1234         {
1235           if (beg_src_slash)
1236             tail += cygheap->cwd.get_drive (dst);
1237           else if (!cygheap->cwd.get (dst, 0))
1238             return get_errno ();
1239           else
1240             {
1241               tail = strchr (tail, '\0');
1242               if (tail[-1] != '\\')
1243                 *tail++ = '\\';
1244             }
1245         }
1246     }
1247
1248   while (*src)
1249     {
1250       /* Strip duplicate /'s.  */
1251       if (isdirsep (src[0]) && isdirsep (src[1]))
1252         src++;
1253       /* Ignore "./".  */
1254       else if (src[0] == '.' && isdirsep (src[1])
1255                && (src == src_start || isdirsep (src[-1])))
1256         src += 2;
1257
1258       /* Backup if "..".  */
1259       else if (src[0] == '.' && src[1] == '.'
1260                /* dst must be greater than dst_start */
1261                && tail[-1] == '\\')
1262         {
1263           if (!isdirsep (src[2]) && src[2] != '\0')
1264               *tail++ = *src++;
1265           else
1266             {
1267               /* Back up over /, but not if it's the first one.  */
1268               if (tail > dst + 1)
1269                 tail--;
1270               /* Now back up to the next /.  */
1271               while (tail > dst + 1 && tail[-1] != '\\' && tail[-2] != ':')
1272                 tail--;
1273               src += 2;
1274               /* Skip /'s to the next path component. */
1275               while (isdirsep (*src))
1276                 src++;
1277             }
1278         }
1279       /* Otherwise, add char to result.  */
1280       else
1281         {
1282           if (*src == '/')
1283             *tail++ = '\\';
1284           else
1285             *tail++ = *src;
1286           src++;
1287         }
1288       if ((tail - dst) >= NT_MAX_PATH)
1289         return ENAMETOOLONG;
1290     }
1291    if (tail > dst + 1 && tail[-1] == '.' && tail[-2] == '\\')
1292      tail--;
1293   *tail = '\0';
1294   debug_printf ("%s = normalize_win32_path (%s)", dst, src_start);
1295   return 0;
1296 }
1297
1298 /* Various utilities.  */
1299
1300 /* nofinalslash: Remove trailing / and \ from SRC (except for the
1301    first one).  It is ok for src == dst.  */
1302
1303 void __stdcall
1304 nofinalslash (const char *src, char *dst)
1305 {
1306   int len = strlen (src);
1307   if (src != dst)
1308     memcpy (dst, src, len + 1);
1309   while (len > 1 && isdirsep (dst[--len]))
1310     dst[len] = '\0';
1311 }
1312
1313 /* conv_path_list: Convert a list of path names to/from Win32/POSIX. */
1314
1315 static int
1316 conv_path_list (const char *src, char *dst, size_t size,
1317                 cygwin_conv_path_t what)
1318 {
1319   tmp_pathbuf tp;
1320   char src_delim, dst_delim;
1321   size_t len;
1322   bool env_cvt = false;
1323
1324   if (what == (cygwin_conv_path_t) ENV_CVT)
1325     {
1326       what = CCP_WIN_A_TO_POSIX | CCP_RELATIVE;
1327       env_cvt = true;
1328     }
1329   if (what & CCP_WIN_A_TO_POSIX)
1330     {
1331       src_delim = ';';
1332       dst_delim = ':';
1333     }
1334   else
1335     {
1336       src_delim = ':';
1337       dst_delim = ';';
1338     }
1339
1340   char *srcbuf;
1341   len = strlen (src) + 1;
1342   if (len <= NT_MAX_PATH * sizeof (WCHAR))
1343     srcbuf = (char *) tp.w_get ();
1344   else
1345     srcbuf = (char *) alloca (len);
1346
1347   int err = 0;
1348   char *d = dst - 1;
1349   bool saw_empty = false;
1350   do
1351     {
1352       char *srcpath = srcbuf;
1353       char *s = strccpy (srcpath, &src, src_delim);
1354       size_t len = s - srcpath;
1355       if (len >= NT_MAX_PATH)
1356         {
1357           err = ENAMETOOLONG;
1358           break;
1359         }
1360       /* Paths in Win32 path lists in the environment (%Path%), are often
1361          enclosed in quotes (usually paths with spaces).  Trailing backslashes
1362          are common, too.  Remove them. */
1363       if (env_cvt && len)
1364         {
1365           if (*srcpath == '"')
1366             {
1367               ++srcpath;
1368               *--s = '\0';
1369               len -= 2;
1370             }
1371           while (len && s[-1] == '\\')
1372             {
1373               *--s = '\0';
1374               --len;
1375             }
1376         }
1377       if (len)
1378         {
1379           ++d;
1380           err = cygwin_conv_path (what, srcpath, d, size - (d - dst));
1381         }
1382       else if ((what & CCP_CONVTYPE_MASK) == CCP_POSIX_TO_WIN_A)
1383         {
1384           ++d;
1385           err = cygwin_conv_path (what, ".", d, size - (d - dst));
1386         }
1387       else
1388         {
1389           if (env_cvt)
1390             saw_empty = true;
1391           continue;
1392         }
1393       if (err)
1394         break;
1395       d = strchr (d, '\0');
1396       *d = dst_delim;
1397     }
1398   while (*src++);
1399
1400   if (saw_empty)
1401     err = EIDRM;
1402
1403   if (d < dst)
1404     d++;
1405   *d = '\0';
1406   return err;
1407 }
1408
1409 /********************** Symbolic Link Support **************************/
1410
1411 /* Create a symlink from FROMPATH to TOPATH. */
1412
1413 /* If TRUE create symlinks as Windows shortcuts, if false create symlinks
1414    as normal files with magic number and system bit set. */
1415 bool allow_winsymlinks = false;
1416
1417 extern "C" int
1418 symlink (const char *oldpath, const char *newpath)
1419 {
1420   return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
1421 }
1422
1423 int
1424 symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
1425                 bool isdevice)
1426 {
1427   int res = -1;
1428   size_t len;
1429   path_conv win32_newpath, win32_oldpath;
1430   char *buf, *cp;
1431   SECURITY_ATTRIBUTES sa = sec_none_nih;
1432   OBJECT_ATTRIBUTES attr;
1433   IO_STATUS_BLOCK io;
1434   NTSTATUS status;
1435   HANDLE fh;
1436   ULONG access = DELETE | FILE_GENERIC_WRITE;
1437   tmp_pathbuf tp;
1438   unsigned check_opt;
1439   bool mk_winsym = use_winsym;
1440   bool has_trailing_dirsep = false;
1441
1442   /* POSIX says that empty 'newpath' is invalid input while empty
1443      'oldpath' is valid -- it's symlink resolver job to verify if
1444      symlink contents point to existing filesystem object */
1445   myfault efault;
1446   if (efault.faulted (EFAULT))
1447     goto done;
1448   if (!*oldpath || !*newpath)
1449     {
1450       set_errno (ENOENT);
1451       goto done;
1452     }
1453
1454   if (strlen (oldpath) > SYMLINK_MAX)
1455     {
1456       set_errno (ENAMETOOLONG);
1457       goto done;
1458     }
1459
1460   /* Trailing dirsep is a no-no. */
1461   len = strlen (newpath);
1462   has_trailing_dirsep = isdirsep (newpath[len - 1]);
1463   if (has_trailing_dirsep)
1464     {
1465       newpath = strdup (newpath);
1466       ((char *) newpath)[len - 1] = '\0';
1467     }
1468
1469   check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0);
1470   /* We need the normalized full path below. */
1471   win32_newpath.check (newpath, check_opt, stat_suffixes);
1472   /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O
1473      attribute.  Therefore we create symlinks on MVFS always as shortcuts. */
1474   mk_winsym |= win32_newpath.fs_is_mvfs ();
1475
1476   if (mk_winsym && !win32_newpath.exists ()
1477       && (isdevice || !win32_newpath.fs_is_nfs ()))
1478     {
1479       char *newplnk = tp.c_get ();
1480       stpcpy (stpcpy (newplnk, newpath), ".lnk");
1481       win32_newpath.check (newplnk, check_opt);
1482     }
1483
1484   if (win32_newpath.error)
1485     {
1486       set_errno (win32_newpath.error);
1487       goto done;
1488     }
1489
1490   syscall_printf ("symlink (%s, %S)", oldpath,
1491                   win32_newpath.get_nt_native_path ());
1492
1493   if ((!isdevice && win32_newpath.exists ())
1494       || win32_newpath.is_auto_device ())
1495     {
1496       set_errno (EEXIST);
1497       goto done;
1498     }
1499   if (has_trailing_dirsep && !win32_newpath.exists ())
1500     {
1501       set_errno (ENOENT);
1502       goto done;
1503     }
1504
1505   if (!isdevice && win32_newpath.fs_is_nfs ())
1506     {
1507       /* On NFS, create symlinks by calling NtCreateFile with an EA of type
1508          NfsSymlinkTargetName containing ... the symlink target name. */
1509       PFILE_FULL_EA_INFORMATION pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1510       pffei->NextEntryOffset = 0;
1511       pffei->Flags = 0;
1512       pffei->EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1513       char *EaValue = stpcpy (pffei->EaName, NFS_SYML_TARGET) + 1;
1514       pffei->EaValueLength = sizeof (WCHAR) *
1515         (sys_mbstowcs ((PWCHAR) EaValue, NT_MAX_PATH, oldpath) - 1);
1516       status = NtCreateFile (&fh, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE,
1517                              win32_newpath.get_object_attr (attr, sa),
1518                              &io, NULL, FILE_ATTRIBUTE_SYSTEM,
1519                              FILE_SHARE_VALID_FLAGS, FILE_CREATE,
1520                              FILE_SYNCHRONOUS_IO_NONALERT
1521                              | FILE_OPEN_FOR_BACKUP_INTENT,
1522                              pffei, NT_MAX_PATH * sizeof (WCHAR));
1523       if (!NT_SUCCESS (status))
1524         {
1525           __seterrno_from_nt_status (status);
1526           goto done;
1527         }
1528       NtClose (fh);
1529       res = 0;
1530       goto done;
1531     }
1532
1533   if (mk_winsym)
1534     {
1535       ITEMIDLIST *pidl = NULL;
1536       size_t full_len = 0;
1537       unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
1538       char desc[MAX_PATH + 1], *relpath;
1539
1540       if (!isdevice)
1541         {
1542           /* First create an IDLIST to learn how big our shortcut is
1543              going to be. */
1544           IShellFolder *psl;
1545
1546           /* The symlink target is relative to the directory in which
1547              the symlink gets created, not relative to the cwd.  Therefore
1548              we have to mangle the path quite a bit before calling path_conv. */
1549         if (isabspath (oldpath))
1550           win32_oldpath.check (oldpath,
1551                                PC_SYM_NOFOLLOW,
1552                                stat_suffixes);
1553         else
1554             {
1555               len = strrchr (win32_newpath.normalized_path, '/')
1556                     - win32_newpath.normalized_path + 1;
1557               char *absoldpath = tp.t_get ();
1558               stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
1559                       oldpath);
1560               win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1561             }
1562           if (SUCCEEDED (SHGetDesktopFolder (&psl)))
1563             {
1564               WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
1565               win32_oldpath.get_wide_win32_path (wc_path);
1566               /* Amazing but true:  Even though the ParseDisplayName method
1567                  takes a wide char path name, it does not understand the
1568                  Win32 prefix for long pathnames!  So we have to tack off
1569                  the prefix and convert the path to the "normal" syntax
1570                  for ParseDisplayName.  */
1571               WCHAR *wc = wc_path + 4;
1572               if (wc[1] != L':') /* native UNC path */
1573                 *(wc += 2) = L'\\';
1574               HRESULT res;
1575               if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
1576                                                     &pidl, NULL)))
1577                 {
1578                   ITEMIDLIST *p;
1579
1580                   for (p = pidl; p->mkid.cb > 0;
1581                        p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
1582                     ;
1583                   pidl_len = (char *) p - (char *) pidl + 2;
1584                 }
1585               psl->Release ();
1586             }
1587         }
1588       /* Compute size of shortcut file. */
1589       full_len = sizeof (win_shortcut_hdr);
1590       if (pidl_len)
1591         full_len += sizeof (unsigned short) + pidl_len;
1592       oldpath_len = strlen (oldpath);
1593       /* Unfortunately the length of the description is restricted to a
1594          length of MAX_PATH up to NT4, and to a length of 2000 bytes
1595          since W2K.  We don't want to add considerations for the different
1596          lengths and even 2000 bytes is not enough for long path names.
1597          So what we do here is to set the description to the POSIX path
1598          only if the path is not longer than MAX_PATH characters.  We
1599          append the full path name after the regular shortcut data
1600          (see below), which works fine with Windows Explorer as well
1601          as older Cygwin versions (as long as the whole file isn't bigger
1602          than 8K).  The description field is only used for backward
1603          compatibility to older Cygwin versions and those versions are
1604          not capable of handling long path names anyway. */
1605       desc_len = stpcpy (desc, oldpath_len > MAX_PATH
1606                                ? "[path too long]" : oldpath) - desc;
1607       full_len += sizeof (unsigned short) + desc_len;
1608       /* Devices get the oldpath string unchanged as relative path. */
1609       if (isdevice)
1610         {
1611           relpath_len = oldpath_len;
1612           stpcpy (relpath = tp.c_get (), oldpath);
1613         }
1614       else
1615         {
1616           relpath_len = strlen (win32_oldpath.get_win32 ());
1617           stpcpy (relpath = tp.c_get (), win32_oldpath.get_win32 ());
1618         }
1619       full_len += sizeof (unsigned short) + relpath_len;
1620       full_len += sizeof (unsigned short) + oldpath_len;
1621       /* 1 byte more for trailing 0 written by stpcpy. */
1622       if (full_len < NT_MAX_PATH * sizeof (WCHAR))
1623         buf = (char *) tp.w_get ();
1624       else
1625         buf = (char *) alloca (full_len + 1);
1626
1627       /* Create shortcut header */
1628       win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf;
1629       memset (shortcut_header, 0, sizeof *shortcut_header);
1630       shortcut_header->size = sizeof *shortcut_header;
1631       shortcut_header->magic = GUID_shortcut;
1632       shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH);
1633       if (pidl)
1634         shortcut_header->flags |= WSH_FLAG_IDLIST;
1635       shortcut_header->run = SW_NORMAL;
1636       cp = buf + sizeof (win_shortcut_hdr);
1637
1638       /* Create IDLIST */
1639       if (pidl)
1640         {
1641           *(unsigned short *)cp = pidl_len;
1642           memcpy (cp += 2, pidl, pidl_len);
1643           cp += pidl_len;
1644           CoTaskMemFree (pidl);
1645         }
1646
1647       /* Create description */
1648       *(unsigned short *)cp = desc_len;
1649       cp = stpcpy (cp += 2, desc);
1650
1651       /* Create relpath */
1652       *(unsigned short *)cp = relpath_len;
1653       cp = stpcpy (cp += 2, relpath);
1654
1655       /* Append the POSIX path after the regular shortcut data for
1656          the long path support. */
1657       unsigned short *plen = (unsigned short *) cp;
1658       cp += 2;
1659       *(PWCHAR) cp = 0xfeff;            /* BOM */
1660       cp += 2;
1661       *plen = sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1662       cp += *plen;
1663     }
1664   else
1665     {
1666       /* Default technique creating a symlink. */
1667       buf = (char *) tp.w_get ();
1668       cp = stpcpy (buf, SYMLINK_COOKIE);
1669       *(PWCHAR) cp = 0xfeff;            /* BOM */
1670       cp += 2;
1671       /* Note that the terminating nul is written.  */
1672       cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1673     }
1674
1675   if (isdevice && win32_newpath.exists ())
1676     {
1677       status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
1678                            win32_newpath.get_object_attr (attr, sa),
1679                            &io, 0, FILE_OPEN_FOR_BACKUP_INTENT);
1680       if (!NT_SUCCESS (status))
1681         {
1682           __seterrno_from_nt_status (status);
1683           goto done;
1684         }
1685       status = NtSetAttributesFile (fh, FILE_ATTRIBUTE_NORMAL);
1686       NtClose (fh);
1687       if (!NT_SUCCESS (status))
1688         {
1689           __seterrno_from_nt_status (status);
1690           goto done;
1691         }
1692     }
1693   else if (!isdevice && win32_newpath.has_acls () && !win32_newpath.isremote ())
1694     /* If the filesystem supports ACLs, we will overwrite the DACL after the
1695        call to NtCreateFile.  This requires a handle with READ_CONTROL and
1696        WRITE_DAC access, otherwise get_file_sd and set_file_sd both have to
1697        open the file again.
1698        FIXME: On remote NTFS shares open sometimes fails because even the
1699        creator of the file doesn't have the right to change the DACL.
1700        I don't know what setting that is or how to recognize such a share,
1701        so for now we don't request WRITE_DAC on remote drives. */
1702     access |= READ_CONTROL | WRITE_DAC;
1703
1704   status = NtCreateFile (&fh, access, win32_newpath.get_object_attr (attr, sa),
1705                          &io, NULL, FILE_ATTRIBUTE_NORMAL,
1706                          FILE_SHARE_VALID_FLAGS,
1707                          isdevice ? FILE_OVERWRITE_IF : FILE_CREATE,
1708                          FILE_SYNCHRONOUS_IO_NONALERT
1709                          | FILE_NON_DIRECTORY_FILE
1710                          | FILE_OPEN_FOR_BACKUP_INTENT,
1711                          NULL, 0);
1712   if (!NT_SUCCESS (status))
1713     {
1714       __seterrno_from_nt_status (status);
1715       goto done;
1716     }
1717   if (win32_newpath.has_acls ())
1718     set_file_attribute (fh, win32_newpath, ILLEGAL_UID, ILLEGAL_GID,
1719                         (io.Information == FILE_CREATED ? S_JUSTCREATED : 0)
1720                         | S_IFLNK | STD_RBITS | STD_WBITS);
1721   status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL);
1722   if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf))
1723     {
1724       status = NtSetAttributesFile (fh, mk_winsym ? FILE_ATTRIBUTE_READONLY
1725                                                   : FILE_ATTRIBUTE_SYSTEM);
1726       if (!NT_SUCCESS (status))
1727         debug_printf ("Setting attributes failed, status = %p", status);
1728       res = 0;
1729     }
1730   else
1731     {
1732       __seterrno_from_nt_status (status);
1733       FILE_DISPOSITION_INFORMATION fdi = { TRUE };
1734       status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
1735                                      FileDispositionInformation);
1736       if (!NT_SUCCESS (status))
1737         debug_printf ("Setting delete dispostion failed, status = %p", status);
1738     }
1739   NtClose (fh);
1740
1741 done:
1742   syscall_printf ("%d = symlink_worker(%s, %s, %d, %d)", res, oldpath,
1743                   newpath, mk_winsym, isdevice);
1744   if (has_trailing_dirsep)
1745     free ((void *) newpath);
1746   return res;
1747 }
1748
1749 static bool
1750 cmp_shortcut_header (win_shortcut_hdr *file_header)
1751 {
1752   /* A Cygwin or U/Win shortcut only contains a description and a relpath.
1753      Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
1754      always set to SW_NORMAL. */
1755   return file_header->size == sizeof (win_shortcut_hdr)
1756       && !memcmp (&file_header->magic, &GUID_shortcut, sizeof GUID_shortcut)
1757       && (file_header->flags & ~WSH_FLAG_IDLIST)
1758          == (WSH_FLAG_DESC | WSH_FLAG_RELPATH)
1759       && file_header->run == SW_NORMAL;
1760 }
1761
1762 int
1763 symlink_info::check_shortcut (HANDLE h)
1764 {
1765   tmp_pathbuf tp;
1766   win_shortcut_hdr *file_header;
1767   char *buf, *cp;
1768   unsigned short len;
1769   int res = 0;
1770   NTSTATUS status;
1771   IO_STATUS_BLOCK io;
1772   FILE_STANDARD_INFORMATION fsi;
1773   LARGE_INTEGER off = { QuadPart:0LL };
1774
1775   status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
1776                                    FileStandardInformation);
1777   if (!NT_SUCCESS (status))
1778     {
1779       set_error (EIO);
1780       return 0;
1781     }
1782   if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
1783       || fsi.EndOfFile.QuadPart > 4 * 65536)
1784     return 0;
1785   if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
1786     buf = (char *) tp.w_get ();
1787   else
1788     buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
1789   status = NtReadFile (h, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
1790                        &off, NULL);
1791   if (!NT_SUCCESS (status))
1792     {
1793       if (status != STATUS_END_OF_FILE)
1794         set_error (EIO);
1795       return 0;
1796     }
1797   file_header = (win_shortcut_hdr *) buf;
1798   if (io.Information != fsi.EndOfFile.LowPart
1799       || !cmp_shortcut_header (file_header))
1800     return 0;
1801   cp = buf + sizeof (win_shortcut_hdr);
1802   if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
1803     cp += *(unsigned short *) cp + 2;
1804   if (!(len = *(unsigned short *) cp))
1805     return 0;
1806   cp += 2;
1807   /* Check if this is a device file - these start with the sequence :\\ */
1808   if (strncmp (cp, ":\\", 2) == 0)
1809     res = strlen (strcpy (contents, cp)); /* Don't mess with device files */
1810   else
1811     {
1812       /* Has appended full path?  If so, use it instead of description. */
1813       unsigned short relpath_len = *(unsigned short *) (cp + len);
1814       if (cp + len + 2 + relpath_len < buf + fsi.EndOfFile.LowPart)
1815         {
1816           cp += len + 2 + relpath_len;
1817           len = *(unsigned short *) cp;
1818           cp += 2;
1819         }
1820       if (*(PWCHAR) cp == 0xfeff)       /* BOM */
1821         {
1822           char *tmpbuf = tp.c_get ();
1823           if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2))
1824               > SYMLINK_MAX + 1)
1825             return 0;
1826           res = posixify (tmpbuf);
1827         }
1828       else if (len > SYMLINK_MAX)
1829         return 0;
1830       else
1831         {
1832           cp[len] = '\0';
1833           res = posixify (cp);
1834         }
1835     }
1836   if (res) /* It's a symlink.  */
1837     pflags |= PATH_SYMLINK | PATH_LNK;
1838   return res;
1839 }
1840
1841 int
1842 symlink_info::check_sysfile (HANDLE h)
1843 {
1844   tmp_pathbuf tp;
1845   char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
1846   char *srcbuf = tp.c_get ();
1847   int res = 0;
1848   NTSTATUS status;
1849   IO_STATUS_BLOCK io;
1850   bool interix_symlink = false;
1851   LARGE_INTEGER off = { QuadPart:0LL };
1852
1853   status = NtReadFile (h, NULL, NULL, NULL, &io, cookie_buf,
1854                        sizeof (cookie_buf), &off, NULL);
1855   if (!NT_SUCCESS (status))
1856     {
1857       debug_printf ("ReadFile1 failed %p", status);
1858       if (status != STATUS_END_OF_FILE)
1859         set_error (EIO);
1860       return 0;
1861     }
1862   off.QuadPart = io.Information;
1863   if (io.Information == sizeof (cookie_buf)
1864            && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
1865     {
1866       /* It's a symlink.  */
1867       pflags |= PATH_SYMLINK;
1868     }
1869   else if (io.Information == sizeof (cookie_buf)
1870            && memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
1871     pflags |= PATH_SOCKET;
1872   else if (io.Information >= sizeof (INTERIX_SYMLINK_COOKIE)
1873            && memcmp (cookie_buf, INTERIX_SYMLINK_COOKIE,
1874                       sizeof (INTERIX_SYMLINK_COOKIE) - 1) == 0)
1875     {
1876       /* It's an Interix symlink.  */
1877       pflags |= PATH_SYMLINK;
1878       interix_symlink = true;
1879       /* Interix symlink cookies are shorter than Cygwin symlink cookies, so
1880          in case of an Interix symlink cooky we have read too far into the
1881          file.  Set file pointer back to the position right after the cookie. */
1882       off.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1;
1883     }
1884   if (pflags & PATH_SYMLINK)
1885     {
1886       status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
1887                            NT_MAX_PATH, &off, NULL);
1888       if (!NT_SUCCESS (status))
1889         {
1890           debug_printf ("ReadFile2 failed");
1891           if (status != STATUS_END_OF_FILE)
1892             set_error (EIO);
1893         }
1894       else if (*(PWCHAR) srcbuf == 0xfeff       /* BOM */
1895                || interix_symlink)
1896         {
1897           /* Add trailing 0 to Interix symlink target.  Skip BOM in Cygwin
1898              symlinks. */
1899           if (interix_symlink)
1900             ((PWCHAR) srcbuf)[io.Information / sizeof (WCHAR)] = L'\0';
1901           else
1902             srcbuf += 2;
1903           char *tmpbuf = tp.c_get ();
1904           if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) srcbuf)
1905               > SYMLINK_MAX + 1)
1906             debug_printf ("symlink string too long");
1907           else
1908             res = posixify (tmpbuf);
1909         }
1910       else if (io.Information > SYMLINK_MAX + 1)
1911         debug_printf ("symlink string too long");
1912       else
1913         res = posixify (srcbuf);
1914     }
1915   return res;
1916 }
1917
1918 int
1919 symlink_info::check_reparse_point (HANDLE h)
1920 {
1921   tmp_pathbuf tp;
1922   NTSTATUS status;
1923   IO_STATUS_BLOCK io;
1924   PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) tp.c_get ();
1925   UNICODE_STRING subst;
1926   char srcbuf[SYMLINK_MAX + 7];
1927
1928   status = NtFsControlFile (h, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT,
1929                             NULL, 0, (LPVOID) rp,
1930                             MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1931   if (!NT_SUCCESS (status))
1932     {
1933       debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %p",
1934                     status);
1935       set_error (EIO);
1936       return 0;
1937     }
1938   if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
1939     RtlInitCountedUnicodeString (&subst,
1940                   (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
1941                         + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset),
1942                   rp->SymbolicLinkReparseBuffer.SubstituteNameLength);
1943   else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
1944     {
1945       RtlInitCountedUnicodeString (&subst,
1946                   (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
1947                           + rp->MountPointReparseBuffer.SubstituteNameOffset),
1948                   rp->MountPointReparseBuffer.SubstituteNameLength);
1949       if (RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE))
1950         {
1951           /* Volume mount point.  Not treated as symlink. The return
1952              value of -1 is a hint for the caller to treat this as a
1953              volume mount point. */
1954           return -1;
1955         }
1956     }
1957   else
1958     {
1959       /* Maybe it's a reparse point, but it's certainly not one we
1960          recognize.  Drop the REPARSE file attribute so we don't even
1961          try to use the flag for some special handling.  It's just some
1962          arbitrary file or directory for us. */
1963       fileattr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1964       return 0;
1965     }
1966   sys_wcstombs (srcbuf, SYMLINK_MAX + 7, subst.Buffer,
1967                 subst.Length / sizeof (WCHAR));
1968   pflags |= PATH_SYMLINK | PATH_REP;
1969   /* A symlink is never a directory. */
1970   fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
1971   return posixify (srcbuf);
1972 }
1973
1974 int
1975 symlink_info::check_nfs_symlink (HANDLE h)
1976 {
1977   tmp_pathbuf tp;
1978   NTSTATUS status;
1979   IO_STATUS_BLOCK io;
1980   struct {
1981     FILE_GET_EA_INFORMATION fgei;
1982     char buf[sizeof (NFS_SYML_TARGET)];
1983   } fgei_buf;
1984   PFILE_FULL_EA_INFORMATION pffei;
1985   int res = 0;
1986
1987   /* To find out if the file is a symlink and to get the symlink target,
1988      try to fetch the NfsSymlinkTargetName EA. */
1989   fgei_buf.fgei.NextEntryOffset = 0;
1990   fgei_buf.fgei.EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1991   stpcpy (fgei_buf.fgei.EaName, NFS_SYML_TARGET);
1992   pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1993   status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE,
1994                           &fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
1995   if (NT_SUCCESS (status) && pffei->EaValueLength > 0)
1996     {
1997       PWCHAR spath = (PWCHAR)
1998                      (pffei->EaName + pffei->EaNameLength + 1);
1999       res = sys_wcstombs (contents, SYMLINK_MAX + 1,
2000                           spath, pffei->EaValueLength) - 1;
2001       pflags |= PATH_SYMLINK;
2002     }
2003   return res;
2004 }
2005
2006 int
2007 symlink_info::posixify (char *srcbuf)
2008 {
2009   /* The definition for a path in a native symlink is a bit weird.  The Flags
2010      value seem to contain 0 for absolute paths (stored as NT native path)
2011      and 1 for relative paths.  Relative paths are paths not starting with a
2012      drive letter.  These are not converted to NT native, but stored as
2013      given.  A path starting with a single backslash is relative to the
2014      current drive thus a "relative" value (Flags == 1).
2015      Funny enough it's possible to store paths with slashes instead of
2016      backslashes, but they are evaluated incorrectly by subsequent Windows
2017      calls like CreateFile (ERROR_INVALID_NAME).  So, what we do here is to
2018      take paths starting with slashes at face value, evaluating them as
2019      Cygwin specific POSIX paths.
2020      A path starting with two slashes(!) or backslashes is converted into an
2021      NT UNC path.  Unfortunately, in contrast to POSIX rules, paths starting
2022      with three or more (back)slashes are also converted into UNC paths,
2023      just incorrectly sticking to one redundant leading backslash.  We go
2024      along with this behaviour to avoid scenarios in which native tools access
2025      other files than Cygwin.
2026      The above rules are used exactly the same way on Cygwin specific symlinks
2027      (sysfiles and shortcuts) to eliminate non-POSIX paths in the output. */
2028
2029   /* Eliminate native NT prefixes. */
2030   if (srcbuf[0] == '\\' && !strncmp (srcbuf + 1, "??\\", 3))
2031     {
2032       srcbuf += 4;
2033       if (srcbuf[1] != ':') /* native UNC path */
2034         *(srcbuf += 2) = '\\';
2035     }
2036   if (isdrive (srcbuf))
2037     mount_table->conv_to_posix_path (srcbuf, contents, 0);
2038   else if (srcbuf[0] == '\\')
2039     {
2040       if (srcbuf[1] == '\\') /* UNC path */
2041         slashify (srcbuf, contents, 0);
2042       else /* Paths starting with \ are current drive relative. */
2043         {
2044           char cvtbuf[SYMLINK_MAX + 1];
2045
2046           stpcpy (cvtbuf + cygheap->cwd.get_drive (cvtbuf), srcbuf);
2047           mount_table->conv_to_posix_path (cvtbuf, contents, 0);
2048         }
2049     }
2050   else /* Everything else is taken as is. */
2051     slashify (srcbuf, contents, 0);
2052   return strlen (contents);
2053 }
2054
2055 enum
2056 {
2057   SCAN_BEG,
2058   SCAN_LNK,
2059   SCAN_HASLNK,
2060   SCAN_JUSTCHECK,
2061   SCAN_JUSTCHECKTHIS, /* Never try to append a suffix. */
2062   SCAN_APPENDLNK,
2063   SCAN_EXTRALNK,
2064   SCAN_DONE,
2065 };
2066
2067 class suffix_scan
2068 {
2069   const suffix_info *suffixes, *suffixes_start;
2070   int nextstate;
2071   char *eopath;
2072 public:
2073   const char *path;
2074   char *has (const char *, const suffix_info *);
2075   int next ();
2076   int lnk_match () {return nextstate >= SCAN_APPENDLNK;}
2077 };
2078
2079 char *
2080 suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
2081 {
2082   nextstate = SCAN_BEG;
2083   suffixes = suffixes_start = in_suffixes;
2084
2085   const char *fname = strrchr (in_path, '\\');
2086   fname = fname ? fname + 1 : in_path;
2087   char *ext_here = strrchr (fname, '.');
2088   path = in_path;
2089   eopath = strchr (path, '\0');
2090
2091   if (!ext_here)
2092     goto noext;
2093
2094   if (suffixes)
2095     {
2096       /* Check if the extension matches a known extension */
2097       for (const suffix_info *ex = in_suffixes; ex->name != NULL; ex++)
2098         if (ascii_strcasematch (ext_here, ex->name))
2099           {
2100             nextstate = SCAN_JUSTCHECK;
2101             suffixes = NULL;    /* Has an extension so don't scan for one. */
2102             goto done;
2103           }
2104     }
2105
2106   /* Didn't match.  Use last resort -- .lnk. */
2107   if (ascii_strcasematch (ext_here, ".lnk"))
2108     {
2109       nextstate = SCAN_HASLNK;
2110       suffixes = NULL;
2111     }
2112
2113  noext:
2114   ext_here = eopath;
2115
2116  done:
2117   /* Avoid attaching suffixes if the resulting filename would be invalid. */
2118   if (eopath - fname > NAME_MAX - 4)
2119     {
2120       nextstate = SCAN_JUSTCHECKTHIS;
2121       suffixes = NULL;
2122     }
2123   return ext_here;
2124 }
2125
2126 int
2127 suffix_scan::next ()
2128 {
2129   for (;;)
2130     {
2131       if (!suffixes)
2132         switch (nextstate)
2133           {
2134           case SCAN_BEG:
2135             suffixes = suffixes_start;
2136             if (!suffixes)
2137               {
2138                 nextstate = SCAN_LNK;
2139                 return 1;
2140               }
2141             nextstate = SCAN_EXTRALNK;
2142             /* fall through to suffix checking below */
2143             break;
2144           case SCAN_HASLNK:
2145             nextstate = SCAN_APPENDLNK; /* Skip SCAN_BEG */
2146             return 1;
2147           case SCAN_EXTRALNK:
2148             nextstate = SCAN_DONE;
2149             *eopath = '\0';
2150             return 0;
2151           case SCAN_JUSTCHECK:
2152             nextstate = SCAN_LNK;
2153             return 1;
2154           case SCAN_JUSTCHECKTHIS:
2155             nextstate = SCAN_DONE;
2156             return 1;
2157           case SCAN_LNK:
2158           case SCAN_APPENDLNK:
2159             strcat (eopath, ".lnk");
2160             nextstate = SCAN_DONE;
2161             return 1;
2162           default:
2163             *eopath = '\0';
2164             return 0;
2165           }
2166
2167       while (suffixes && suffixes->name)
2168         if (nextstate == SCAN_EXTRALNK && !suffixes->addon)
2169           suffixes++;
2170         else
2171           {
2172             strcpy (eopath, suffixes->name);
2173             if (nextstate == SCAN_EXTRALNK)
2174               strcat (eopath, ".lnk");
2175             suffixes++;
2176             return 1;
2177           }
2178       suffixes = NULL;
2179     }
2180 }
2181
2182 bool
2183 symlink_info::set_error (int in_errno)
2184 {
2185   bool res;
2186   if (!(pflags & PATH_NO_ACCESS_CHECK) || in_errno == ENAMETOOLONG || in_errno == EIO)
2187     {
2188       error = in_errno;
2189       res = true;
2190     }
2191   else if (in_errno == ENOENT)
2192     res = true;
2193   else
2194     {
2195       fileattr = FILE_ATTRIBUTE_NORMAL;
2196       res = false;
2197     }
2198   return res;
2199 }
2200
2201 bool
2202 symlink_info::parse_device (const char *contents)
2203 {
2204   char *endptr;
2205   _major_t mymajor;
2206   _major_t myminor;
2207   _mode_t mymode;
2208
2209   mymajor = strtol (contents += 2, &endptr, 16);
2210   if (endptr == contents)
2211     return isdevice = false;
2212
2213   contents = endptr;
2214   myminor = strtol (++contents, &endptr, 16);
2215   if (endptr == contents)
2216     return isdevice = false;
2217
2218   contents = endptr;
2219   mymode = strtol (++contents, &endptr, 16);
2220   if (endptr == contents)
2221     return isdevice = false;
2222
2223   if ((mymode & S_IFMT) == S_IFIFO)
2224     {
2225       mymajor = _major (FH_FIFO);
2226       myminor = _minor (FH_FIFO);
2227     }
2228
2229   major = mymajor;
2230   minor = myminor;
2231   mode = mymode;
2232   return isdevice = true;
2233 }
2234
2235 /* Check if PATH is a symlink.  PATH must be a valid Win32 path name.
2236
2237    If PATH is a symlink, put the value of the symlink--the file to
2238    which it points--into BUF.  The value stored in BUF is not
2239    necessarily null terminated.  BUFLEN is the length of BUF; only up
2240    to BUFLEN characters will be stored in BUF.  BUF may be NULL, in
2241    which case nothing will be stored.
2242
2243    Set *SYML if PATH is a symlink.
2244
2245    Set *EXEC if PATH appears to be executable.  This is an efficiency
2246    hack because we sometimes have to open the file anyhow.  *EXEC will
2247    not be set for every executable file.
2248
2249    Return -1 on error, 0 if PATH is not a symlink, or the length
2250    stored into BUF if PATH is a symlink.  */
2251
2252 int
2253 symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs,
2254                      path_conv_handle &conv_hdl)
2255 {
2256   int res;
2257   HANDLE h;
2258   NTSTATUS status;
2259   UNICODE_STRING upath;
2260   OBJECT_ATTRIBUTES attr;
2261   IO_STATUS_BLOCK io;
2262   suffix_scan suffix;
2263
2264   const ULONG ci_flag = cygwin_shared->obcaseinsensitive
2265                         || (pflags & PATH_NOPOSIX) ? OBJ_CASE_INSENSITIVE : 0;
2266   /* TODO: Temporarily do all char->UNICODE conversion here.  This should
2267      already be slightly faster than using Ascii functions. */
2268   tmp_pathbuf tp;
2269   tp.u_get (&upath);
2270   InitializeObjectAttributes (&attr, &upath, ci_flag, NULL, NULL);
2271
2272   /* This label is used in case we encounter a FS which only handles
2273      DOS paths.  See below. */
2274   bool restarted = false;
2275 restart:
2276
2277   h = NULL;
2278   res = 0;
2279   contents[0] = '\0';
2280   issymlink = true;
2281   isdevice = false;
2282   major = 0;
2283   minor = 0;
2284   mode = 0;
2285   pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
2286
2287   ext_here = suffix.has (path, suffixes);
2288   extn = ext_here - path;
2289
2290   PVOID eabuf = &nfs_aol_ffei;
2291   ULONG easize = sizeof nfs_aol_ffei;
2292
2293   bool had_ext = !!*ext_here;
2294   while (suffix.next ())
2295     {
2296       bool no_ea = false;
2297
2298       error = 0;
2299       get_nt_native_path (suffix.path, upath, pflags & PATH_DOS);
2300       if (h)
2301         {
2302           NtClose (h);
2303           h = NULL;
2304         }
2305       /* The EA given to NtCreateFile allows to get a handle to a symlink on
2306          an NFS share, rather than getting a handle to the target of the
2307          symlink (which would spoil the task of this method quite a bit).
2308          Fortunately it's ignored on most other file systems so we don't have
2309          to special case NFS too much. */
2310       status = NtCreateFile (&h,
2311                              READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA,
2312                              &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS,
2313                              FILE_OPEN,
2314                              FILE_OPEN_REPARSE_POINT
2315                              | FILE_OPEN_FOR_BACKUP_INTENT,
2316                              eabuf, easize);
2317       debug_printf ("%p = NtCreateFile (%S)", status, &upath);
2318       /* No right to access EAs or EAs not supported? */
2319       if (!NT_SUCCESS (status)
2320           && (status == STATUS_ACCESS_DENIED
2321               || status == STATUS_EAS_NOT_SUPPORTED
2322               || status == STATUS_NOT_SUPPORTED
2323               || status == STATUS_INVALID_NETWORK_RESPONSE
2324               /* Or a bug in Samba 3.2.x (x <= 7) when accessing a share's
2325                  root dir which has EAs enabled? */
2326               || status == STATUS_INVALID_PARAMETER))
2327         {
2328           no_ea = true;
2329           /* If EAs are not supported, there's no sense to check them again
2330              with suffixes attached.  So we set eabuf/easize to 0 here once. */
2331           if (status == STATUS_EAS_NOT_SUPPORTED
2332               || status == STATUS_NOT_SUPPORTED)
2333             {
2334               eabuf = NULL;
2335               easize = 0;
2336             }
2337           status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2338                                &attr, &io, FILE_SHARE_VALID_FLAGS,
2339                                FILE_OPEN_REPARSE_POINT
2340                                | FILE_OPEN_FOR_BACKUP_INTENT);
2341           debug_printf ("%p = NtOpenFile (no-EAs %S)", status, &upath);
2342         }
2343       if (status == STATUS_OBJECT_NAME_NOT_FOUND)
2344         {
2345           if (ci_flag == 0 && wincap.has_broken_udf ()
2346               && (!fs.inited () || fs.is_udf ()))
2347             {
2348               /* On NT 5.x UDF is broken (at least) in terms of case
2349                  sensitivity.  When trying to open a file case sensitive,
2350                  the file appears to be non-existant.  Another bug is
2351                  described in fs_info::update. */
2352               attr.Attributes = OBJ_CASE_INSENSITIVE;
2353               status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2354                                    &attr, &io, FILE_SHARE_VALID_FLAGS,
2355                                    FILE_OPEN_REPARSE_POINT
2356                                    | FILE_OPEN_FOR_BACKUP_INTENT);
2357               debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath);
2358               attr.Attributes = 0;
2359               if (NT_SUCCESS (status))
2360                 {
2361                   if (!fs.inited ())
2362                     fs.update (&upath, h);
2363                   if (!fs.is_udf ())
2364                     {
2365                       NtClose (h);
2366                       h = NULL;
2367                       status = STATUS_OBJECT_NAME_NOT_FOUND;
2368                     }
2369                 }
2370             }
2371           /* There are filesystems out in the wild (Netapp, NWFS, and others)
2372              which are uncapable of generating pathnames outside the Win32
2373              rules.  That means, filenames on these FSes must not have a
2374              leading space or trailing dots and spaces.  This code snippet
2375              manages them.  I really hope it's streamlined enough not to
2376              slow down normal operation.  This extra check only kicks in if
2377              we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't
2378              already attach a suffix *and* the above special case for UDF
2379              on XP didn't succeeed. */
2380           if (!restarted && !*ext_here && !(pflags & PATH_DOS) && !fs.inited ())
2381             {
2382               /* Check for trailing dot or space or leading space in
2383                  last component. */
2384               char *p = ext_here - 1;
2385               if (*p != '.' && *p != ' ')
2386                 {
2387                   while (*--p != '\\')
2388                     ;
2389                   if (*++p != ' ')
2390                     p = NULL;
2391                 }
2392               if (p)
2393                 {
2394                   /* If so, check if file resides on one of the known broken
2395                      FSes only supporting filenames following DOS rules. */
2396                   if (!fs.inited ())
2397                     fs.update (&upath, NULL);
2398                   if (fs.has_dos_filenames_only ())
2399                     {
2400                       /* If so, try again.  Since we now know the FS, the
2401                          filenames will be tweaked to follow DOS rules via the
2402                          third parameter in the call to get_nt_native_path. */
2403                       pflags |= PATH_DOS;
2404                       restarted = true;
2405                       goto restart;
2406                     }
2407                 }
2408             }
2409         }
2410
2411       if (NT_SUCCESS (status)
2412           /* Check file system while we're having the file open anyway.
2413              This speeds up path_conv noticably (~10%). */
2414           && (fs.inited () || fs.update (&upath, h)))
2415         {
2416           if (fs.is_nfs ())
2417             {
2418               status = nfs_fetch_fattr3 (h, conv_hdl.nfsattr ());
2419               if (NT_SUCCESS (status))
2420                 fileattr = ((conv_hdl.nfsattr ()->type & 7) == NF3DIR)
2421                             ? FILE_ATTRIBUTE_DIRECTORY : 0;
2422             }
2423           else
2424             {
2425               PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2426
2427               /* Netapps don't implement FileNetworkOpenInformation. */
2428               status = fs.is_netapp ()
2429                        ? STATUS_INVALID_PARAMETER
2430                        : NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi,
2431                                                  FileNetworkOpenInformation);
2432               if (status == STATUS_INVALID_PARAMETER
2433                   || status == STATUS_NOT_IMPLEMENTED)
2434                 {
2435                   /* Apart from accessing Netapps, this also occurs when
2436                      accessing SMB share root dirs hosted on NT4
2437                      (STATUS_INVALID_PARAMETER), or when trying to access
2438                      SMB share root dirs from NT4 (STATUS_NOT_IMPLEMENTED). */
2439                   FILE_BASIC_INFORMATION fbi;
2440                   FILE_STANDARD_INFORMATION fsi;
2441
2442                   status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
2443                                                    FileBasicInformation);
2444                   if (NT_SUCCESS (status))
2445                     {
2446                       memcpy (pfnoi, &fbi, 4 * sizeof (LARGE_INTEGER));
2447                       if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fsi,
2448                                                      sizeof fsi,
2449                                                      FileStandardInformation)))
2450                         {
2451                           pfnoi->EndOfFile.QuadPart = fsi.EndOfFile.QuadPart;
2452                           pfnoi->AllocationSize.QuadPart
2453                             = fsi.AllocationSize.QuadPart;
2454                         }
2455                       else
2456                         pfnoi->EndOfFile.QuadPart
2457                           = pfnoi->AllocationSize.QuadPart = 0;
2458                       pfnoi->FileAttributes = fbi.FileAttributes;
2459                     }
2460                 }
2461               if (NT_SUCCESS (status))
2462                 fileattr = pfnoi->FileAttributes;
2463             }
2464         }
2465       if (!NT_SUCCESS (status))
2466         {
2467           debug_printf ("%p = NtQueryInformationFile (%S)", status, &upath);
2468           fileattr = INVALID_FILE_ATTRIBUTES;
2469
2470           /* One of the inner path components is invalid, or the path contains
2471              invalid characters.  Bail out with ENOENT.
2472
2473              Note that additional STATUS_OBJECT_PATH_INVALID and
2474              STATUS_OBJECT_PATH_SYNTAX_BAD status codes exist.  The first one
2475              is seemingly not generated by NtQueryInformationFile, the latter
2476              is only generated if the path is no absolute path within the
2477              NT name space, which should not happen and would point to an
2478              error in get_nt_native_path.  Both status codes are deliberately
2479              not tested here unless proved necessary. */
2480           if (status == STATUS_OBJECT_PATH_NOT_FOUND
2481               || status == STATUS_OBJECT_NAME_INVALID
2482               || status == STATUS_BAD_NETWORK_PATH
2483               || status == STATUS_BAD_NETWORK_NAME
2484               || status == STATUS_NO_MEDIA_IN_DEVICE)
2485             {
2486               set_error (ENOENT);
2487               goto file_not_symlink;
2488             }
2489           if (status != STATUS_OBJECT_NAME_NOT_FOUND
2490               && status != STATUS_NO_SUCH_FILE) /* ENOENT on NFS or 9x share */
2491             {
2492               /* The file exists, but the user can't access it for one reason
2493                  or the other.  To get the file attributes we try to access the
2494                  information by opening the parent directory and getting the
2495                  file attributes using a matching NtQueryDirectoryFile call. */
2496               UNICODE_STRING dirname, basename;
2497               OBJECT_ATTRIBUTES dattr;
2498               HANDLE dir;
2499               struct {
2500                 FILE_BOTH_DIRECTORY_INFORMATION fdi;
2501                 WCHAR dummy_buf[NAME_MAX + 1];
2502               } fdi_buf;
2503
2504               RtlSplitUnicodePath (&upath, &dirname, &basename);
2505               InitializeObjectAttributes (&dattr, &dirname, ci_flag,
2506                                           NULL, NULL);
2507               status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
2508                                    &dattr, &io, FILE_SHARE_VALID_FLAGS,
2509                                    FILE_SYNCHRONOUS_IO_NONALERT
2510                                    | FILE_OPEN_FOR_BACKUP_INTENT
2511                                    | FILE_DIRECTORY_FILE);
2512               if (!NT_SUCCESS (status))
2513                 {
2514                   debug_printf ("%p = NtOpenFile(%S)", status, &dirname);
2515                   /* There's a special case if the file is itself the root
2516                      of a drive which is not accessible by the current user.
2517                      This case is only recognized by the length of the
2518                      basename part.  If it's 0, the incoming file is the
2519                      root of a drive.  So we at least know it's a directory. */
2520                   fileattr = basename.Length ? 0 : FILE_ATTRIBUTE_DIRECTORY;
2521                 }
2522               else
2523                 {
2524                   status = NtQueryDirectoryFile (dir, NULL, NULL, NULL, &io,
2525                                                  &fdi_buf, sizeof fdi_buf,
2526                                                  FileBothDirectoryInformation,
2527                                                  TRUE, &basename, TRUE);
2528                   /* Take the opportunity to check file system while we're
2529                      having the handle to the parent dir. */
2530                   fs.update (&upath, dir);
2531                   NtClose (dir);
2532                   if (!NT_SUCCESS (status))
2533                     {
2534                       debug_printf ("%p = NtQueryDirectoryFile(%S)",
2535                                     status, &dirname);
2536                       if (status == STATUS_NO_SUCH_FILE)
2537                         {
2538                           /* This can happen when trying to access files
2539                              which match DOS device names on SMB shares.
2540                              NtOpenFile failed with STATUS_ACCESS_DENIED,
2541                              but the NtQueryDirectoryFile tells us the
2542                              file doesn't exist.  We're suspicious in this
2543                              case and retry with the next suffix instead of
2544                              just giving up. */
2545                           set_error (ENOENT);
2546                           continue;
2547                         }
2548                       fileattr = 0;
2549                     }
2550                   else
2551                     {
2552                       PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2553
2554                       fileattr = fdi_buf.fdi.FileAttributes;
2555                       memcpy (pfnoi, &fdi_buf.fdi.CreationTime, sizeof *pfnoi);
2556                       /* Amazing, but true:  The FILE_NETWORK_OPEN_INFORMATION
2557                          structure has the AllocationSize and EndOfFile members
2558                          interchanged relative to the directory information
2559                          classes. */
2560                       pfnoi->AllocationSize.QuadPart
2561                         = fdi_buf.fdi.AllocationSize.QuadPart;
2562                       pfnoi->EndOfFile.QuadPart
2563                         = fdi_buf.fdi.EndOfFile.QuadPart;
2564                     }
2565                 }
2566               ext_tacked_on = !!*ext_here;
2567               goto file_not_symlink;
2568             }
2569           set_error (ENOENT);
2570           continue;
2571         }
2572
2573       ext_tacked_on = !!*ext_here;
2574       /* Don't allow to returns directories with appended suffix.  If we found
2575          a directory with a suffix which has been appended here, then this
2576          directory doesn't match the request.  So, just do as usual if file
2577          hasn't been found. */
2578       if (ext_tacked_on && !had_ext && (fileattr & FILE_ATTRIBUTE_DIRECTORY))
2579         {
2580           set_error (ENOENT);
2581           continue;
2582         }
2583
2584       res = -1;
2585
2586       /* Reparse points are potentially symlinks.  This check must be
2587          performed before checking the SYSTEM attribute for sysfile
2588          symlinks, since reparse points can have this flag set, too.
2589          For instance, Vista starts to create a couple of reparse points
2590          with SYSTEM and HIDDEN flags set. */
2591       if ((fileattr & FILE_ATTRIBUTE_REPARSE_POINT))
2592         {
2593           /* Don't check reparse points on remote filesystems.  A reparse point
2594              pointing to another file on the remote system will be mistreated
2595              as pointing to a local file on the local system.  This breaks the
2596              way reparse points are transparently handled on remote systems. */
2597           if (fs.is_remote_drive())
2598             res = 0;
2599           else
2600             res = check_reparse_point (h);
2601           if (res == -1)
2602             {
2603               /* Volume mount point.  The filesystem information for the top
2604                  level directory should be for the volume top level directory,
2605                  rather than for the reparse point itself.  So we fetch the
2606                  filesystem information again, but with a NULL handle.
2607                  This does what we want because fs_info::update opens the
2608                  handle without FILE_OPEN_REPARSE_POINT. */
2609               fs.update (&upath, NULL);
2610               /* Make sure the open handle is not used in later stat calls.
2611                  The handle has been opened with the FILE_OPEN_REPARSE_POINT
2612                  flag, so it's a handle to the reparse point, not a handle
2613                  to the volumes root dir. */
2614               pflags &= ~PC_KEEP_HANDLE;
2615             }
2616           else if (res)
2617             {
2618               /* A symlink is never a directory. */
2619               conv_hdl.fnoi ()->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
2620               break;
2621             }
2622         }
2623
2624       /* Windows shortcuts are potentially treated as symlinks.  Valid Cygwin
2625          & U/WIN shortcuts are R/O, but definitely not directories. */
2626       else if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
2627           == FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
2628         {
2629           HANDLE sym_h;
2630
2631           status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2632                                FILE_SHARE_VALID_FLAGS,
2633                                FILE_OPEN_FOR_BACKUP_INTENT
2634                                | FILE_SYNCHRONOUS_IO_NONALERT);
2635           if (!NT_SUCCESS (status))
2636             res = 0;
2637           else
2638             {
2639               res = check_shortcut (sym_h);
2640               NtClose (sym_h);
2641             }
2642           if (!res)
2643             {
2644               /* If searching for `foo' and then finding a `foo.lnk' which
2645                  is no shortcut, return the same as if file not found. */
2646               if (ext_tacked_on)
2647                 {
2648                   fileattr = INVALID_FILE_ATTRIBUTES;
2649                   set_error (ENOENT);
2650                   continue;
2651                 }
2652             }
2653           else if (contents[0] != ':' || contents[1] != '\\'
2654                    || !parse_device (contents))
2655             break;
2656         }
2657
2658       /* If searching for `foo' and then finding a `foo.lnk' which is
2659          no shortcut, return the same as if file not found. */
2660       else if (suffix.lnk_match () && ext_tacked_on)
2661         {
2662           fileattr = INVALID_FILE_ATTRIBUTES;
2663           set_error (ENOENT);
2664           continue;
2665         }
2666
2667       /* This is the old Cygwin method creating symlinks.  A symlink will
2668          have the `system' file attribute.  Only files can be symlinks
2669          (which can be symlinks to directories). */
2670       else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))
2671                == FILE_ATTRIBUTE_SYSTEM)
2672         {
2673           HANDLE sym_h;
2674
2675           status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2676                                FILE_SHARE_VALID_FLAGS,
2677                                FILE_OPEN_FOR_BACKUP_INTENT
2678                                | FILE_SYNCHRONOUS_IO_NONALERT);
2679
2680           if (!NT_SUCCESS (status))
2681             res = 0;
2682           else
2683             {
2684               res = check_sysfile (sym_h);
2685               NtClose (sym_h);
2686             }
2687           if (res)
2688             break;
2689         }
2690
2691       /* If the file is on an NFS share and could be opened with extended
2692          attributes, check if it's a symlink.  Only files can be symlinks
2693          (which can be symlinks to directories). */
2694       else if (fs.is_nfs () && (conv_hdl.nfsattr ()->type & 7) == NF3LNK)
2695         {
2696           res = check_nfs_symlink (h);
2697           if (res)
2698             break;
2699         }
2700
2701     /* Normal file. */
2702     file_not_symlink:
2703       issymlink = false;
2704       syscall_printf ("%s", isdevice ? "is a device" : "not a symlink");
2705       res = 0;
2706       break;
2707     }
2708
2709   if (h)
2710     {
2711       if (pflags & PC_KEEP_HANDLE)
2712         conv_hdl.set (h);
2713       else
2714         NtClose (h);
2715     }
2716
2717   syscall_printf ("%d = symlink.check(%s, %p) (%p)",
2718                   res, suffix.path, contents, pflags);
2719   return res;
2720 }
2721
2722 /* "path" is the path in a virtual symlink.  Set a symlink_info struct from
2723    that and proceed with further path checking afterwards. */
2724 int
2725 symlink_info::set (char *path)
2726 {
2727   strcpy (contents, path);
2728   pflags = PATH_SYMLINK;
2729   fileattr = FILE_ATTRIBUTE_NORMAL;
2730   error = 0;
2731   issymlink = true;
2732   isdevice = false;
2733   ext_tacked_on = false;
2734   ext_here = NULL;
2735   extn = major = minor = mode = 0;
2736   return strlen (path);
2737 }
2738
2739 /* readlink system call */
2740
2741 extern "C" ssize_t
2742 readlink (const char *path, char *buf, size_t buflen)
2743 {
2744   if (buflen < 0)
2745     {
2746       set_errno (ENAMETOOLONG);
2747       return -1;
2748     }
2749
2750   path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2751
2752   if (pathbuf.error)
2753     {
2754       set_errno (pathbuf.error);
2755       syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2756       return -1;
2757     }
2758
2759   if (!pathbuf.exists ())
2760     {
2761       set_errno (ENOENT);
2762       return -1;
2763     }
2764
2765   if (!pathbuf.issymlink ())
2766     {
2767       if (pathbuf.exists ())
2768         set_errno (EINVAL);
2769       return -1;
2770     }
2771
2772   ssize_t len = min (buflen, strlen (pathbuf.get_win32 ()));
2773   memcpy (buf, pathbuf.get_win32 (), len);
2774
2775   /* errno set by symlink.check if error */
2776   return len;
2777 }
2778
2779 /* Some programs rely on st_dev/st_ino being unique for each file.
2780    Hash the path name and hope for the best.  The hash arg is not
2781    always initialized to zero since readdir needs to compute the
2782    dirent ino_t based on a combination of the hash of the directory
2783    done during the opendir call and the hash or the filename within
2784    the directory.  FIXME: Not bullet-proof. */
2785 /* Cygwin internal */
2786 __ino64_t __stdcall
2787 hash_path_name (__ino64_t hash, PUNICODE_STRING name)
2788 {
2789   if (name->Length == 0)
2790     return hash;
2791
2792   /* Build up hash. Name is already normalized */
2793   USHORT len = name->Length / sizeof (WCHAR);
2794   for (USHORT idx = 0; idx < len; ++idx)
2795     hash = RtlUpcaseUnicodeChar (name->Buffer[idx])
2796            + (hash << 6) + (hash << 16) - hash;
2797   return hash;
2798 }
2799
2800 __ino64_t __stdcall
2801 hash_path_name (__ino64_t hash, PCWSTR name)
2802 {
2803   UNICODE_STRING uname;
2804   RtlInitUnicodeString (&uname, name);
2805   return hash_path_name (hash, &uname);
2806 }
2807
2808 __ino64_t __stdcall
2809 hash_path_name (__ino64_t hash, const char *name)
2810 {
2811   UNICODE_STRING uname;
2812   RtlCreateUnicodeStringFromAsciiz (&uname, name);
2813   __ino64_t ret = hash_path_name (hash, &uname);
2814   RtlFreeUnicodeString (&uname);
2815   return ret;
2816 }
2817
2818 extern "C" char *
2819 getcwd (char *buf, size_t ulen)
2820 {
2821   char* res = NULL;
2822   myfault efault;
2823   if (efault.faulted (EFAULT))
2824       /* errno set */;
2825   else if (ulen == 0 && buf)
2826     set_errno (EINVAL);
2827   else
2828     res = cygheap->cwd.get (buf, 1, 1, ulen);
2829   return res;
2830 }
2831
2832 /* getwd: Legacy. */
2833 extern "C" char *
2834 getwd (char *buf)
2835 {
2836   return getcwd (buf, PATH_MAX + 1);  /*Per SuSv3!*/
2837 }
2838
2839 /* chdir: POSIX 5.2.1.1 */
2840 extern "C" int
2841 chdir (const char *in_dir)
2842 {
2843   myfault efault;
2844   if (efault.faulted (EFAULT))
2845     return -1;
2846   if (!*in_dir)
2847     {
2848       set_errno (ENOENT);
2849       return -1;
2850     }
2851
2852   syscall_printf ("dir '%s'", in_dir);
2853
2854   /* Convert path.  First argument ensures that we don't check for NULL/empty/invalid
2855      again. */
2856   path_conv path (PC_NONULLEMPTY, in_dir, PC_SYM_FOLLOW | PC_POSIX);
2857   if (path.error)
2858     {
2859       set_errno (path.error);
2860       syscall_printf ("-1 = chdir (%s)", in_dir);
2861       return -1;
2862     }
2863
2864   int res = -1;
2865   const char *posix_cwd = NULL;
2866   int devn = path.get_devn ();
2867   if (!path.exists ())
2868     set_errno (ENOENT);
2869   else if (!path.isdir ())
2870     set_errno (ENOTDIR);
2871   else if (!isvirtual_dev (devn))
2872     {
2873       /* The sequence chdir("xx"); chdir(".."); must be a noop if xx
2874          is not a symlink. This is exploited by find.exe.
2875          The posix_cwd is just path.normalized_path.
2876          In other cases we let cwd.set obtain the Posix path through
2877          the mount table. */
2878       if (!isdrive(path.normalized_path))
2879         posix_cwd = path.normalized_path;
2880       res = 0;
2881     }
2882   else
2883    {
2884      posix_cwd = path.normalized_path;
2885      res = 0;
2886    }
2887
2888   if (!res)
2889     res = cygheap->cwd.set (&path, posix_cwd);
2890
2891   /* Note that we're accessing cwd.posix without a lock here.  I didn't think
2892      it was worth locking just for strace. */
2893   syscall_printf ("%R = chdir() cygheap->cwd.posix '%s' native '%S'", res,
2894                   cygheap->cwd.get_posix (), path.get_nt_native_path ());
2895   MALLOC_CHECK;
2896   return res;
2897 }
2898
2899 extern "C" int
2900 fchdir (int fd)
2901 {
2902   int res;
2903   cygheap_fdget cfd (fd);
2904   if (cfd >= 0)
2905     res = chdir (cfd->get_name ());
2906   else
2907     res = -1;
2908
2909   syscall_printf ("%R = fchdir(%d)", res, fd);
2910   return res;
2911 }
2912
2913 /******************** Exported Path Routines *********************/
2914
2915 /* Cover functions to the path conversion routines.
2916    These are exported to the world as cygwin_foo by cygwin.din.  */
2917
2918 #define return_with_errno(x) \
2919   do {\
2920     int err = (x);\
2921     if (!err)\
2922      return 0;\
2923     set_errno (err);\
2924     return -1;\
2925   } while (0)
2926
2927 extern "C" ssize_t
2928 cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to,
2929                   size_t size)
2930 {
2931   tmp_pathbuf tp;
2932   myfault efault;
2933   if (efault.faulted (EFAULT))
2934     return -1;
2935
2936   path_conv p;
2937   size_t lsiz = 0;
2938   char *buf = NULL;
2939   PWCHAR path = NULL;
2940   int error = 0;
2941   bool relative = !!(what & CCP_RELATIVE);
2942   what &= ~CCP_RELATIVE;
2943
2944   switch (what)
2945     {
2946     case CCP_POSIX_TO_WIN_A:
2947       {
2948         p.check ((const char *) from,
2949                  PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2950                  | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2951         if (p.error)
2952           return_with_errno (p.error);
2953         PUNICODE_STRING up = p.get_nt_native_path ();
2954         buf = tp.c_get ();
2955         UINT cp = AreFileApisANSI () ? CP_ACP : CP_OEMCP;
2956         int len = WideCharToMultiByte (cp, WC_NO_BEST_FIT_CHARS,
2957                                        up->Buffer, up->Length / sizeof (WCHAR),
2958                                        buf, NT_MAX_PATH, NULL, NULL);
2959         buf[len] = '\0';
2960         /* Convert native path to standard DOS path. */
2961         if (!strncmp (buf, "\\??\\", 4))
2962           {
2963             buf += 4;
2964             if (buf[1] != ':') /* native UNC path */
2965               *(buf += 2) = '\\';
2966           }
2967         else if (*buf == '\\')
2968           {
2969             /* Device name points to somewhere else in the NT namespace.
2970                Use GLOBALROOT prefix to convert to Win32 path. */
2971             char *p = buf + WideCharToMultiByte (cp, WC_NO_BEST_FIT_CHARS,
2972                                        ro_u_globalroot.Buffer,
2973                                        ro_u_globalroot.Length / sizeof (WCHAR),
2974                                        buf, NT_MAX_PATH, NULL, NULL);
2975             len = WideCharToMultiByte (cp, WC_NO_BEST_FIT_CHARS,
2976                                        up->Buffer, up->Length / sizeof (WCHAR),
2977                                        p, NT_MAX_PATH - (p - buf), NULL, NULL);
2978             p[len] = '\0';
2979           }
2980         lsiz = strlen (buf) + 1;
2981         /* TODO: Incoming "." is a special case which leads to a trailing
2982            backslash ".\\" in the Win32 path.  That's a result of the
2983            conversion in normalize_posix_path.  This should not occur
2984            so the below code is just a band-aid. */
2985         if (relative && !strcmp ((const char *) from, ".")
2986             && !strcmp (buf, ".\\"))
2987           {
2988             lsiz = 2;
2989             buf[1] = '\0';
2990           }
2991       }
2992       break;
2993     case CCP_POSIX_TO_WIN_W:
2994       p.check ((const char *) from,
2995                PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2996                | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2997       if (p.error)
2998         return_with_errno (p.error);
2999       /* Relative Windows paths are always restricted to MAX_PATH chars. */
3000       if (relative && !isabspath (p.get_win32 ())
3001           && sys_mbstowcs (NULL, 0, p.get_win32 ()) > MAX_PATH)
3002         {
3003           /* Recreate as absolute path. */
3004           p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW
3005                                         | PC_NO_ACCESS_CHECK | PC_NOWARN);
3006           if (p.error)
3007             return_with_errno (p.error);
3008         }
3009       lsiz = p.get_wide_win32_path_len () + 1;
3010       path = p.get_nt_native_path ()->Buffer;
3011
3012       /* Convert native path to standard DOS path. */
3013       if (!wcsncmp (path, L"\\??\\", 4))
3014         {
3015           path[1] = L'\\';
3016
3017           /* Drop long path prefix for short pathnames.  Unfortunately there's
3018              quite a bunch of Win32 functions, especially in user32.dll,
3019              apparently, which don't grok long path names at all, not even
3020              in the UNICODE API. */
3021           if ((path[5] == L':' && lsiz <= MAX_PATH + 4)
3022               || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6))
3023             {
3024               path += 4;
3025               lsiz -= 4;
3026               if (path[1] != L':')
3027                 {
3028                   *(path += 2) = '\\';
3029                   lsiz -= 2;
3030                 }
3031             }
3032         }
3033       else if (*path == L'\\')
3034         {
3035           /* Device name points to somewhere else in the NT namespace.
3036              Use GLOBALROOT prefix to convert to Win32 path. */
3037           to = (void *) wcpcpy ((wchar_t *) to, ro_u_globalroot.Buffer);
3038           lsiz += ro_u_globalroot.Length / sizeof (WCHAR);
3039         }
3040       /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */
3041       if (relative && !strcmp ((const char *) from, ".")
3042           && !wcscmp (path, L".\\"))
3043         {
3044           lsiz = 2;
3045           path[1] = L'\0';
3046         }
3047       lsiz *= sizeof (WCHAR);
3048       break;
3049     case CCP_WIN_A_TO_POSIX:
3050       {
3051         UINT cp = AreFileApisANSI () ? CP_ACP : CP_OEMCP;
3052         PWCHAR wbuf = tp.w_get ();
3053         MultiByteToWideChar (cp, 0, (const char *) from, -1, wbuf, NT_MAX_PATH);
3054         buf = tp.c_get ();
3055         error = mount_table->conv_to_posix_path (wbuf, buf, relative);
3056         if (error)
3057           return_with_errno (error);
3058         lsiz = strlen (buf) + 1;
3059       }
3060       break;
3061     case CCP_WIN_W_TO_POSIX:
3062       buf = tp.c_get ();
3063       error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf,
3064                                                relative);
3065       if (error)
3066         return_with_errno (error);
3067       lsiz = strlen (buf) + 1;
3068       break;
3069     default:
3070       set_errno (EINVAL);
3071       return -1;
3072     }
3073   if (!size)
3074     return lsiz;
3075   if (size < lsiz)
3076     {
3077       set_errno (ENOSPC);
3078       return -1;
3079     }
3080   switch (what)
3081     {
3082     case CCP_POSIX_TO_WIN_A:
3083     case CCP_WIN_A_TO_POSIX:
3084     case CCP_WIN_W_TO_POSIX:
3085       stpcpy ((char *) to, buf);
3086       break;
3087     case CCP_POSIX_TO_WIN_W:
3088       wcpcpy ((PWCHAR) to, path);
3089       break;
3090     }
3091   return 0;
3092 }
3093
3094 extern "C" void *
3095 cygwin_create_path (cygwin_conv_path_t what, const void *from)
3096 {
3097   void *to;
3098   ssize_t size = cygwin_conv_path (what, from, NULL, 0);
3099   if (size <= 0)
3100     to = NULL;
3101   else if (!(to = malloc (size)))
3102     to = NULL;
3103   if (cygwin_conv_path (what, from, to, size) == -1)
3104     {
3105       free (to);
3106       to = NULL;
3107     }
3108   return to;
3109 }
3110
3111
3112 extern "C" int
3113 cygwin_conv_to_win32_path (const char *path, char *win32_path)
3114 {
3115   return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, path, win32_path,
3116                            MAX_PATH);
3117 }
3118
3119 extern "C" int
3120 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
3121 {
3122   return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path, win32_path,
3123                            MAX_PATH);
3124 }
3125
3126 /* This is exported to the world as cygwin_foo by cygwin.din.  */
3127
3128 extern "C" int
3129 cygwin_conv_to_posix_path (const char *path, char *posix_path)
3130 {
3131   return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, path, posix_path,
3132                            MAX_PATH);
3133 }
3134
3135 extern "C" int
3136 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
3137 {
3138   return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, path, posix_path,
3139                            MAX_PATH);
3140 }
3141
3142 /* The realpath function is required by POSIX:2008.  */
3143
3144 extern "C" char *
3145 realpath (const char *path, char *resolved)
3146 {
3147   /* Make sure the right errno is returned if path is NULL. */
3148   if (!path)
3149     {
3150       set_errno (EINVAL);
3151       return NULL;
3152     }
3153
3154   /* Guard reading from a potentially invalid path and writing to a
3155      potentially invalid resolved. */
3156   tmp_pathbuf tp;
3157   myfault efault;
3158   if (efault.faulted (EFAULT))
3159     return NULL;
3160
3161   char *tpath;
3162   if (isdrive (path))
3163     {
3164       tpath = tp.c_get ();
3165       mount_table->cygdrive_posix_path (path, tpath, 0);
3166     }
3167   else
3168     tpath = (char *) path;
3169
3170   path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
3171
3172
3173   /* POSIX 2008 requires malloc'ing if resolved is NULL, and states
3174      that using non-NULL resolved is asking for portability
3175      problems.  */
3176
3177   if (!real_path.error && real_path.exists ())
3178     {
3179       if (!resolved)
3180         {
3181           resolved = (char *) malloc (strlen (real_path.normalized_path) + 1);
3182           if (!resolved)
3183             return NULL;
3184         }
3185       strcpy (resolved, real_path.normalized_path);
3186       return resolved;
3187     }
3188
3189   /* FIXME: on error, Linux puts the name of the path
3190      component which could not be resolved into RESOLVED, but POSIX
3191      does not require this.  */
3192   if (resolved)
3193     resolved[0] = '\0';
3194   set_errno (real_path.error ?: ENOENT);
3195   return NULL;
3196 }
3197
3198 /* Linux provides this extension.  Since the only portable use of
3199    realpath requires a NULL second argument, we might as well have a
3200    one-argument wrapper.  */
3201 extern "C" char *
3202 canonicalize_file_name (const char *path)
3203 {
3204   return realpath (path, NULL);
3205 }
3206
3207 /* Return non-zero if path is a POSIX path list.
3208    This is exported to the world as cygwin_foo by cygwin.din.
3209
3210 DOCTOOL-START
3211 <sect1 id="add-func-cygwin-posix-path-list-p">
3212   <para>Rather than use a mode to say what the "proper" path list
3213   format is, we allow any, and give apps the tools they need to
3214   convert between the two.  If a ';' is present in the path list it's
3215   a Win32 path list.  Otherwise, if the first path begins with
3216   [letter]: (in which case it can be the only element since if it
3217   wasn't a ';' would be present) it's a Win32 path list.  Otherwise,
3218   it's a POSIX path list.</para>
3219 </sect1>
3220 DOCTOOL-END
3221   */
3222
3223 extern "C" int
3224 cygwin_posix_path_list_p (const char *path)
3225 {
3226   int posix_p = !(strchr (path, ';') || isdrive (path));
3227   return posix_p;
3228 }
3229
3230 /* These are used for apps that need to convert env vars like PATH back and
3231    forth.  The conversion is a two step process.  First, an upper bound on the
3232    size of the buffer needed is computed.  Then the conversion is done.  This
3233    allows the caller to use alloca if it wants.  */
3234
3235 static int
3236 conv_path_list_buf_size (const char *path_list, bool to_posix)
3237 {
3238   int i, num_elms, max_mount_path_len, size;
3239   const char *p;
3240
3241   path_conv pc(".", PC_POSIX);
3242   /* The theory is that an upper bound is
3243      current_size + (num_elms * max_mount_path_len)  */
3244   /* FIXME: This method is questionable in the long run. */
3245
3246   unsigned nrel;
3247   char delim = to_posix ? ';' : ':';
3248   for (p = path_list, num_elms = nrel = 0; p; num_elms++)
3249     {
3250       if (!isabspath (p))
3251         nrel++;
3252       p = strchr (++p, delim);
3253     }
3254
3255   /* 7: strlen ("//c") + slop, a conservative initial value */
3256   for (max_mount_path_len = sizeof ("/cygdrive/X"), i = 0;
3257        i < mount_table->nmounts; i++)
3258     {
3259       int mount_len = (to_posix
3260                        ? mount_table->mount[i].posix_pathlen
3261                        : mount_table->mount[i].native_pathlen);
3262       if (max_mount_path_len < mount_len)
3263         max_mount_path_len = mount_len;
3264     }
3265
3266   /* 100: slop */
3267   size = strlen (path_list)
3268     + (num_elms * max_mount_path_len)
3269     + (nrel * strlen (to_posix ? pc.normalized_path : pc.get_win32 ()))
3270     + 100;
3271
3272   return size;
3273 }
3274
3275
3276 extern "C" int
3277 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
3278 {
3279   return conv_path_list_buf_size (path_list, true);
3280 }
3281
3282 extern "C" int
3283 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
3284 {
3285   return conv_path_list_buf_size (path_list, false);
3286 }
3287
3288 extern "C" ssize_t
3289 env_PATH_to_posix (const void *win32, void *posix, size_t size)
3290 {
3291   return_with_errno (conv_path_list ((const char *) win32, (char *) posix,
3292                                      size, ENV_CVT));
3293 }
3294
3295 extern "C" int
3296 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
3297 {
3298   return_with_errno (conv_path_list (win32, posix, MAX_PATH,
3299                      CCP_WIN_A_TO_POSIX | CCP_RELATIVE));
3300 }
3301
3302 extern "C" int
3303 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
3304 {
3305   return_with_errno (conv_path_list (posix, win32, MAX_PATH,
3306                      CCP_POSIX_TO_WIN_A | CCP_RELATIVE));
3307 }
3308
3309 extern "C" ssize_t
3310 cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
3311                        size_t size)
3312 {
3313   int ret;
3314   char *winp = NULL;
3315   void *orig_to = NULL;
3316   size_t orig_size = (size_t) -1;
3317   tmp_pathbuf tp;
3318
3319   switch (what & CCP_CONVTYPE_MASK)
3320     {
3321     case CCP_WIN_W_TO_POSIX:
3322       if (!sys_wcstombs_alloc (&winp, HEAP_NOTHEAP, (const wchar_t *) from,
3323                                (size_t) -1))
3324         return -1;
3325       what = (what & ~CCP_CONVTYPE_MASK) | CCP_WIN_A_TO_POSIX;
3326       from = (const void *) winp;
3327       break;
3328     case CCP_POSIX_TO_WIN_W:
3329       if (size == 0)
3330         return conv_path_list_buf_size ((const char *) from, 0)
3331                * sizeof (WCHAR);
3332       what = (what & ~CCP_CONVTYPE_MASK) | CCP_POSIX_TO_WIN_A;
3333       orig_to = to;
3334       orig_size = size;
3335       to = (void *) tp.w_get ();
3336       size = 65536;
3337       break;
3338     }
3339   switch (what & CCP_CONVTYPE_MASK)
3340     {
3341     case CCP_WIN_A_TO_POSIX:
3342     case CCP_POSIX_TO_WIN_A:
3343       if (size == 0)
3344         return conv_path_list_buf_size ((const char *) from,
3345                                         what == CCP_WIN_A_TO_POSIX);
3346       ret = conv_path_list ((const char *) from, (char *) to, size, what);
3347       /* Free winp buffer in case of CCP_WIN_W_TO_POSIX. */
3348       if (winp)
3349         free (winp);
3350       /* Convert to WCHAR in case of CCP_POSIX_TO_WIN_W. */
3351       if (orig_to)
3352         sys_mbstowcs ((wchar_t *) orig_to, size / sizeof (WCHAR),
3353                       (const char *) to, (size_t) -1);
3354       return_with_errno (ret);
3355       break;
3356     default:
3357       break;
3358     }
3359   set_errno (EINVAL);
3360   return -1;
3361 }
3362
3363 /* cygwin_split_path: Split a path into directory and file name parts.
3364    Buffers DIR and FILE are assumed to be big enough.
3365
3366    Examples (path -> `dir' / `file'):
3367    / -> `/' / `'
3368    "" -> `.' / `'
3369    . -> `.' / `.' (FIXME: should this be `.' / `'?)
3370    .. -> `.' / `..' (FIXME: should this be `..' / `'?)
3371    foo -> `.' / `foo'
3372    foo/bar -> `foo' / `bar'
3373    foo/bar/ -> `foo' / `bar'
3374    /foo -> `/' / `foo'
3375    /foo/bar -> `/foo' / `bar'
3376    c: -> `c:/' / `'
3377    c:/ -> `c:/' / `'
3378    c:foo -> `c:/' / `foo'
3379    c:/foo -> `c:/' / `foo'
3380  */
3381
3382 extern "C" void
3383 cygwin_split_path (const char *path, char *dir, char *file)
3384 {
3385   int dir_started_p = 0;
3386
3387   /* Deal with drives.
3388      Remember that c:foo <==> c:/foo.  */
3389   if (isdrive (path))
3390     {
3391       *dir++ = *path++;
3392       *dir++ = *path++;
3393       *dir++ = '/';
3394       if (!*path)
3395         {
3396           *dir = 0;
3397           *file = 0;
3398           return;
3399         }
3400       if (isdirsep (*path))
3401         ++path;
3402       dir_started_p = 1;
3403     }
3404
3405   /* Determine if there are trailing slashes and "delete" them if present.
3406      We pretend as if they don't exist.  */
3407   const char *end = path + strlen (path);
3408   /* path + 1: keep leading slash.  */
3409   while (end > path + 1 && isdirsep (end[-1]))
3410     --end;
3411
3412   /* At this point, END points to one beyond the last character
3413      (with trailing slashes "deleted").  */
3414
3415   /* Point LAST_SLASH at the last slash (duh...).  */
3416   const char *last_slash;
3417   for (last_slash = end - 1; last_slash >= path; --last_slash)
3418     if (isdirsep (*last_slash))
3419       break;
3420
3421   if (last_slash == path)
3422     {
3423       *dir++ = '/';
3424       *dir = 0;
3425     }
3426   else if (last_slash > path)
3427     {
3428       memcpy (dir, path, last_slash - path);
3429       dir[last_slash - path] = 0;
3430     }
3431   else
3432     {
3433       if (dir_started_p)
3434         ; /* nothing to do */
3435       else
3436         *dir++ = '.';
3437       *dir = 0;
3438     }
3439
3440   memcpy (file, last_slash + 1, end - last_slash - 1);
3441   file[end - last_slash - 1] = 0;
3442 }
3443
3444 static inline void
3445 copy_cwd_str (PUNICODE_STRING tgt, PUNICODE_STRING src)
3446 {
3447   RtlCopyUnicodeString (tgt, src);
3448   if (tgt->Buffer[tgt->Length / sizeof (WCHAR) - 1] != L'\\')
3449     {
3450       tgt->Buffer[tgt->Length / sizeof (WCHAR)] = L'\\';
3451       tgt->Length += sizeof (WCHAR);
3452     }
3453 }
3454
3455 /*****************************************************************************/
3456
3457 /* The find_fast_cwd_pointer function and parts of the
3458    cwdstuff::override_win32_cwd method are based on code using the
3459    following license:
3460
3461    Copyright 2010 John Carey. All rights reserved.
3462
3463    Redistribution and use in source and binary forms, with or without
3464    modification, are permitted provided that the following conditions
3465    are met:
3466
3467       1. Redistributions of source code must retain the above
3468       copyright notice, this list of conditions and the following
3469       disclaimer.
3470
3471       2. Redistributions in binary form must reproduce the above
3472       copyright notice, this list of conditions and the following
3473       disclaimer in the documentation and/or other materials provided
3474       with the distribution.
3475
3476    THIS SOFTWARE IS PROVIDED BY JOHN CAREY ``AS IS'' AND ANY EXPRESS
3477    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3478    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3479    ARE DISCLAIMED. IN NO EVENT SHALL JOHN CAREY OR CONTRIBUTORS BE
3480    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3481    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
3482    OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
3483    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3484    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3485    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3486    USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3487    DAMAGE. */
3488
3489 /* This class is used to store the CWD starting with Windows Vista.
3490    The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only
3491    an afterthought now.  The actual CWD storage is a FAST_CWD structure
3492    which is allocated on the process heap.  The new method only requires
3493    minimal locking and it's much more multi-thread friendly.  Presumably
3494    it minimizes contention when accessing the CWD. 
3495    The class fcwd_access_t is supposed to encapsulate the gory implementation
3496    details depending on OS version from the calling functions. */
3497 class fcwd_access_t {
3498   /* This is the layout used in Windows 8 developer preview. */
3499   struct FAST_CWD_8 {
3500     LONG           ReferenceCount;      /* Only release when this is 0. */
3501     HANDLE         DirectoryHandle;
3502     ULONG          OldDismountCount;    /* Reflects the system DismountCount
3503                                            at the time the CWD has been set. */
3504     UNICODE_STRING Path;                /* Path's Buffer member always refers
3505                                            to the following Buffer array. */
3506     LONG           FSCharacteristics;   /* Taken from FileFsDeviceInformation */
3507     WCHAR          Buffer[MAX_PATH];
3508   };
3509   /* This is the layout used in Windows 7 and Vista. */
3510   struct FAST_CWD_7 {
3511     UNICODE_STRING Path;                /* Path's Buffer member always refers
3512                                            to the following Buffer array. */
3513     HANDLE         DirectoryHandle;
3514     LONG           FSCharacteristics;   /* Taken from FileFsDeviceInformation */
3515     LONG           ReferenceCount;      /* Only release when this is 0. */
3516     ULONG          OldDismountCount;    /* Reflects the system DismountCount
3517                                            at the time the CWD has been set. */
3518     WCHAR          Buffer[MAX_PATH];
3519   };
3520   /* This is the old FAST_CWD structure up to the patch from KB 2393802,
3521      release in February 2011. */
3522   struct FAST_CWD_OLD {
3523     LONG           ReferenceCount;      /* Only release when this is 0. */
3524     HANDLE         DirectoryHandle;
3525     ULONG          OldDismountCount;    /* Reflects the system DismountCount
3526                                            at the time the CWD has been set. */
3527     UNICODE_STRING Path;                /* Path's Buffer member always refers
3528                                            to the following Buffer array. */
3529     WCHAR          Buffer[MAX_PATH];
3530   };
3531   union {
3532     FAST_CWD_OLD fold;
3533     FAST_CWD_7   f7;
3534     FAST_CWD_8   f8;
3535   };
3536
3537   /* Type of FAST_CWD used on this system.  Keeping this information available
3538      in shared memory avoids to test for the version every time around.
3539      Default to new version. */
3540   enum fcwd_version_t {
3541     FCWD_OLD,
3542     FCWD_W7,
3543     FCWD_W8
3544   };
3545   static fcwd_version_t fast_cwd_version;
3546
3547 #define IMPLEMENT(type, name) \
3548   type name () { \
3549     switch (fast_cwd_version) { \
3550       case FCWD_OLD: \
3551       default: \
3552         return fold.name; \
3553       case FCWD_W7: \
3554         return f7.name; \
3555       case FCWD_W8: \
3556         return f8.name; \
3557     } \
3558   }
3559   IMPLEMENT (LONG &, ReferenceCount)
3560   IMPLEMENT (HANDLE &, DirectoryHandle)
3561   IMPLEMENT (ULONG &, OldDismountCount)
3562   IMPLEMENT (UNICODE_STRING &, Path)
3563   IMPLEMENT (WCHAR *, Buffer)
3564   /* Special case FSCharacteristics.  Didn't exist originally. */
3565   void SetFSCharacteristics (LONG val)
3566     {
3567       switch (fast_cwd_version)
3568         {
3569         case FCWD_OLD:
3570           break;
3571         case FCWD_W7:
3572           f7.FSCharacteristics = val;
3573           break;
3574         case FCWD_W8:
3575           f8.FSCharacteristics = val;
3576           break;
3577         }
3578     }
3579 public:
3580   void CopyPath (UNICODE_STRING &target)
3581     {
3582       /* Copy the Path contents over into the UNICODE_STRING referenced by
3583          target.  This is used to set the CurrentDirectoryName in the
3584          user parameter block. */
3585       target = Path ();
3586     }
3587   void Free (PVOID heap)
3588     {
3589       /* Decrement the reference count.  If it's down to 0, free
3590          structure from heap. */
3591       if (this && InterlockedDecrement (&ReferenceCount ()) == 0)
3592         {
3593           /* In contrast to pre-Vista, the handle on init is always a
3594              fresh one and not the handle inherited from the parent
3595              process.  So we always have to close it here.  However, the
3596              handle could be NULL, if we cd'ed into a virtual dir. */
3597           HANDLE h = DirectoryHandle ();
3598           if (h)
3599             NtClose (h);
3600           RtlFreeHeap (heap, 0, this);
3601         }
3602     }
3603   void FillIn (HANDLE dir, PUNICODE_STRING name, ULONG old_dismount_count)
3604     {
3605       /* Fill in all values into this FAST_CWD structure. */
3606       DirectoryHandle () = dir;
3607       ReferenceCount () = 1;
3608       OldDismountCount () = old_dismount_count;
3609       /* The new structure stores the device characteristics of the
3610          volume holding the dir.  RtlGetCurrentDirectory_U checks
3611          if the FILE_REMOVABLE_MEDIA flag is set and, if so, checks if
3612          the volume is still the same as the one used when opening
3613          the directory handle.
3614          We don't call NtQueryVolumeInformationFile for the \\?\PIPE,
3615          though.  It just returns STATUS_INVALID_HANDLE anyway. */
3616       if (fast_cwd_version != FCWD_OLD)
3617         {
3618           SetFSCharacteristics (0);
3619           if (name != &ro_u_pipedir)
3620             {
3621               IO_STATUS_BLOCK io;
3622               FILE_FS_DEVICE_INFORMATION ffdi;
3623               if (NT_SUCCESS (NtQueryVolumeInformationFile (dir, &io, &ffdi,
3624                               sizeof ffdi, FileFsDeviceInformation)))
3625                 SetFSCharacteristics (ffdi.Characteristics);
3626             }
3627         }
3628       RtlInitEmptyUnicodeString (&Path (), Buffer (),
3629                                  MAX_PATH * sizeof (WCHAR));
3630       copy_cwd_str (&Path (), name);
3631     }
3632
3633   static void SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir)
3634     {
3635       /* Input: The buffer pointer as it's stored in the user parameter block
3636          and a directory handle.
3637          This function computes the address to the FAST_CWD structure based
3638          on the version and overwrites the directory handle.  It is only
3639          used if we couldn't figure out the address of fast_cwd_ptr. */
3640       fcwd_access_t *f_cwd;
3641       switch (fast_cwd_version)
3642         {
3643         case FCWD_OLD:
3644         default:
3645           f_cwd = (fcwd_access_t *) 
3646             ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_OLD, Buffer));
3647         case FCWD_W7:
3648           f_cwd = (fcwd_access_t *) 
3649             ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_7, Buffer));
3650         case FCWD_W8:
3651           f_cwd = (fcwd_access_t *) 
3652             ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_8, Buffer));
3653         }
3654       f_cwd->DirectoryHandle () = dir;
3655     }
3656   static void SetVersionFromPointer (PBYTE buf_p, bool is_buffer)
3657     {
3658       /* Given a pointer to the FAST_CWD structure (is_buffer == false) or a
3659          pointer to the Buffer within (is_buffer == true), this function
3660          computes the FAST_CWD version by checking that Path.MaximumLength
3661          equals MAX_PATH, and that Path.Buffer == Buffer. */
3662       if (is_buffer)
3663         buf_p -= __builtin_offsetof (FAST_CWD_8, Buffer);
3664       fcwd_access_t *f_cwd = (fcwd_access_t *) buf_p;
3665       if (f_cwd->f8.Path.MaximumLength == MAX_PATH * sizeof (WCHAR)
3666           && f_cwd->f8.Path.Buffer == f_cwd->f8.Buffer)
3667         fast_cwd_version = FCWD_W8;
3668       else if (f_cwd->f7.Path.MaximumLength == MAX_PATH * sizeof (WCHAR)
3669                && f_cwd->f7.Path.Buffer == f_cwd->f7.Buffer)
3670         fast_cwd_version = FCWD_W7;
3671       else
3672         fast_cwd_version = FCWD_OLD;
3673     }
3674 };
3675 fcwd_access_t::fcwd_version_t fcwd_access_t::fast_cwd_version
3676   __attribute__((section (".cygwin_dll_common"), shared))
3677   = fcwd_access_t::FCWD_W7;
3678 /* fast_cwd_ptr is a pointer to the global RtlpCurDirRef pointer in
3679    ntdll.dll pointing to the FAST_CWD structure which constitutes the CWD.
3680    Unfortunately RtlpCurDirRef is not exported from ntdll.dll.
3681    We put the pointer into the common shared DLL segment.  This allows to
3682    restrict the call to find_fast_cwd_pointer() to once per Cygwin session
3683    per user session.  This works, because ASLR randomizes the load address
3684    of DLLs only once at boot time. */
3685 static fcwd_access_t **fast_cwd_ptr
3686   __attribute__((section (".cygwin_dll_common"), shared))
3687   = (fcwd_access_t **) -1;
3688
3689 #define peek32(x)       (*(uint32_t *)(x))
3690
3691 /* This function scans the code in ntdll.dll to find the address of the
3692    global variable used to access the CWD starting with Vista.  While the
3693    pointer is global, it's not exported from the DLL, unfortunately.
3694    Therefore we have to use some knowledge to figure out the address.
3695
3696    This code has been tested on Vista 32/64 bit, Server 2008 32/64 bit,
3697    Windows 7 32/64 bit, and Server 2008 R2 (which is only 64 bit anyway).
3698    There's some hope that this will still work for Windows 8... */
3699 static fcwd_access_t **
3700 find_fast_cwd_pointer ()
3701 {
3702   /* Fetch entry points of relevant functions in ntdll.dll. */
3703   HMODULE ntdll = GetModuleHandle ("ntdll.dll");
3704   if (!ntdll)
3705     return NULL;
3706   const uint8_t *get_dir = (const uint8_t *)
3707                            GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
3708   const uint8_t *ent_crit = (const uint8_t *)
3709                             GetProcAddress (ntdll, "RtlEnterCriticalSection");
3710   if (!get_dir || !ent_crit)
3711     return NULL;
3712   /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
3713   const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 32);
3714   if (!rcall)
3715     return NULL;
3716   /* Fetch offset from instruction and compute address of called function.
3717      This function actually fetches the current FAST_CWD instance and
3718      performs some other actions, not important to us. */
3719   ptrdiff_t offset = (ptrdiff_t) peek32 (rcall + 1);
3720   const uint8_t *use_cwd = rcall + 5 + offset;
3721   /* Find first "push edi" instruction. */
3722   const uint8_t *pushedi = (const uint8_t *) memchr (use_cwd, 0x57, 32);
3723   /* ...which should be followed by "mov edi, crit-sect-addr" then
3724      "push edi", or by just a single "push crit-sect-addr". */
3725   const uint8_t *movedi = pushedi + 1;
3726   if (movedi[0] == 0xbf && movedi[5] == 0x57)
3727     rcall = movedi + 6;
3728   else if (movedi[0] == 0x68)
3729     rcall = movedi + 5;
3730   else
3731     return NULL;
3732   /* Compare the address used for the critical section with the known
3733      PEB lock as stored in the PEB. */
3734   if ((PRTL_CRITICAL_SECTION) peek32 (movedi + 1)
3735       != NtCurrentTeb ()->Peb->FastPebLock)
3736     return NULL;
3737   /* To check we are seeing the right code, we check our expectation that
3738      the next instruction is a relative call into RtlEnterCriticalSection. */
3739   if (rcall[0] != 0xe8)
3740     return NULL;
3741   /* Check that this is a relative call to RtlEnterCriticalSection. */
3742   offset = (ptrdiff_t) peek32 (rcall + 1);
3743   if (rcall + 5 + offset != ent_crit)
3744     return NULL;
3745   /* After locking the critical section, the code should read the global
3746      PFAST_CWD * pointer that is guarded by that critical section. */
3747   const uint8_t *movesi = rcall + 5;
3748   if (movesi[0] != 0x8b)
3749     return NULL;
3750   return (fcwd_access_t **) peek32 (movesi + 2);
3751 }
3752
3753 static fcwd_access_t **
3754 find_fast_cwd ()
3755 {
3756   /* Fetch the pointer but don't set the global fast_cwd_ptr yet.  First
3757      we have to make sure we know the version of the FAST_CWD structure
3758      used on the system. */
3759   fcwd_access_t **f_cwd_ptr = find_fast_cwd_pointer ();
3760   if (!f_cwd_ptr)
3761     system_printf ("WARNING: Couldn't compute FAST_CWD pointer.  "
3762                    "Please report this problem to\nthe public mailing "
3763                    "list cygwin@cygwin.com");
3764   if (f_cwd_ptr && *f_cwd_ptr)
3765     {
3766       /* Just evaluate structure version. */
3767       fcwd_access_t::SetVersionFromPointer ((PBYTE) *f_cwd_ptr, false);
3768     }
3769   else
3770     {
3771       /* If we couldn't fetch fast_cwd_ptr, or if fast_cwd_ptr is NULL(*)
3772          we have to figure out the version from the Buffer pointer in the
3773          ProcessParameters.
3774          
3775          (*) This is very unlikely to happen when starting the first
3776          Cygwin process, since it only happens when starting the
3777          process in a directory which can't be used as CWD by Win32, or
3778          if the directory doesn't exist.  But *if* it happens, we have
3779          no valid FAST_CWD structure, even though upp_cwd_str.Buffer is
3780          not NULL in that case.  So we let the OS create a valid
3781          FAST_CWD structure temporarily to have something to work with.
3782          We know the pipe FS works. */
3783       PEB &peb = *NtCurrentTeb ()->Peb;
3784
3785       if (f_cwd_ptr     /* so *f_cwd_ptr == NULL */
3786           && !NT_SUCCESS (RtlSetCurrentDirectory_U (&ro_u_pipedir)))
3787         api_fatal ("Couldn't set directory to %S temporarily.\n"
3788                    "Cannot continue.", &ro_u_pipedir);
3789       RtlEnterCriticalSection (peb.FastPebLock);
3790       fcwd_access_t::SetVersionFromPointer
3791         ((PBYTE) peb.ProcessParameters->CurrentDirectoryName.Buffer, true);
3792       RtlLeaveCriticalSection (peb.FastPebLock);
3793     }
3794   /* Eventually, after we set the version as well, set fast_cwd_ptr. */
3795   return f_cwd_ptr;
3796 }
3797
3798 void
3799 cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
3800 {
3801   HANDLE h = NULL;
3802
3803   PEB &peb = *NtCurrentTeb ()->Peb;
3804   UNICODE_STRING &upp_cwd_str = peb.ProcessParameters->CurrentDirectoryName;
3805   HANDLE &upp_cwd_hdl = peb.ProcessParameters->CurrentDirectoryHandle;
3806
3807   if (wincap.has_fast_cwd ())
3808     {
3809       if (fast_cwd_ptr == (fcwd_access_t **) -1)
3810         fast_cwd_ptr = find_fast_cwd ();
3811       if (fast_cwd_ptr)
3812         {
3813           /* Default method starting with Vista.  If we got a valid value for
3814              fast_cwd_ptr, we can simply replace the RtlSetCurrentDirectory_U
3815              function entirely, just as on pre-Vista. */
3816           PVOID heap = peb.ProcessHeap;
3817           /* First allocate a new fcwd_access_t structure on the heap.
3818              The new fcwd_access_t structure is 4 byte bigger than the old one,
3819              but we simply don't care, so we allocate always room for the
3820              new one. */
3821           fcwd_access_t *f_cwd = (fcwd_access_t *)
3822                             RtlAllocateHeap (heap, 0, sizeof (fcwd_access_t));
3823           if (!f_cwd)
3824             {
3825               debug_printf ("RtlAllocateHeap failed");
3826               return;
3827             }
3828           /* Fill in the values. */
3829           f_cwd->FillIn (dir, error ? &ro_u_pipedir : &win32,
3830                          old_dismount_count);
3831           /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
3832              structure and writing the CWD to the user process parameter
3833              block.  This is equivalent to calling RtlAcquirePebLock/
3834              RtlReleasePebLock, but without having to go through the FS
3835              selector again. */
3836           RtlEnterCriticalSection (peb.FastPebLock);
3837           fcwd_access_t *old_cwd = *fast_cwd_ptr;
3838           *fast_cwd_ptr = f_cwd;
3839           f_cwd->CopyPath (upp_cwd_str);
3840           upp_cwd_hdl = dir;
3841           RtlLeaveCriticalSection (peb.FastPebLock);
3842           old_cwd->Free (heap);
3843         }
3844       else
3845         {
3846           /* This is more a hack, and it's only used on Vista and later if we
3847              failed to find the fast_cwd_ptr value.  What we do here is to call
3848              RtlSetCurrentDirectory_U and let it set up a new FAST_CWD
3849              structure.  Afterwards, compute the address of that structure
3850              utilizing the fact that the buffer address in the user process
3851              parameter block is actually pointing to the buffer in that
3852              FAST_CWD structure.  Then replace the directory handle in that
3853              structure with our own handle and close the original one.
3854
3855              Note that the call to RtlSetCurrentDirectory_U also closes our
3856              old dir handle, so there won't be any handle left open.
3857
3858              This method is prone to two race conditions:
3859
3860              - Due to the way RtlSetCurrentDirectory_U opens the directory
3861                handle, the directory is locked against deletion or renaming
3862                between the RtlSetCurrentDirectory_U and the subsequent NtClose
3863                call.
3864
3865              - When another thread calls SetCurrentDirectory at exactly the
3866                same time, a crash might occur, or worse, unrelated data could
3867                be overwritten or NtClose could be called on an unrelated handle.
3868
3869              Therefore, use this *only* as a fallback. */
3870           if (!init)
3871             {
3872               NTSTATUS status =
3873                 RtlSetCurrentDirectory_U (error ? &ro_u_pipedir : &win32);
3874               if (!NT_SUCCESS (status))
3875                 {
3876                   debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %p",
3877                                 error ? &ro_u_pipedir : &win32, status);
3878                   return;
3879                 }
3880             }
3881           else if (upp_cwd_hdl == NULL)
3882             return;
3883           RtlEnterCriticalSection (peb.FastPebLock);
3884           fcwd_access_t::SetDirHandleFromBufferPointer(upp_cwd_str.Buffer, dir);
3885           h = upp_cwd_hdl;
3886           upp_cwd_hdl = dir;
3887           RtlLeaveCriticalSection (peb.FastPebLock);
3888           /* In contrast to pre-Vista, the handle on init is always a fresh one
3889              and not the handle inherited from the parent process.  So we always
3890              have to close it here. */
3891           NtClose (h);
3892         }
3893     }
3894   else
3895     {
3896       /* This method is used for all pre-Vista OSes.  We simply set the values
3897          for the CWD in the user process parameter block entirely by ourselves
3898          under PEB lock condition.  This is how RtlSetCurrentDirectory_U worked
3899          in these older OSes, so we're safe.
3900
3901          Note that we can't just RtlEnterCriticalSection (peb.FastPebLock)
3902          on pre-Vista.  RtlAcquirePebLock was way more complicated back then. */
3903       RtlAcquirePebLock ();
3904       if (!init)
3905         copy_cwd_str (&upp_cwd_str, error ? &ro_u_pipedir : &win32);
3906       h = upp_cwd_hdl;
3907       upp_cwd_hdl = dir;
3908       RtlReleasePebLock ();
3909       /* Only on init, the handle is potentially a native handle.  However,
3910          if it's identical to dir, it's the inherited handle from a Cygwin
3911          parent process and must not be closed. */
3912       if (h && h != dir)
3913         NtClose (h);
3914     }
3915 }
3916
3917 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
3918 void
3919 cwdstuff::init ()
3920 {
3921   cwd_lock.init ("cwd_lock");
3922
3923   /* Cygwin processes inherit the cwd from their parent.  If the win32 path
3924      buffer is not NULL, the cwd struct is already set up, and we only
3925      have to override the Win32 CWD with ours. */
3926   if (win32.Buffer)
3927     override_win32_cwd (true, SharedUserData.DismountCount);
3928   else
3929     /* Initially re-open the cwd to allow POSIX semantics. */
3930     set (NULL, NULL);
3931 }
3932
3933 /* Chdir and fill out the elements of a cwdstuff struct. */
3934 int
3935 cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
3936 {
3937   NTSTATUS status;
3938   UNICODE_STRING upath;
3939   PEB &peb = *NtCurrentTeb ()->Peb;
3940   bool virtual_path = false;
3941   bool unc_path = false;
3942   bool inaccessible_path = false;
3943
3944   /* Here are the problems with using SetCurrentDirectory.  Just skip this
3945      comment if you don't like whining.
3946
3947      - SetCurrentDirectory only supports paths of up to MAX_PATH - 1 chars,
3948        including a trailing backslash.  That's an absolute restriction, even
3949        in the UNICODE API.
3950
3951      - SetCurrentDirectory fails for directories with strict permissions even
3952        for processes with the SE_BACKUP_NAME privilege enabled.  The reason
3953        is apparently that SetCurrentDirectory calls NtOpenFile without the
3954        FILE_OPEN_FOR_BACKUP_INTENT flag set.
3955
3956      - SetCurrentDirectory does not support case-sensitivity.
3957
3958      - Unlinking a cwd fails because SetCurrentDirectory seems to open
3959        directories so that deleting the directory is disallowed.
3960
3961      - SetCurrentDirectory can naturally not work on virtual Cygwin paths
3962        like /proc or /cygdrive.
3963
3964      Unfortunately, even though we have access to the Win32 process parameter
3965      block, we can't just replace the directory handle.  Starting with Vista,
3966      the handle is used elsewhere, and just replacing the handle in the process
3967      parameter block shows quite surprising results.
3968      FIXME: If we ever find a *safe* way to replace the directory handle in
3969      the process parameter block, we're back in business.
3970
3971      Nevertheless, doing entirely without SetCurrentDirectory is not really
3972      feasible, because it breaks too many mixed applications using the Win32
3973      API.
3974
3975      Therefore we handle the CWD all by ourselves and just keep the Win32
3976      CWD in sync.  However, to avoid surprising behaviour in the Win32 API
3977      when we are in a CWD which is inaccessible as Win32 CWD, we set the
3978      Win32 CWD to a "weird" directory in which all relative filesystem-related
3979      calls fail. */
3980
3981   cwd_lock.acquire ();
3982
3983   if (nat_cwd)
3984     {
3985       upath = *nat_cwd->get_nt_native_path ();
3986       if (nat_cwd->isspecial ())
3987         virtual_path = true;
3988     }
3989
3990   /* Memorize old DismountCount before opening the dir.  This value is
3991      stored in the FAST_CWD structure on Vista and later.  It would be
3992      simpler to fetch the old DismountCount in override_win32_cwd, but
3993      Windows also fetches it before opening the directory handle.  It's
3994      not quite clear if that's really required, but since we don't know
3995      the side effects of this action, we better follow Windows' lead. */
3996   ULONG old_dismount_count = SharedUserData.DismountCount;
3997   /* Open a directory handle with FILE_OPEN_FOR_BACKUP_INTENT and with all
3998      sharing flags set.  The handle is right now used in exceptions.cc only,
3999      but that might change in future. */
4000   HANDLE h = NULL;
4001   if (!virtual_path)
4002     {
4003       IO_STATUS_BLOCK io;
4004       OBJECT_ATTRIBUTES attr;
4005
4006       if (!nat_cwd)
4007         {
4008           /* On init, just reopen Win32 CWD with desired access flags.
4009              We can access the PEB without lock, because no other thread
4010              can change the CWD. */
4011           RtlInitUnicodeString (&upath, L"");
4012           InitializeObjectAttributes (&attr, &upath,
4013                         OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
4014                         peb.ProcessParameters->CurrentDirectoryHandle, NULL);
4015         }
4016       else
4017         InitializeObjectAttributes (&attr, &upath,
4018                         nat_cwd->objcaseinsensitive () | OBJ_INHERIT,
4019                         NULL, NULL);
4020       /* First try without FILE_OPEN_FOR_BACKUP_INTENT, to find out if the
4021          directory is valid for Win32 apps.  And, no, we can't just call
4022          SetCurrentDirectory here, since that would potentially break
4023          case-sensitivity. */
4024       status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
4025                            FILE_SHARE_VALID_FLAGS,
4026                            FILE_DIRECTORY_FILE
4027                            | FILE_SYNCHRONOUS_IO_NONALERT);
4028       if (status == STATUS_ACCESS_DENIED)
4029         {
4030           status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
4031                                FILE_SHARE_VALID_FLAGS,
4032                                FILE_DIRECTORY_FILE
4033                                | FILE_SYNCHRONOUS_IO_NONALERT
4034                                | FILE_OPEN_FOR_BACKUP_INTENT);
4035           inaccessible_path = true;
4036         }
4037       if (!NT_SUCCESS (status))
4038         {
4039           cwd_lock.release ();
4040           __seterrno_from_nt_status (status);
4041           return -1;
4042         }
4043     }
4044   /* Set new handle.  Note that we simply overwrite the old handle here
4045      without closing it.  The handle is also used as Win32 CWD handle in
4046      the user parameter block, and it will be closed in override_win32_cwd,
4047      if required. */
4048   dir = h;
4049
4050   if (!nat_cwd)
4051     {
4052       /* On init, just fetch the Win32 dir from the PEB.  We can access
4053          the PEB without lock, because no other thread can change the CWD
4054          at that time. */
4055       PUNICODE_STRING pdir = &peb.ProcessParameters->CurrentDirectoryName;
4056       RtlInitEmptyUnicodeString (&win32,
4057                                  (PWCHAR) crealloc_abort (win32.Buffer,
4058                                                           pdir->Length
4059                                                           + sizeof (WCHAR)),
4060                                  pdir->Length + sizeof (WCHAR));
4061       RtlCopyUnicodeString (&win32, pdir);
4062
4063       PWSTR eoBuffer = win32.Buffer + (win32.Length / sizeof (WCHAR));
4064       /* Remove trailing slash if one exists. */
4065       if ((eoBuffer - win32.Buffer) > 3 && eoBuffer[-1] == L'\\')
4066         win32.Length -= sizeof (WCHAR);
4067       if (eoBuffer[0] == L'\\')
4068         unc_path = true;
4069
4070       posix_cwd = NULL;
4071     }
4072   else
4073     {
4074       if (!virtual_path) /* don't mangle virtual path. */
4075         {
4076           /* Convert into Win32 path and compute length. */
4077           if (upath.Buffer[1] == L'?')
4078             {
4079               upath.Buffer += 4;
4080               upath.Length -= 4 * sizeof (WCHAR);
4081               if (upath.Buffer[1] != L':')
4082                 {
4083                   /* UNC path */
4084                   upath.Buffer += 2;
4085                   upath.Length -= 2 * sizeof (WCHAR);
4086                   unc_path = true;
4087                 }
4088             }
4089           else
4090             {
4091               /* Path via native NT namespace.  Prepend GLOBALROOT prefix
4092                  to create a valid Win32 path. */
4093               PWCHAR buf = (PWCHAR) alloca (upath.Length
4094                                             + ro_u_globalroot.Length
4095                                             + sizeof (WCHAR));
4096               wcpcpy (wcpcpy (buf, ro_u_globalroot.Buffer), upath.Buffer);
4097               upath.Buffer = buf;
4098               upath.Length += ro_u_globalroot.Length;
4099             }
4100           PWSTR eoBuffer = upath.Buffer + (upath.Length / sizeof (WCHAR));
4101           /* Remove trailing slash if one exists. */
4102           if ((eoBuffer - upath.Buffer) > 3 && eoBuffer[-1] == L'\\')
4103             upath.Length -= sizeof (WCHAR);
4104         }
4105       RtlInitEmptyUnicodeString (&win32,
4106                                  (PWCHAR) crealloc_abort (win32.Buffer,
4107                                                           upath.Length
4108                                                           + sizeof (WCHAR)),
4109                                  upath.Length + sizeof (WCHAR));
4110       RtlCopyUnicodeString (&win32, &upath);
4111       if (unc_path)
4112         win32.Buffer[0] = L'\\';
4113     }
4114   /* Make sure it's NUL-terminated. */
4115   win32.Buffer[win32.Length / sizeof (WCHAR)] = L'\0';
4116
4117   /* Set drive_length, used in path conversion, and error code, used in
4118      spawn_guts to decide whether a native Win32 app can be started or not. */
4119   if (virtual_path)
4120     {
4121       drive_length = 0;
4122       error = ENOTDIR;
4123     }
4124   else
4125     {
4126       if (!unc_path)
4127         drive_length = 2;
4128       else
4129         {
4130           PWCHAR ptr = wcschr (win32.Buffer + 2, L'\\');
4131           if (ptr)
4132             ptr = wcschr (ptr + 1, L'\\');
4133           if (ptr)
4134             drive_length = ptr - win32.Buffer;
4135           else
4136             drive_length = win32.Length / sizeof (WCHAR);
4137         }
4138       if (inaccessible_path)
4139         error = EACCES;
4140       else if (win32.Length > (MAX_PATH - 2) * sizeof (WCHAR))
4141         error = ENAMETOOLONG;
4142       else
4143         error = 0;
4144     }
4145   /* Keep the Win32 CWD in sync.  Don't check for error, other than for
4146      strace output.  Try to keep overhead low. */
4147   override_win32_cwd (!nat_cwd, old_dismount_count);
4148
4149   /* Eventually, create POSIX path if it's not set on entry. */
4150   tmp_pathbuf tp;
4151   if (!posix_cwd)
4152     {
4153       posix_cwd = (const char *) tp.c_get ();
4154       mount_table->conv_to_posix_path (win32.Buffer, (char *) posix_cwd, 0);
4155     }
4156   posix = (char *) crealloc_abort (posix, strlen (posix_cwd) + 1);
4157   stpcpy (posix, posix_cwd);
4158
4159   cwd_lock.release ();
4160   return 0;
4161 }
4162
4163 const char *
4164 cwdstuff::get_error_desc () const
4165 {
4166   switch (cygheap->cwd.get_error ())
4167     {
4168     case EACCES:
4169       return "has restricted permissions which render it\n"
4170              "inaccessible as Win32 working directory";
4171     case ENOTDIR:
4172       return "is a virtual Cygwin directory which does\n"
4173              "not exist for a native Windows application";
4174     case ENAMETOOLONG:
4175       return "has a path longer than allowed for a\n"
4176              "Win32 working directory";
4177     default:
4178       break;
4179     }
4180   /* That shouldn't occur, unless we defined a new error code
4181      in cwdstuff::set. */
4182   return "is not accessible for some unknown reason";
4183 }
4184
4185 /* Store incoming wchar_t path as current posix cwd.  This is called from
4186    setlocale so that the cwd is always stored in the right charset. */
4187 void
4188 cwdstuff::reset_posix (wchar_t *w_cwd)
4189 {
4190   size_t len = sys_wcstombs (NULL, (size_t) -1, w_cwd);
4191   posix = (char *) crealloc_abort (posix, len + 1);
4192   sys_wcstombs (posix, len + 1, w_cwd);
4193 }
4194
4195 char *
4196 cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
4197 {
4198   MALLOC_CHECK;
4199
4200   tmp_pathbuf tp;
4201   if (ulen)
4202     /* nothing */;
4203   else if (buf == NULL)
4204     ulen = (unsigned) -1;
4205   else
4206     {
4207       set_errno (EINVAL);
4208       goto out;
4209     }
4210
4211   cwd_lock.acquire ();
4212
4213   char *tocopy;
4214   if (!need_posix)
4215     {
4216       tocopy = tp.c_get ();
4217       sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer,
4218                     win32.Length / sizeof (WCHAR));
4219     }
4220   else
4221     tocopy = posix;
4222
4223   debug_printf ("posix %s", posix);
4224   if (strlen (tocopy) >= ulen)
4225     {
4226       set_errno (ERANGE);
4227       buf = NULL;
4228     }
4229   else
4230     {
4231       if (!buf)
4232         buf = (char *) malloc (strlen (tocopy) + 1);
4233       strcpy (buf, tocopy);
4234       if (!buf[0])      /* Should only happen when chroot */
4235         strcpy (buf, "/");
4236     }
4237
4238   cwd_lock.release ();
4239
4240 out:
4241   syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
4242                   buf, buf, ulen, need_posix, with_chroot, errno);
4243   MALLOC_CHECK;
4244   return buf;
4245 }
4246
4247 int etc::curr_ix = 0;
4248 /* Note that the first elements of the below arrays are unused */
4249 bool etc::change_possible[MAX_ETC_FILES + 1];
4250 OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1];
4251 LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1];
4252
4253 int
4254 etc::init (int n, POBJECT_ATTRIBUTES attr)
4255 {
4256   if (n > 0)
4257     /* ok */;
4258   else if (++curr_ix <= MAX_ETC_FILES)
4259     n = curr_ix;
4260   else
4261     api_fatal ("internal error");
4262
4263   fn[n] = *attr;
4264   change_possible[n] = false;
4265   test_file_change (n);
4266   paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix);
4267   return n;
4268 }
4269
4270 bool
4271 etc::test_file_change (int n)
4272 {
4273   NTSTATUS status;
4274   FILE_NETWORK_OPEN_INFORMATION fnoi;
4275   bool res;
4276
4277   status = NtQueryFullAttributesFile (&fn[n], &fnoi);
4278   if (!NT_SUCCESS (status))
4279     {
4280       res = true;
4281       memset (last_modified + n, 0, sizeof (last_modified[n]));
4282       debug_printf ("NtQueryFullAttributesFile (%S) failed, %p",
4283                     fn[n].ObjectName, status);
4284     }
4285   else
4286     {
4287       res = CompareFileTime ((FILETIME *) &fnoi.LastWriteTime,
4288                              (FILETIME *) last_modified + n) > 0;
4289       last_modified[n].QuadPart = fnoi.LastWriteTime.QuadPart;
4290     }
4291
4292   paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4293   return res;
4294 }
4295
4296 bool
4297 etc::dir_changed (int n)
4298 {
4299   if (!change_possible[n])
4300     {
4301       static HANDLE changed_h NO_COPY;
4302       NTSTATUS status;
4303       IO_STATUS_BLOCK io;
4304
4305       if (!changed_h)
4306         {
4307           OBJECT_ATTRIBUTES attr;
4308
4309           path_conv dir ("/etc");
4310           status = NtOpenFile (&changed_h, SYNCHRONIZE | FILE_LIST_DIRECTORY,
4311                                dir.get_object_attr (attr, sec_none_nih), &io,
4312                                FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE);
4313           if (!NT_SUCCESS (status))
4314             {
4315 #ifdef DEBUGGING
4316               system_printf ("NtOpenFile (%S) failed, %p",
4317                              dir.get_nt_native_path (), status);
4318 #endif
4319               changed_h = INVALID_HANDLE_VALUE;
4320             }
4321           else
4322             {
4323               status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4324                                                 NULL, &io, NULL, 0,
4325                                                 FILE_NOTIFY_CHANGE_LAST_WRITE
4326                                                 | FILE_NOTIFY_CHANGE_FILE_NAME,
4327                                                 FALSE);
4328               if (!NT_SUCCESS (status))
4329                 {
4330 #ifdef DEBUGGING
4331                   system_printf ("NtNotifyChangeDirectoryFile (1) failed, %p",
4332                                  status);
4333 #endif
4334                   NtClose (changed_h);
4335                   changed_h = INVALID_HANDLE_VALUE;
4336                 }
4337             }
4338           memset (change_possible, true, sizeof (change_possible));
4339         }
4340
4341       if (changed_h == INVALID_HANDLE_VALUE)
4342         change_possible[n] = true;
4343       else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
4344         {
4345           status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4346                                                 NULL, &io, NULL, 0,
4347                                                 FILE_NOTIFY_CHANGE_LAST_WRITE
4348                                                 | FILE_NOTIFY_CHANGE_FILE_NAME,
4349                                                 FALSE);
4350           if (!NT_SUCCESS (status))
4351             {
4352 #ifdef DEBUGGING
4353               system_printf ("NtNotifyChangeDirectoryFile (2) failed, %p",
4354                              status);
4355 #endif
4356               NtClose (changed_h);
4357               changed_h = INVALID_HANDLE_VALUE;
4358             }
4359           memset (change_possible, true, sizeof change_possible);
4360         }
4361     }
4362
4363   paranoid_printf ("fn[%d] %S change_possible %d",
4364                    n, fn[n].ObjectName, change_possible[n]);
4365   return change_possible[n];
4366 }
4367
4368 bool
4369 etc::file_changed (int n)
4370 {
4371   bool res = false;
4372   if (dir_changed (n) && test_file_change (n))
4373     res = true;
4374   change_possible[n] = false;   /* Change is no longer possible */
4375   paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4376   return res;
4377 }
4378
4379 /* No need to be reentrant or thread-safe according to SUSv3.
4380    / and \\ are treated equally.  Leading drive specifiers are
4381    kept intact as far as it makes sense.  Everything else is
4382    POSIX compatible. */
4383 extern "C" char *
4384 basename (char *path)
4385 {
4386   static char buf[4];
4387   char *c, *d, *bs = path;
4388
4389   if (!path || !*path)
4390     return strcpy (buf, ".");
4391   if (isalpha (path[0]) && path[1] == ':')
4392     bs += 2;
4393   else if (strspn (path, "/\\") > 1)
4394     ++bs;
4395   c = strrchr (bs, '/');
4396   if ((d = strrchr (c ?: bs, '\\')) > c)
4397     c = d;
4398   if (c)
4399     {
4400       /* Trailing (back)slashes are eliminated. */
4401       while (c && c > bs && c[1] == '\0')
4402         {
4403           *c = '\0';
4404           c = strrchr (bs, '/');
4405           if ((d = strrchr (c ?: bs, '\\')) > c)
4406             c = d;
4407         }
4408       if (c && (c > bs || c[1]))
4409         return c + 1;
4410     }
4411   else if (!bs[0])
4412     {
4413       stpncpy (buf, path, bs - path);
4414       stpcpy (buf + (bs - path), ".");
4415       return buf;
4416     }
4417   return path;
4418 }
4419
4420 /* No need to be reentrant or thread-safe according to SUSv3.
4421    / and \\ are treated equally.  Leading drive specifiers and
4422    leading double (back)slashes are kept intact as far as it
4423    makes sense.  Everything else is POSIX compatible. */
4424 extern "C" char *
4425 dirname (char *path)
4426 {
4427   static char buf[4];
4428   char *c, *d, *bs = path;
4429
4430   if (!path || !*path)
4431     return strcpy (buf, ".");
4432   if (isalpha (path[0]) && path[1] == ':')
4433     bs += 2;
4434   else if (strspn (path, "/\\") > 1)
4435     ++bs;
4436   c = strrchr (bs, '/');
4437   if ((d = strrchr (c ?: bs, '\\')) > c)
4438     c = d;
4439   if (c)
4440     {
4441       /* Trailing (back)slashes are eliminated. */
4442       while (c && c > bs && c[1] == '\0')
4443         {
4444           *c = '\0';
4445           c = strrchr (bs, '/');
4446           if ((d = strrchr (c ?: bs, '\\')) > c)
4447             c = d;
4448         }
4449       if (!c)
4450         strcpy (bs, ".");
4451       else if (c > bs)
4452         {
4453           /* More trailing (back)slashes are eliminated. */
4454           while (c > bs && (*c == '/' || *c == '\\'))
4455             *c-- = '\0';
4456         }
4457       else
4458         c[1] = '\0';
4459     }
4460   else
4461     {
4462       stpncpy (buf, path, bs - path);
4463       stpcpy (buf + (bs - path), ".");
4464       return buf;
4465     }
4466   return path;
4467 }