OSDN Git Service

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