OSDN Git Service

cb38a25f1c5b538f9c64b87d1cb80e1f8f72b361
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / path.cc
1 /* path.cc: path support.
2
3      Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4      2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
5
6   This file is part of Cygwin.
7
8   This software is a copyrighted work licensed under the terms of the
9   Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10   details. */
11
12   /* This module's job is to
13      - convert between POSIX and Win32 style filenames,
14      - support the `mount' functionality,
15      - support symlinks for files and directories
16
17      Pathnames are handled as follows:
18
19      - A \ or : in a path denotes a pure windows spec.
20      - Paths beginning with // (or \\) are not translated (i.e. looked
21        up in the mount table) and are assumed to be UNC path names.
22
23      The goal in the above set of rules is to allow both POSIX and Win32
24      flavors of pathnames without either interfering.  The rules are
25      intended to be as close to a superset of both as possible.
26
27      Note that you can have more than one path to a file.  The mount
28      table is always prefered when translating Win32 paths to POSIX
29      paths.  Win32 paths in mount table entries may be UNC paths or
30      standard Win32 paths starting with <drive-letter>:
31
32      Text vs Binary issues are not considered here in path style
33      decisions, although the appropriate flags are retrieved and
34      stored in various structures.
35
36      Removing mounted filesystem support would simplify things greatly,
37      but having it gives us a mechanism of treating disk that lives on a
38      UNIX machine as having UNIX semantics [it allows one to edit a text
39      file on that disk and not have cr's magically appear and perhaps
40      break apps running on UNIX boxes].  It also useful to be able to
41      layout a hierarchy without changing the underlying directories.
42
43      The semantics of mounting file systems is not intended to precisely
44      follow normal UNIX systems.
45
46      Each DOS drive is defined to have a current directory.  Supporting
47      this would complicate things so for now things are defined so that
48      c: means c:\.
49   */
50
51 #include "winsup.h"
52 #include "miscfuncs.h"
53 #include <ctype.h>
54 #include <winioctl.h>
55 #include <wingdi.h>
56 #include <winuser.h>
57 #include <winnetwk.h>
58 #include <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 *s = strccpy (srcbuf, &src, src_delim);
1355       size_t len = s - srcbuf;
1356       if (len >= NT_MAX_PATH)
1357         {
1358           err = ENAMETOOLONG;
1359           break;
1360         }
1361       if (len)
1362         {
1363           ++d;
1364           err = cygwin_conv_path (conv_fn, srcbuf, d, size - (d - dst));
1365         }
1366       else if (!to_posix)
1367         {
1368           ++d;
1369           err = cygwin_conv_path (conv_fn, ".", d, size - (d - dst));
1370         }
1371       else
1372         {
1373           if (to_posix == ENV_CVT)
1374             saw_empty = true;
1375           continue;
1376         }
1377       if (err)
1378         break;
1379       d = strchr (d, '\0');
1380       *d = dst_delim;
1381     }
1382   while (*src++);
1383
1384   if (saw_empty)
1385     err = EIDRM;
1386
1387   if (d < dst)
1388     d++;
1389   *d = '\0';
1390   return err;
1391 }
1392
1393 /********************** Symbolic Link Support **************************/
1394
1395 /* Create a symlink from FROMPATH to TOPATH. */
1396
1397 /* If TRUE create symlinks as Windows shortcuts, if false create symlinks
1398    as normal files with magic number and system bit set. */
1399 bool allow_winsymlinks = false;
1400
1401 extern "C" int
1402 symlink (const char *oldpath, const char *newpath)
1403 {
1404   return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
1405 }
1406
1407 int
1408 symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
1409                 bool isdevice)
1410 {
1411   int res = -1;
1412   size_t len;
1413   path_conv win32_newpath, win32_oldpath;
1414   char *buf, *cp;
1415   SECURITY_ATTRIBUTES sa = sec_none_nih;
1416   OBJECT_ATTRIBUTES attr;
1417   IO_STATUS_BLOCK io;
1418   NTSTATUS status;
1419   HANDLE fh;
1420   tmp_pathbuf tp;
1421   unsigned check_opt;
1422   bool mk_winsym = use_winsym;
1423   bool has_trailing_dirsep = false;
1424
1425   /* POSIX says that empty 'newpath' is invalid input while empty
1426      'oldpath' is valid -- it's symlink resolver job to verify if
1427      symlink contents point to existing filesystem object */
1428   myfault efault;
1429   if (efault.faulted (EFAULT))
1430     goto done;
1431   if (!*oldpath || !*newpath)
1432     {
1433       set_errno (ENOENT);
1434       goto done;
1435     }
1436
1437   if (strlen (oldpath) > SYMLINK_MAX)
1438     {
1439       set_errno (ENAMETOOLONG);
1440       goto done;
1441     }
1442
1443   /* Trailing dirsep is a no-no. */
1444   len = strlen (newpath);
1445   has_trailing_dirsep = isdirsep (newpath[len - 1]);
1446   if (has_trailing_dirsep)
1447     {
1448       newpath = strdup (newpath);
1449       ((char *) newpath)[len - 1] = '\0';
1450     }
1451
1452   check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0);
1453   /* We need the normalized full path below. */
1454   win32_newpath.check (newpath, check_opt, stat_suffixes);
1455   /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O
1456      attribute.  Therefore we create symlinks on MVFS always as shortcuts. */
1457   mk_winsym |= win32_newpath.fs_is_mvfs ();
1458
1459   if (mk_winsym && !win32_newpath.exists ()
1460       && (isdevice || !win32_newpath.fs_is_nfs ()))
1461     {
1462       char *newplnk = tp.c_get ();
1463       stpcpy (stpcpy (newplnk, newpath), ".lnk");
1464       win32_newpath.check (newplnk, check_opt);
1465     }
1466
1467   if (win32_newpath.error)
1468     {
1469       set_errno (win32_newpath.error);
1470       goto done;
1471     }
1472
1473   syscall_printf ("symlink (%s, %S)", oldpath,
1474                   win32_newpath.get_nt_native_path ());
1475
1476   if ((!isdevice && win32_newpath.exists ())
1477       || win32_newpath.is_auto_device ())
1478     {
1479       set_errno (EEXIST);
1480       goto done;
1481     }
1482   if (has_trailing_dirsep && !win32_newpath.exists ())
1483     {
1484       set_errno (ENOENT);
1485       goto done;
1486     }
1487
1488   if (!isdevice && win32_newpath.fs_is_nfs ())
1489     {
1490       /* On NFS, create symlinks by calling NtCreateFile with an EA of type
1491          NfsSymlinkTargetName containing ... the symlink target name. */
1492       PFILE_FULL_EA_INFORMATION pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1493       pffei->NextEntryOffset = 0;
1494       pffei->Flags = 0;
1495       pffei->EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1496       char *EaValue = stpcpy (pffei->EaName, NFS_SYML_TARGET) + 1;
1497       pffei->EaValueLength = sizeof (WCHAR) *
1498         (sys_mbstowcs ((PWCHAR) EaValue, NT_MAX_PATH, oldpath) - 1);
1499       status = NtCreateFile (&fh, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE,
1500                              win32_newpath.get_object_attr (attr, sa),
1501                              &io, NULL, FILE_ATTRIBUTE_SYSTEM,
1502                              FILE_SHARE_VALID_FLAGS, FILE_CREATE,
1503                              FILE_SYNCHRONOUS_IO_NONALERT
1504                              | FILE_OPEN_FOR_BACKUP_INTENT,
1505                              pffei, NT_MAX_PATH * sizeof (WCHAR));
1506       if (!NT_SUCCESS (status))
1507         {
1508           __seterrno_from_nt_status (status);
1509           goto done;
1510         }
1511       NtClose (fh);
1512       res = 0;
1513       goto done;
1514     }
1515
1516   if (mk_winsym)
1517     {
1518       ITEMIDLIST *pidl = NULL;
1519       size_t full_len = 0;
1520       unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
1521       char desc[MAX_PATH + 1], *relpath;
1522
1523       if (!isdevice)
1524         {
1525           /* First create an IDLIST to learn how big our shortcut is
1526              going to be. */
1527           IShellFolder *psl;
1528
1529           /* The symlink target is relative to the directory in which
1530              the symlink gets created, not relative to the cwd.  Therefore
1531              we have to mangle the path quite a bit before calling path_conv. */
1532         if (isabspath (oldpath))
1533           win32_oldpath.check (oldpath,
1534                                PC_SYM_NOFOLLOW,
1535                                stat_suffixes);
1536         else
1537             {
1538               len = strrchr (win32_newpath.normalized_path, '/')
1539                     - win32_newpath.normalized_path + 1;
1540               char *absoldpath = tp.t_get ();
1541               stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
1542                       oldpath);
1543               win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1544             }
1545           if (SUCCEEDED (SHGetDesktopFolder (&psl)))
1546             {
1547               WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
1548               win32_oldpath.get_wide_win32_path (wc_path);
1549               /* Amazing but true:  Even though the ParseDisplayName method
1550                  takes a wide char path name, it does not understand the
1551                  Win32 prefix for long pathnames!  So we have to tack off
1552                  the prefix and convert the path to the "normal" syntax
1553                  for ParseDisplayName.  */
1554               WCHAR *wc = wc_path + 4;
1555               if (wc[1] != L':') /* native UNC path */
1556                 *(wc += 2) = L'\\';
1557               HRESULT res;
1558               if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
1559                                                     &pidl, NULL)))
1560                 {
1561                   ITEMIDLIST *p;
1562
1563                   for (p = pidl; p->mkid.cb > 0;
1564                        p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
1565                     ;
1566                   pidl_len = (char *) p - (char *) pidl + 2;
1567                 }
1568               psl->Release ();
1569             }
1570         }
1571       /* Compute size of shortcut file. */
1572       full_len = sizeof (win_shortcut_hdr);
1573       if (pidl_len)
1574         full_len += sizeof (unsigned short) + pidl_len;
1575       oldpath_len = strlen (oldpath);
1576       /* Unfortunately the length of the description is restricted to a
1577          length of MAX_PATH up to NT4, and to a length of 2000 bytes
1578          since W2K.  We don't want to add considerations for the different
1579          lengths and even 2000 bytes is not enough for long path names.
1580          So what we do here is to set the description to the POSIX path
1581          only if the path is not longer than MAX_PATH characters.  We
1582          append the full path name after the regular shortcut data
1583          (see below), which works fine with Windows Explorer as well
1584          as older Cygwin versions (as long as the whole file isn't bigger
1585          than 8K).  The description field is only used for backward
1586          compatibility to older Cygwin versions and those versions are
1587          not capable of handling long path names anyway. */
1588       desc_len = stpcpy (desc, oldpath_len > MAX_PATH
1589                                ? "[path too long]" : oldpath) - desc;
1590       full_len += sizeof (unsigned short) + desc_len;
1591       /* Devices get the oldpath string unchanged as relative path. */
1592       if (isdevice)
1593         {
1594           relpath_len = oldpath_len;
1595           stpcpy (relpath = tp.c_get (), oldpath);
1596         }
1597       else
1598         {
1599           relpath_len = strlen (win32_oldpath.get_win32 ());
1600           stpcpy (relpath = tp.c_get (), win32_oldpath.get_win32 ());
1601         }
1602       full_len += sizeof (unsigned short) + relpath_len;
1603       full_len += sizeof (unsigned short) + oldpath_len;
1604       /* 1 byte more for trailing 0 written by stpcpy. */
1605       if (full_len < NT_MAX_PATH * sizeof (WCHAR))
1606         buf = (char *) tp.w_get ();
1607       else
1608         buf = (char *) alloca (full_len + 1);
1609
1610       /* Create shortcut header */
1611       win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf;
1612       memset (shortcut_header, 0, sizeof *shortcut_header);
1613       shortcut_header->size = sizeof *shortcut_header;
1614       shortcut_header->magic = GUID_shortcut;
1615       shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH);
1616       if (pidl)
1617         shortcut_header->flags |= WSH_FLAG_IDLIST;
1618       shortcut_header->run = SW_NORMAL;
1619       cp = buf + sizeof (win_shortcut_hdr);
1620
1621       /* Create IDLIST */
1622       if (pidl)
1623         {
1624           *(unsigned short *)cp = pidl_len;
1625           memcpy (cp += 2, pidl, pidl_len);
1626           cp += pidl_len;
1627           CoTaskMemFree (pidl);
1628         }
1629
1630       /* Create description */
1631       *(unsigned short *)cp = desc_len;
1632       cp = stpcpy (cp += 2, desc);
1633
1634       /* Create relpath */
1635       *(unsigned short *)cp = relpath_len;
1636       cp = stpcpy (cp += 2, relpath);
1637
1638       /* Append the POSIX path after the regular shortcut data for
1639          the long path support. */
1640       unsigned short *plen = (unsigned short *) cp;
1641       cp += 2;
1642       *(PWCHAR) cp = 0xfeff;            /* BOM */
1643       cp += 2;
1644       *plen = sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1645       cp += *plen;
1646     }
1647   else
1648     {
1649       /* Default technique creating a symlink. */
1650       buf = (char *) tp.w_get ();
1651       cp = stpcpy (buf, SYMLINK_COOKIE);
1652       *(PWCHAR) cp = 0xfeff;            /* BOM */
1653       cp += 2;
1654       /* Note that the terminating nul is written.  */
1655       cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1656     }
1657
1658   if (isdevice && win32_newpath.exists ())
1659     {
1660       status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
1661                            win32_newpath.get_object_attr (attr, sa),
1662                            &io, 0, FILE_OPEN_FOR_BACKUP_INTENT);
1663       if (!NT_SUCCESS (status))
1664         {
1665           __seterrno_from_nt_status (status);
1666           goto done;
1667         }
1668       status = NtSetAttributesFile (fh, FILE_ATTRIBUTE_NORMAL);
1669       NtClose (fh);
1670       if (!NT_SUCCESS (status))
1671         {
1672           __seterrno_from_nt_status (status);
1673           goto done;
1674         }
1675     }
1676   status = NtCreateFile (&fh, DELETE | FILE_GENERIC_WRITE,
1677                          win32_newpath.get_object_attr (attr, sa),
1678                          &io, NULL, FILE_ATTRIBUTE_NORMAL,
1679                          FILE_SHARE_VALID_FLAGS,
1680                          isdevice ? FILE_OVERWRITE_IF : FILE_CREATE,
1681                          FILE_SYNCHRONOUS_IO_NONALERT
1682                          | FILE_NON_DIRECTORY_FILE
1683                          | FILE_OPEN_FOR_BACKUP_INTENT,
1684                          NULL, 0);
1685   if (!NT_SUCCESS (status))
1686     {
1687       __seterrno_from_nt_status (status);
1688       goto done;
1689     }
1690   if (win32_newpath.has_acls ())
1691     set_file_attribute (fh, win32_newpath, ILLEGAL_UID, ILLEGAL_GID,
1692                         (io.Information == FILE_CREATED ? S_JUSTCREATED : 0)
1693                         | S_IFLNK | STD_RBITS | STD_WBITS);
1694   status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL);
1695   if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf))
1696     {
1697       status = NtSetAttributesFile (fh, mk_winsym ? FILE_ATTRIBUTE_READONLY
1698                                                   : FILE_ATTRIBUTE_SYSTEM);
1699       if (!NT_SUCCESS (status))
1700         debug_printf ("Setting attributes failed, status = %p", status);
1701       res = 0;
1702     }
1703   else
1704     {
1705       __seterrno_from_nt_status (status);
1706       FILE_DISPOSITION_INFORMATION fdi = { TRUE };
1707       status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
1708                                      FileDispositionInformation);
1709       if (!NT_SUCCESS (status))
1710         debug_printf ("Setting delete dispostion failed, status = %p", status);
1711     }
1712   NtClose (fh);
1713
1714 done:
1715   syscall_printf ("%d = symlink_worker (%s, %s, %d, %d)", res, oldpath,
1716                   newpath, mk_winsym, isdevice);
1717   if (has_trailing_dirsep)
1718     free ((void *) newpath);
1719   return res;
1720 }
1721
1722 static bool
1723 cmp_shortcut_header (win_shortcut_hdr *file_header)
1724 {
1725   /* A Cygwin or U/Win shortcut only contains a description and a relpath.
1726      Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
1727      always set to SW_NORMAL. */
1728   return file_header->size == sizeof (win_shortcut_hdr)
1729       && !memcmp (&file_header->magic, &GUID_shortcut, sizeof GUID_shortcut)
1730       && (file_header->flags & ~WSH_FLAG_IDLIST)
1731          == (WSH_FLAG_DESC | WSH_FLAG_RELPATH)
1732       && file_header->run == SW_NORMAL;
1733 }
1734
1735 int
1736 symlink_info::check_shortcut (HANDLE h)
1737 {
1738   tmp_pathbuf tp;
1739   win_shortcut_hdr *file_header;
1740   char *buf, *cp;
1741   unsigned short len;
1742   int res = 0;
1743   NTSTATUS status;
1744   IO_STATUS_BLOCK io;
1745   FILE_STANDARD_INFORMATION fsi;
1746   LARGE_INTEGER off = { QuadPart:0LL };
1747
1748   status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
1749                                    FileStandardInformation);
1750   if (!NT_SUCCESS (status))
1751     {
1752       set_error (EIO);
1753       return 0;
1754     }
1755   if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
1756       || fsi.EndOfFile.QuadPart > 4 * 65536)
1757     return 0;
1758   if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
1759     buf = (char *) tp.w_get ();
1760   else
1761     buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
1762   status = NtReadFile (h, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
1763                        &off, NULL);
1764   if (!NT_SUCCESS (status))
1765     {
1766       if (status != STATUS_END_OF_FILE)
1767         set_error (EIO);
1768       return 0;
1769     }
1770   file_header = (win_shortcut_hdr *) buf;
1771   if (io.Information != fsi.EndOfFile.LowPart
1772       || !cmp_shortcut_header (file_header))
1773     return 0;
1774   cp = buf + sizeof (win_shortcut_hdr);
1775   if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
1776     cp += *(unsigned short *) cp + 2;
1777   if (!(len = *(unsigned short *) cp))
1778     return 0;
1779   cp += 2;
1780   /* Check if this is a device file - these start with the sequence :\\ */
1781   if (strncmp (cp, ":\\", 2) == 0)
1782     res = strlen (strcpy (contents, cp)); /* Don't mess with device files */
1783   else
1784     {
1785       /* Has appended full path?  If so, use it instead of description. */
1786       unsigned short relpath_len = *(unsigned short *) (cp + len);
1787       if (cp + len + 2 + relpath_len < buf + fsi.EndOfFile.LowPart)
1788         {
1789           cp += len + 2 + relpath_len;
1790           len = *(unsigned short *) cp;
1791           cp += 2;
1792         }
1793       if (*(PWCHAR) cp == 0xfeff)       /* BOM */
1794         {
1795           char *tmpbuf = tp.c_get ();
1796           if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2))
1797               > SYMLINK_MAX + 1)
1798             return 0;
1799           res = posixify (tmpbuf);
1800         }
1801       else if (len > SYMLINK_MAX)
1802         return 0;
1803       else
1804         {
1805           cp[len] = '\0';
1806           res = posixify (cp);
1807         }
1808     }
1809   if (res) /* It's a symlink.  */
1810     pflags |= PATH_SYMLINK | PATH_LNK;
1811   return res;
1812 }
1813
1814 int
1815 symlink_info::check_sysfile (HANDLE h)
1816 {
1817   tmp_pathbuf tp;
1818   char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
1819   char *srcbuf = tp.c_get ();
1820   int res = 0;
1821   NTSTATUS status;
1822   IO_STATUS_BLOCK io;
1823   bool interix_symlink = false;
1824   LARGE_INTEGER off = { QuadPart:0LL };
1825
1826   status = NtReadFile (h, NULL, NULL, NULL, &io, cookie_buf,
1827                        sizeof (cookie_buf), &off, NULL);
1828   if (!NT_SUCCESS (status))
1829     {
1830       debug_printf ("ReadFile1 failed %p", status);
1831       if (status != STATUS_END_OF_FILE)
1832         set_error (EIO);
1833       return 0;
1834     }
1835   off.QuadPart = io.Information;
1836   if (io.Information == sizeof (cookie_buf)
1837            && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
1838     {
1839       /* It's a symlink.  */
1840       pflags |= PATH_SYMLINK;
1841     }
1842   else if (io.Information == sizeof (cookie_buf)
1843            && memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
1844     pflags |= PATH_SOCKET;
1845   else if (io.Information >= sizeof (INTERIX_SYMLINK_COOKIE)
1846            && memcmp (cookie_buf, INTERIX_SYMLINK_COOKIE,
1847                       sizeof (INTERIX_SYMLINK_COOKIE) - 1) == 0)
1848     {
1849       /* It's an Interix symlink.  */
1850       pflags |= PATH_SYMLINK;
1851       interix_symlink = true;
1852       /* Interix symlink cookies are shorter than Cygwin symlink cookies, so
1853          in case of an Interix symlink cooky we have read too far into the
1854          file.  Set file pointer back to the position right after the cookie. */
1855       off.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1;
1856     }
1857   if (pflags & PATH_SYMLINK)
1858     {
1859       status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
1860                            NT_MAX_PATH, &off, NULL);
1861       if (!NT_SUCCESS (status))
1862         {
1863           debug_printf ("ReadFile2 failed");
1864           if (status != STATUS_END_OF_FILE)
1865             set_error (EIO);
1866         }
1867       else if (*(PWCHAR) srcbuf == 0xfeff       /* BOM */
1868                || interix_symlink)
1869         {
1870           /* Add trailing 0 to Interix symlink target.  Skip BOM in Cygwin
1871              symlinks. */
1872           if (interix_symlink)
1873             ((PWCHAR) srcbuf)[io.Information / sizeof (WCHAR)] = L'\0';
1874           else
1875             srcbuf += 2;
1876           char *tmpbuf = tp.c_get ();
1877           if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) srcbuf)
1878               > SYMLINK_MAX + 1)
1879             debug_printf ("symlink string too long");
1880           else
1881             res = posixify (tmpbuf);
1882         }
1883       else if (io.Information > SYMLINK_MAX + 1)
1884         debug_printf ("symlink string too long");
1885       else
1886         res = posixify (srcbuf);
1887     }
1888   return res;
1889 }
1890
1891 int
1892 symlink_info::check_reparse_point (HANDLE h)
1893 {
1894   tmp_pathbuf tp;
1895   NTSTATUS status;
1896   IO_STATUS_BLOCK io;
1897   PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) tp.c_get ();
1898   UNICODE_STRING subst;
1899   char srcbuf[SYMLINK_MAX + 7];
1900
1901   status = NtFsControlFile (h, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT,
1902                             NULL, 0, (LPVOID) rp,
1903                             MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1904   if (!NT_SUCCESS (status))
1905     {
1906       debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %p",
1907                     status);
1908       set_error (EIO);
1909       return 0;
1910     }
1911   if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
1912     RtlInitCountedUnicodeString (&subst,
1913                   (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
1914                         + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset),
1915                   rp->SymbolicLinkReparseBuffer.SubstituteNameLength);
1916   else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
1917     {
1918       RtlInitCountedUnicodeString (&subst, 
1919                   (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
1920                           + rp->MountPointReparseBuffer.SubstituteNameOffset),
1921                   rp->MountPointReparseBuffer.SubstituteNameLength);
1922       if (RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE))
1923         {
1924           /* Volume mount point.  Not treated as symlink. The return
1925              value of -1 is a hint for the caller to treat this as a
1926              volume mount point. */
1927           return -1;
1928         }
1929     }
1930   else
1931     {
1932       /* Maybe it's a reparse point, but it's certainly not one we
1933          recognize.  Drop the REPARSE file attribute so we don't even
1934          try to use the flag for some special handling.  It's just some
1935          arbitrary file or directory for us. */
1936       fileattr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1937       return 0;
1938     }
1939   sys_wcstombs (srcbuf, SYMLINK_MAX + 7, subst.Buffer,
1940                 subst.Length / sizeof (WCHAR));
1941   pflags |= PATH_SYMLINK | PATH_REP;
1942   /* A symlink is never a directory. */
1943   fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
1944   return posixify (srcbuf);
1945 }
1946
1947 int
1948 symlink_info::check_nfs_symlink (HANDLE h)
1949 {
1950   tmp_pathbuf tp;
1951   NTSTATUS status;
1952   IO_STATUS_BLOCK io;
1953   struct {
1954     FILE_GET_EA_INFORMATION fgei;
1955     char buf[sizeof (NFS_SYML_TARGET)];
1956   } fgei_buf;
1957   PFILE_FULL_EA_INFORMATION pffei;
1958   int res = 0;
1959
1960   /* To find out if the file is a symlink and to get the symlink target,
1961      try to fetch the NfsSymlinkTargetName EA. */
1962   fgei_buf.fgei.NextEntryOffset = 0;
1963   fgei_buf.fgei.EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1964   stpcpy (fgei_buf.fgei.EaName, NFS_SYML_TARGET);
1965   pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1966   status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE,
1967                           &fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
1968   if (NT_SUCCESS (status) && pffei->EaValueLength > 0)
1969     {
1970       PWCHAR spath = (PWCHAR)
1971                      (pffei->EaName + pffei->EaNameLength + 1);
1972       res = sys_wcstombs (contents, SYMLINK_MAX + 1,
1973                           spath, pffei->EaValueLength) - 1;
1974       pflags |= PATH_SYMLINK;
1975     }
1976   return res;
1977 }
1978
1979 int
1980 symlink_info::posixify (char *srcbuf)
1981 {
1982   /* The definition for a path in a native symlink is a bit weird.  The Flags
1983      value seem to contain 0 for absolute paths (stored as NT native path)
1984      and 1 for relative paths.  Relative paths are paths not starting with a
1985      drive letter.  These are not converted to NT native, but stored as
1986      given.  A path starting with a single backslash is relative to the
1987      current drive thus a "relative" value (Flags == 1).
1988      Funny enough it's possible to store paths with slashes instead of
1989      backslashes, but they are evaluated incorrectly by subsequent Windows
1990      calls like CreateFile (ERROR_INVALID_NAME).  So, what we do here is to
1991      take paths starting with slashes at face value, evaluating them as
1992      Cygwin specific POSIX paths.
1993      A path starting with two slashes(!) or backslashes is converted into an
1994      NT UNC path.  Unfortunately, in contrast to POSIX rules, paths starting
1995      with three or more (back)slashes are also converted into UNC paths,
1996      just incorrectly sticking to one redundant leading backslashe.  We go
1997      along with this behaviour to avoid scenarios in which native tools access
1998      other files than Cygwin.
1999      The above rules are used exactly the same way on Cygwin specific symlinks
2000      (sysfiles and shortcuts) to eliminate non-POSIX paths in the output. */
2001
2002   /* Eliminate native NT prefixes. */
2003   if (srcbuf[0] == '\\' && !strncmp (srcbuf + 1, "??\\", 3))
2004     {
2005       srcbuf += 4;
2006       if (srcbuf[1] != ':') /* native UNC path */
2007         *(srcbuf += 2) = '\\';
2008     }
2009   if (isdrive (srcbuf))
2010     mount_table->conv_to_posix_path (srcbuf, contents, 0);
2011   else if (srcbuf[0] == '\\')
2012     {
2013       if (srcbuf[1] == '\\') /* UNC path */
2014         slashify (srcbuf, contents, 0);
2015       else /* Paths starting with \ are current drive relative. */
2016         {
2017           char cvtbuf[SYMLINK_MAX + 1];
2018
2019           stpcpy (cvtbuf + cygheap->cwd.get_drive (cvtbuf), srcbuf);
2020           mount_table->conv_to_posix_path (cvtbuf, contents, 0);
2021         }
2022     }
2023   else /* Everything else is taken as is. */
2024     slashify (srcbuf, contents, 0);
2025   return strlen (contents);
2026 }
2027
2028 enum
2029 {
2030   SCAN_BEG,
2031   SCAN_LNK,
2032   SCAN_HASLNK,
2033   SCAN_JUSTCHECK,
2034   SCAN_JUSTCHECKTHIS, /* Never try to append a suffix. */
2035   SCAN_APPENDLNK,
2036   SCAN_EXTRALNK,
2037   SCAN_DONE,
2038 };
2039
2040 class suffix_scan
2041 {
2042   const suffix_info *suffixes, *suffixes_start;
2043   int nextstate;
2044   char *eopath;
2045 public:
2046   const char *path;
2047   char *has (const char *, const suffix_info *);
2048   int next ();
2049   int lnk_match () {return nextstate >= SCAN_APPENDLNK;}
2050 };
2051
2052 char *
2053 suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
2054 {
2055   nextstate = SCAN_BEG;
2056   suffixes = suffixes_start = in_suffixes;
2057
2058   const char *fname = strrchr (in_path, '\\');
2059   fname = fname ? fname + 1 : in_path;
2060   char *ext_here = strrchr (fname, '.');
2061   path = in_path;
2062   eopath = strchr (path, '\0');
2063
2064   if (!ext_here)
2065     goto noext;
2066
2067   if (suffixes)
2068     {
2069       /* Check if the extension matches a known extension */
2070       for (const suffix_info *ex = in_suffixes; ex->name != NULL; ex++)
2071         if (ascii_strcasematch (ext_here, ex->name))
2072           {
2073             nextstate = SCAN_JUSTCHECK;
2074             suffixes = NULL;    /* Has an extension so don't scan for one. */
2075             goto done;
2076           }
2077     }
2078
2079   /* Didn't match.  Use last resort -- .lnk. */
2080   if (ascii_strcasematch (ext_here, ".lnk"))
2081     {
2082       nextstate = SCAN_HASLNK;
2083       suffixes = NULL;
2084     }
2085
2086  noext:
2087   ext_here = eopath;
2088
2089  done:
2090   /* Avoid attaching suffixes if the resulting filename would be invalid. */
2091   if (eopath - fname > NAME_MAX - 4)
2092     {
2093       nextstate = SCAN_JUSTCHECKTHIS;
2094       suffixes = NULL;
2095     }
2096   return ext_here;
2097 }
2098
2099 int
2100 suffix_scan::next ()
2101 {
2102   for (;;)
2103     {
2104       if (!suffixes)
2105         switch (nextstate)
2106           {
2107           case SCAN_BEG:
2108             suffixes = suffixes_start;
2109             if (!suffixes)
2110               {
2111                 nextstate = SCAN_LNK;
2112                 return 1;
2113               }
2114             nextstate = SCAN_EXTRALNK;
2115             /* fall through to suffix checking below */
2116             break;
2117           case SCAN_HASLNK:
2118             nextstate = SCAN_APPENDLNK; /* Skip SCAN_BEG */
2119             return 1;
2120           case SCAN_EXTRALNK:
2121             nextstate = SCAN_DONE;
2122             *eopath = '\0';
2123             return 0;
2124           case SCAN_JUSTCHECK:
2125             nextstate = SCAN_LNK;
2126             return 1;
2127           case SCAN_JUSTCHECKTHIS:
2128             nextstate = SCAN_DONE;
2129             return 1;
2130           case SCAN_LNK:
2131           case SCAN_APPENDLNK:
2132             strcat (eopath, ".lnk");
2133             nextstate = SCAN_DONE;
2134             return 1;
2135           default:
2136             *eopath = '\0';
2137             return 0;
2138           }
2139
2140       while (suffixes && suffixes->name)
2141         if (nextstate == SCAN_EXTRALNK && !suffixes->addon)
2142           suffixes++;
2143         else
2144           {
2145             strcpy (eopath, suffixes->name);
2146             if (nextstate == SCAN_EXTRALNK)
2147               strcat (eopath, ".lnk");
2148             suffixes++;
2149             return 1;
2150           }
2151       suffixes = NULL;
2152     }
2153 }
2154
2155 bool
2156 symlink_info::set_error (int in_errno)
2157 {
2158   bool res;
2159   if (!(pflags & PATH_NO_ACCESS_CHECK) || in_errno == ENAMETOOLONG || in_errno == EIO)
2160     {
2161       error = in_errno;
2162       res = true;
2163     }
2164   else if (in_errno == ENOENT)
2165     res = true;
2166   else
2167     {
2168       fileattr = FILE_ATTRIBUTE_NORMAL;
2169       res = false;
2170     }
2171   return res;
2172 }
2173
2174 bool
2175 symlink_info::parse_device (const char *contents)
2176 {
2177   char *endptr;
2178   _major_t mymajor;
2179   _major_t myminor;
2180   _mode_t mymode;
2181
2182   mymajor = strtol (contents += 2, &endptr, 16);
2183   if (endptr == contents)
2184     return isdevice = false;
2185
2186   contents = endptr;
2187   myminor = strtol (++contents, &endptr, 16);
2188   if (endptr == contents)
2189     return isdevice = false;
2190
2191   contents = endptr;
2192   mymode = strtol (++contents, &endptr, 16);
2193   if (endptr == contents)
2194     return isdevice = false;
2195
2196   if ((mymode & S_IFMT) == S_IFIFO)
2197     {
2198       mymajor = _major (FH_FIFO);
2199       myminor = _minor (FH_FIFO);
2200     }
2201
2202   major = mymajor;
2203   minor = myminor;
2204   mode = mymode;
2205   return isdevice = true;
2206 }
2207
2208 /* Check if PATH is a symlink.  PATH must be a valid Win32 path name.
2209
2210    If PATH is a symlink, put the value of the symlink--the file to
2211    which it points--into BUF.  The value stored in BUF is not
2212    necessarily null terminated.  BUFLEN is the length of BUF; only up
2213    to BUFLEN characters will be stored in BUF.  BUF may be NULL, in
2214    which case nothing will be stored.
2215
2216    Set *SYML if PATH is a symlink.
2217
2218    Set *EXEC if PATH appears to be executable.  This is an efficiency
2219    hack because we sometimes have to open the file anyhow.  *EXEC will
2220    not be set for every executable file.
2221
2222    Return -1 on error, 0 if PATH is not a symlink, or the length
2223    stored into BUF if PATH is a symlink.  */
2224
2225 int
2226 symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs,
2227                      path_conv_handle &conv_hdl)
2228 {
2229   int res;
2230   HANDLE h;
2231   NTSTATUS status;
2232   UNICODE_STRING upath;
2233   OBJECT_ATTRIBUTES attr;
2234   IO_STATUS_BLOCK io;
2235   suffix_scan suffix;
2236
2237   const ULONG ci_flag = cygwin_shared->obcaseinsensitive
2238                         || (pflags & PATH_NOPOSIX) ? OBJ_CASE_INSENSITIVE : 0;
2239   /* TODO: Temporarily do all char->UNICODE conversion here.  This should
2240      already be slightly faster than using Ascii functions. */
2241   tmp_pathbuf tp;
2242   tp.u_get (&upath);
2243   InitializeObjectAttributes (&attr, &upath, ci_flag, NULL, NULL);
2244
2245   /* This label is used in case we encounter a FS which only handles
2246      DOS paths.  See below. */
2247   bool restarted = false;
2248 restart:
2249
2250   h = NULL;
2251   res = 0;
2252   contents[0] = '\0';
2253   issymlink = true;
2254   isdevice = false;
2255   major = 0;
2256   minor = 0;
2257   mode = 0;
2258   pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
2259
2260   ext_here = suffix.has (path, suffixes);
2261   extn = ext_here - path;
2262
2263   PVOID eabuf = &nfs_aol_ffei;
2264   ULONG easize = sizeof nfs_aol_ffei;
2265
2266   bool had_ext = !!*ext_here;
2267   while (suffix.next ())
2268     {
2269       bool no_ea = false;
2270
2271       error = 0;
2272       get_nt_native_path (suffix.path, upath, pflags & PATH_DOS);
2273       if (h)
2274         {
2275           NtClose (h);
2276           h = NULL;
2277         }
2278       /* The EA given to NtCreateFile allows to get a handle to a symlink on
2279          an NFS share, rather than getting a handle to the target of the
2280          symlink (which would spoil the task of this method quite a bit).
2281          Fortunately it's ignored on most other file systems so we don't have
2282          to special case NFS too much. */
2283       status = NtCreateFile (&h,
2284                              READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA,
2285                              &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS,
2286                              FILE_OPEN,
2287                              FILE_OPEN_REPARSE_POINT
2288                              | FILE_OPEN_FOR_BACKUP_INTENT,
2289                              eabuf, easize);
2290       debug_printf ("%p = NtCreateFile (%S)", status, &upath);
2291       /* No right to access EAs or EAs not supported? */
2292       if (!NT_SUCCESS (status)
2293           && (status == STATUS_ACCESS_DENIED
2294               || status == STATUS_EAS_NOT_SUPPORTED
2295               || status == STATUS_NOT_SUPPORTED
2296               || status == STATUS_INVALID_NETWORK_RESPONSE
2297               /* Or a bug in Samba 3.2.x (x <= 7) when accessing a share's
2298                  root dir which has EAs enabled? */
2299               || status == STATUS_INVALID_PARAMETER))
2300         {
2301           no_ea = true;
2302           /* If EAs are not supported, there's no sense to check them again
2303              with suffixes attached.  So we set eabuf/easize to 0 here once. */
2304           if (status == STATUS_EAS_NOT_SUPPORTED
2305               || status == STATUS_NOT_SUPPORTED)
2306             {
2307               eabuf = NULL;
2308               easize = 0;
2309             }
2310           status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2311                                &attr, &io, FILE_SHARE_VALID_FLAGS,
2312                                FILE_OPEN_REPARSE_POINT
2313                                | FILE_OPEN_FOR_BACKUP_INTENT);
2314           debug_printf ("%p = NtOpenFile (no-EAs %S)", status, &upath);
2315         }
2316       if (status == STATUS_OBJECT_NAME_NOT_FOUND)
2317         {
2318           if (ci_flag == 0 && wincap.has_broken_udf ()
2319               && (!fs.inited () || fs.is_udf ()))
2320             {
2321               /* On NT 5.x UDF is broken (at least) in terms of case
2322                  sensitivity.  When trying to open a file case sensitive,
2323                  the file appears to be non-existant.  Another bug is
2324                  described in fs_info::update. */
2325               attr.Attributes = OBJ_CASE_INSENSITIVE;
2326               status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2327                                    &attr, &io, FILE_SHARE_VALID_FLAGS,
2328                                    FILE_OPEN_REPARSE_POINT
2329                                    | FILE_OPEN_FOR_BACKUP_INTENT);
2330               debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath);
2331               attr.Attributes = 0;
2332               if (NT_SUCCESS (status))
2333                 {
2334                   if (!fs.inited ())
2335                     fs.update (&upath, h);
2336                   if (!fs.is_udf ())
2337                     {
2338                       NtClose (h);
2339                       h = NULL;
2340                       status = STATUS_OBJECT_NAME_NOT_FOUND;
2341                     }
2342                 }
2343             }
2344           /* There are filesystems out in the wild (Netapp, NWFS, and others)
2345              which are uncapable of generating pathnames outside the Win32
2346              rules.  That means, filenames on these FSes must not have a
2347              leading space or trailing dots and spaces.  This code snippet
2348              manages them.  I really hope it's streamlined enough not to
2349              slow down normal operation.  This extra check only kicks in if
2350              we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't
2351              already attach a suffix *and* the above special case for UDF
2352              on XP didn't succeeed. */
2353           if (!restarted && !*ext_here && !(pflags & PATH_DOS) && !fs.inited ())
2354             {
2355               /* Check for trailing dot or space or leading space in
2356                  last component. */
2357               char *p = ext_here - 1;
2358               if (*p != '.' && *p != ' ')
2359                 {
2360                   while (*--p != '\\')
2361                     ;
2362                   if (*++p != ' ')
2363                     p = NULL;
2364                 }
2365               if (p)
2366                 {
2367                   /* If so, check if file resides on one of the known broken
2368                      FSes only supporting filenames following DOS rules. */
2369                   if (!fs.inited ())
2370                     fs.update (&upath, NULL);
2371                   if (fs.has_dos_filenames_only ())
2372                     {
2373                       /* If so, try again.  Since we now know the FS, the
2374                          filenames will be tweaked to follow DOS rules via the
2375                          third parameter in the call to get_nt_native_path. */
2376                       pflags |= PATH_DOS;
2377                       restarted = true;
2378                       goto restart;
2379                     }
2380                 }
2381             }
2382         }
2383
2384       if (NT_SUCCESS (status)
2385           /* Check file system while we're having the file open anyway.
2386              This speeds up path_conv noticably (~10%). */
2387           && (fs.inited () || fs.update (&upath, h)))
2388         {
2389           if (fs.is_nfs ())
2390             {
2391               status = nfs_fetch_fattr3 (h, conv_hdl.nfsattr ());
2392               if (NT_SUCCESS (status))
2393                 fileattr = ((conv_hdl.nfsattr ()->type & 7) == NF3DIR)
2394                             ? FILE_ATTRIBUTE_DIRECTORY : 0;
2395             }
2396           else
2397             {
2398               PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2399
2400               /* Netapps don't implement FileNetworkOpenInformation. */
2401               status = fs.is_netapp ()
2402                        ? STATUS_INVALID_PARAMETER
2403                        : NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi,
2404                                                  FileNetworkOpenInformation);
2405               if (status == STATUS_INVALID_PARAMETER
2406                   || status == STATUS_NOT_IMPLEMENTED)
2407                 {
2408                   /* Apart from accessing Netapps, this also occurs when
2409                      accessing SMB share root dirs hosted on NT4
2410                      (STATUS_INVALID_PARAMETER), or when trying to access
2411                      SMB share root dirs from NT4 (STATUS_NOT_IMPLEMENTED). */
2412                   FILE_BASIC_INFORMATION fbi;
2413                   FILE_STANDARD_INFORMATION fsi;
2414
2415                   status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
2416                                                    FileBasicInformation);
2417                   if (NT_SUCCESS (status))
2418                     {
2419                       memcpy (pfnoi, &fbi, 4 * sizeof (LARGE_INTEGER));
2420                       if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fsi,
2421                                                      sizeof fsi,
2422                                                      FileStandardInformation)))
2423                         {
2424                           pfnoi->EndOfFile.QuadPart = fsi.EndOfFile.QuadPart;
2425                           pfnoi->AllocationSize.QuadPart
2426                             = fsi.AllocationSize.QuadPart;
2427                         }
2428                       else
2429                         pfnoi->EndOfFile.QuadPart
2430                           = pfnoi->AllocationSize.QuadPart = 0;
2431                       pfnoi->FileAttributes = fbi.FileAttributes;
2432                     }
2433                 }
2434               if (NT_SUCCESS (status))
2435                 fileattr = pfnoi->FileAttributes;
2436             }
2437         }
2438       if (!NT_SUCCESS (status))
2439         {
2440           debug_printf ("%p = NtQueryInformationFile (%S)", status, &upath);
2441           fileattr = INVALID_FILE_ATTRIBUTES;
2442
2443           /* One of the inner path components is invalid, or the path contains
2444              invalid characters.  Bail out with ENOENT.
2445
2446              Note that additional STATUS_OBJECT_PATH_INVALID and
2447              STATUS_OBJECT_PATH_SYNTAX_BAD status codes exist.  The first one
2448              is seemingly not generated by NtQueryInformationFile, the latter
2449              is only generated if the path is no absolute path within the
2450              NT name space, which should not happen and would point to an
2451              error in get_nt_native_path.  Both status codes are deliberately
2452              not tested here unless proved necessary. */
2453           if (status == STATUS_OBJECT_PATH_NOT_FOUND
2454               || status == STATUS_OBJECT_NAME_INVALID
2455               || status == STATUS_BAD_NETWORK_PATH
2456               || status == STATUS_BAD_NETWORK_NAME
2457               || status == STATUS_NO_MEDIA_IN_DEVICE)
2458             {
2459               set_error (ENOENT);
2460               goto file_not_symlink;
2461             }
2462           if (status != STATUS_OBJECT_NAME_NOT_FOUND
2463               && status != STATUS_NO_SUCH_FILE) /* ENOENT on NFS or 9x share */
2464             {
2465               /* The file exists, but the user can't access it for one reason
2466                  or the other.  To get the file attributes we try to access the
2467                  information by opening the parent directory and getting the
2468                  file attributes using a matching NtQueryDirectoryFile call. */
2469               UNICODE_STRING dirname, basename;
2470               OBJECT_ATTRIBUTES dattr;
2471               HANDLE dir;
2472               struct {
2473                 FILE_BOTH_DIRECTORY_INFORMATION fdi;
2474                 WCHAR dummy_buf[NAME_MAX + 1];
2475               } fdi_buf;
2476
2477               RtlSplitUnicodePath (&upath, &dirname, &basename);
2478               InitializeObjectAttributes (&dattr, &dirname, ci_flag,
2479                                           NULL, NULL);
2480               status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
2481                                    &dattr, &io, FILE_SHARE_VALID_FLAGS,
2482                                    FILE_SYNCHRONOUS_IO_NONALERT
2483                                    | FILE_OPEN_FOR_BACKUP_INTENT
2484                                    | FILE_DIRECTORY_FILE);
2485               if (!NT_SUCCESS (status))
2486                 {
2487                   debug_printf ("%p = NtOpenFile(%S)", status, &dirname);
2488                   /* There's a special case if the file is itself the root
2489                      of a drive which is not accessible by the current user.
2490                      This case is only recognized by the length of the
2491                      basename part.  If it's 0, the incoming file is the
2492                      root of a drive.  So we at least know it's a directory. */
2493                   fileattr = basename.Length ? 0 : FILE_ATTRIBUTE_DIRECTORY;
2494                 }
2495               else
2496                 {
2497                   status = NtQueryDirectoryFile (dir, NULL, NULL, NULL, &io,
2498                                                  &fdi_buf, sizeof fdi_buf,
2499                                                  FileBothDirectoryInformation,
2500                                                  TRUE, &basename, TRUE);
2501                   /* Take the opportunity to check file system while we're
2502                      having the handle to the parent dir. */
2503                   fs.update (&upath, dir);
2504                   NtClose (dir);
2505                   if (!NT_SUCCESS (status))
2506                     {
2507                       debug_printf ("%p = NtQueryDirectoryFile(%S)",
2508                                     status, &dirname);
2509                       if (status == STATUS_NO_SUCH_FILE)
2510                         {
2511                           /* This can happen when trying to access files
2512                              which match DOS device names on SMB shares.
2513                              NtOpenFile failed with STATUS_ACCESS_DENIED,
2514                              but the NtQueryDirectoryFile tells us the
2515                              file doesn't exist.  We're suspicious in this
2516                              case and retry with the next suffix instead of
2517                              just giving up. */
2518                           set_error (ENOENT);
2519                           continue;
2520                         }
2521                       fileattr = 0;
2522                     }
2523                   else
2524                     {
2525                       PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2526
2527                       fileattr = fdi_buf.fdi.FileAttributes;
2528                       memcpy (pfnoi, &fdi_buf.fdi.CreationTime, sizeof *pfnoi);
2529                       /* Amazing, but true:  The FILE_NETWORK_OPEN_INFORMATION
2530                          structure has the AllocationSize and EndOfFile members
2531                          interchanged relative to the directory information
2532                          classes. */
2533                       pfnoi->AllocationSize.QuadPart
2534                         = fdi_buf.fdi.AllocationSize.QuadPart;
2535                       pfnoi->EndOfFile.QuadPart
2536                         = fdi_buf.fdi.EndOfFile.QuadPart;
2537                     }
2538                 }
2539               ext_tacked_on = !!*ext_here;
2540               goto file_not_symlink;
2541             }
2542           set_error (ENOENT);
2543           continue;
2544         }
2545
2546       ext_tacked_on = !!*ext_here;
2547       /* Don't allow to returns directories with appended suffix.  If we found
2548          a directory with a suffix which has been appended here, then this
2549          directory doesn't match the request.  So, just do as usual if file
2550          hasn't been found. */
2551       if (ext_tacked_on && !had_ext && (fileattr & FILE_ATTRIBUTE_DIRECTORY))
2552         {
2553           set_error (ENOENT);
2554           continue;
2555         }
2556
2557       res = -1;
2558
2559       /* Reparse points are potentially symlinks.  This check must be
2560          performed before checking the SYSTEM attribute for sysfile
2561          symlinks, since reparse points can have this flag set, too.
2562          For instance, Vista starts to create a couple of reparse points
2563          with SYSTEM and HIDDEN flags set. */
2564       if ((fileattr & FILE_ATTRIBUTE_REPARSE_POINT))
2565         {
2566           /* Don't check reparse points on remote filesystems.  A reparse point
2567              pointing to another file on the remote system will be mistreated
2568              as pointing to a local file on the local system.  This breaks the
2569              way reparse points are transparently handled on remote systems. */
2570           if (fs.is_remote_drive())
2571             res = 0;
2572           else
2573             res = check_reparse_point (h);
2574           if (res == -1)
2575             {
2576               /* Volume mount point.  The filesystem information for the top
2577                  level directory should be for the volume top level directory,
2578                  rather than for the reparse point itself.  So we fetch the
2579                  filesystem information again, but with a NULL handle.
2580                  This does what we want because fs_info::update opens the
2581                  handle without FILE_OPEN_REPARSE_POINT. */
2582               fs.update (&upath, NULL);
2583               /* Make sure the open handle is not used in later stat calls.
2584                  The handle has been opened with the FILE_OPEN_REPARSE_POINT
2585                  flag, so it's a handle to the reparse point, not a handle
2586                  to the volumes root dir. */
2587               pflags &= ~PC_KEEP_HANDLE;
2588             }
2589           else if (res)
2590             {
2591               /* A symlink is never a directory. */
2592               conv_hdl.fnoi ()->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
2593               break;
2594             }
2595         }
2596
2597       /* Windows shortcuts are potentially treated as symlinks.  Valid Cygwin
2598          & U/WIN shortcuts are R/O, but definitely not directories. */
2599       else if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
2600           == FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
2601         {
2602           HANDLE sym_h;
2603
2604           status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2605                                FILE_SHARE_VALID_FLAGS,
2606                                FILE_OPEN_FOR_BACKUP_INTENT
2607                                | FILE_SYNCHRONOUS_IO_NONALERT);
2608           if (!NT_SUCCESS (status))
2609             res = 0;
2610           else
2611             {
2612               res = check_shortcut (sym_h);
2613               NtClose (sym_h);
2614             }
2615           if (!res)
2616             {
2617               /* If searching for `foo' and then finding a `foo.lnk' which
2618                  is no shortcut, return the same as if file not found. */
2619               if (ext_tacked_on)
2620                 {
2621                   fileattr = INVALID_FILE_ATTRIBUTES;
2622                   set_error (ENOENT);
2623                   continue;
2624                 }
2625             }
2626           else if (contents[0] != ':' || contents[1] != '\\'
2627                    || !parse_device (contents))
2628             break;
2629         }
2630
2631       /* If searching for `foo' and then finding a `foo.lnk' which is
2632          no shortcut, return the same as if file not found. */
2633       else if (suffix.lnk_match () && ext_tacked_on)
2634         {
2635           fileattr = INVALID_FILE_ATTRIBUTES;
2636           set_error (ENOENT);
2637           continue;
2638         }
2639
2640       /* This is the old Cygwin method creating symlinks.  A symlink will
2641          have the `system' file attribute.  Only files can be symlinks
2642          (which can be symlinks to directories). */
2643       else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))
2644                == FILE_ATTRIBUTE_SYSTEM)
2645         {
2646           HANDLE sym_h;
2647
2648           status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2649                                FILE_SHARE_VALID_FLAGS,
2650                                FILE_OPEN_FOR_BACKUP_INTENT
2651                                | FILE_SYNCHRONOUS_IO_NONALERT);
2652
2653           if (!NT_SUCCESS (status))
2654             res = 0;
2655           else
2656             {
2657               res = check_sysfile (sym_h);
2658               NtClose (sym_h);
2659             }
2660           if (res)
2661             break;
2662         }
2663
2664       /* If the file is on an NFS share and could be opened with extended
2665          attributes, check if it's a symlink.  Only files can be symlinks
2666          (which can be symlinks to directories). */
2667       else if (fs.is_nfs () && (conv_hdl.nfsattr ()->type & 7) == NF3LNK)
2668         {
2669           res = check_nfs_symlink (h);
2670           if (res)
2671             break;
2672         }
2673
2674     /* Normal file. */
2675     file_not_symlink:
2676       issymlink = false;
2677       syscall_printf ("%s", isdevice ? "is a device" : "not a symlink");
2678       res = 0;
2679       break;
2680     }
2681
2682   if (h)
2683     {
2684       if (pflags & PC_KEEP_HANDLE)
2685         conv_hdl.set (h);
2686       else
2687         NtClose (h);
2688     }
2689
2690   syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2691                   res, suffix.path, contents, pflags);
2692   return res;
2693 }
2694
2695 /* "path" is the path in a virtual symlink.  Set a symlink_info struct from
2696    that and proceed with further path checking afterwards. */
2697 int
2698 symlink_info::set (char *path)
2699 {
2700   strcpy (contents, path);
2701   pflags = PATH_SYMLINK;
2702   fileattr = FILE_ATTRIBUTE_NORMAL;
2703   error = 0;
2704   issymlink = true;
2705   isdevice = false;
2706   ext_tacked_on = false;
2707   ext_here = NULL;
2708   extn = major = minor = mode = 0;
2709   return strlen (path);
2710 }
2711
2712 /* readlink system call */
2713
2714 extern "C" ssize_t
2715 readlink (const char *path, char *buf, size_t buflen)
2716 {
2717   if (buflen < 0)
2718     {
2719       set_errno (ENAMETOOLONG);
2720       return -1;
2721     }
2722
2723   path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2724
2725   if (pathbuf.error)
2726     {
2727       set_errno (pathbuf.error);
2728       syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2729       return -1;
2730     }
2731
2732   if (!pathbuf.exists ())
2733     {
2734       set_errno (ENOENT);
2735       return -1;
2736     }
2737
2738   if (!pathbuf.issymlink ())
2739     {
2740       if (pathbuf.exists ())
2741         set_errno (EINVAL);
2742       return -1;
2743     }
2744
2745   ssize_t len = min (buflen, strlen (pathbuf.get_win32 ()));
2746   memcpy (buf, pathbuf.get_win32 (), len);
2747
2748   /* errno set by symlink.check if error */
2749   return len;
2750 }
2751
2752 /* Some programs rely on st_dev/st_ino being unique for each file.
2753    Hash the path name and hope for the best.  The hash arg is not
2754    always initialized to zero since readdir needs to compute the
2755    dirent ino_t based on a combination of the hash of the directory
2756    done during the opendir call and the hash or the filename within
2757    the directory.  FIXME: Not bullet-proof. */
2758 /* Cygwin internal */
2759 __ino64_t __stdcall
2760 hash_path_name (__ino64_t hash, PUNICODE_STRING name)
2761 {
2762   if (name->Length == 0)
2763     return hash;
2764
2765   /* Build up hash. Name is already normalized */
2766   USHORT len = name->Length / sizeof (WCHAR);
2767   for (USHORT idx = 0; idx < len; ++idx)
2768     hash = RtlUpcaseUnicodeChar (name->Buffer[idx])
2769            + (hash << 6) + (hash << 16) - hash;
2770   return hash;
2771 }
2772
2773 __ino64_t __stdcall
2774 hash_path_name (__ino64_t hash, PCWSTR name)
2775 {
2776   UNICODE_STRING uname;
2777   RtlInitUnicodeString (&uname, name);
2778   return hash_path_name (hash, &uname);
2779 }
2780
2781 __ino64_t __stdcall
2782 hash_path_name (__ino64_t hash, const char *name)
2783 {
2784   UNICODE_STRING uname;
2785   RtlCreateUnicodeStringFromAsciiz (&uname, name);
2786   __ino64_t ret = hash_path_name (hash, &uname);
2787   RtlFreeUnicodeString (&uname);
2788   return ret;
2789 }
2790
2791 extern "C" char *
2792 getcwd (char *buf, size_t ulen)
2793 {
2794   char* res = NULL;
2795   myfault efault;
2796   if (efault.faulted (EFAULT))
2797       /* errno set */;
2798   else if (ulen == 0 && buf)
2799     set_errno (EINVAL);
2800   else
2801     res = cygheap->cwd.get (buf, 1, 1, ulen);
2802   return res;
2803 }
2804
2805 /* getwd: Legacy. */
2806 extern "C" char *
2807 getwd (char *buf)
2808 {
2809   return getcwd (buf, PATH_MAX + 1);  /*Per SuSv3!*/
2810 }
2811
2812 /* chdir: POSIX 5.2.1.1 */
2813 extern "C" int
2814 chdir (const char *in_dir)
2815 {
2816   myfault efault;
2817   if (efault.faulted (EFAULT))
2818     return -1;
2819   if (!*in_dir)
2820     {
2821       set_errno (ENOENT);
2822       return -1;
2823     }
2824
2825   syscall_printf ("dir '%s'", in_dir);
2826
2827   /* Convert path.  First argument ensures that we don't check for NULL/empty/invalid
2828      again. */
2829   path_conv path (PC_NONULLEMPTY, in_dir, PC_SYM_FOLLOW | PC_POSIX);
2830   if (path.error)
2831     {
2832       set_errno (path.error);
2833       syscall_printf ("-1 = chdir (%s)", in_dir);
2834       return -1;
2835     }
2836
2837   int res = -1;
2838   const char *posix_cwd = NULL;
2839   int devn = path.get_devn ();
2840   if (!path.exists ())
2841     set_errno (ENOENT);
2842   else if (!path.isdir ())
2843     set_errno (ENOTDIR);
2844   else if (!isvirtual_dev (devn))
2845     {
2846       /* The sequence chdir("xx"); chdir(".."); must be a noop if xx
2847          is not a symlink. This is exploited by find.exe.
2848          The posix_cwd is just path.normalized_path.
2849          In other cases we let cwd.set obtain the Posix path through
2850          the mount table. */
2851       if (!isdrive(path.normalized_path))
2852         posix_cwd = path.normalized_path;
2853       res = 0;
2854     }
2855   else
2856    {
2857      posix_cwd = path.normalized_path;
2858      res = 0;
2859    }
2860
2861   if (!res)
2862     res = cygheap->cwd.set (&path, posix_cwd);
2863
2864   /* Note that we're accessing cwd.posix without a lock here.  I didn't think
2865      it was worth locking just for strace. */
2866   syscall_printf ("%d = chdir() cygheap->cwd.posix '%s' native '%S'", res,
2867                   cygheap->cwd.get_posix (), path.get_nt_native_path ());
2868   MALLOC_CHECK;
2869   return res;
2870 }
2871
2872 extern "C" int
2873 fchdir (int fd)
2874 {
2875   int res;
2876   cygheap_fdget cfd (fd);
2877   if (cfd >= 0)
2878     res = chdir (cfd->get_name ());
2879   else
2880     res = -1;
2881
2882   syscall_printf ("%d = fchdir (%d)", res, fd);
2883   return res;
2884 }
2885
2886 /******************** Exported Path Routines *********************/
2887
2888 /* Cover functions to the path conversion routines.
2889    These are exported to the world as cygwin_foo by cygwin.din.  */
2890
2891 #define return_with_errno(x) \
2892   do {\
2893     int err = (x);\
2894     if (!err)\
2895      return 0;\
2896     set_errno (err);\
2897     return -1;\
2898   } while (0)
2899
2900 extern "C" ssize_t
2901 cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to,
2902                   size_t size)
2903 {
2904   tmp_pathbuf tp;
2905   myfault efault;
2906   if (efault.faulted (EFAULT))
2907     return -1;
2908
2909   path_conv p;
2910   size_t lsiz = 0;
2911   char *buf = NULL;
2912   PWCHAR path = NULL;
2913   int error = 0;
2914   bool relative = !!(what & CCP_RELATIVE);
2915   what &= ~CCP_RELATIVE;
2916
2917   switch (what)
2918     {
2919     case CCP_POSIX_TO_WIN_A:
2920       {
2921         p.check ((const char *) from,
2922                  PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2923                  | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2924         if (p.error)
2925           return_with_errno (p.error);
2926         PUNICODE_STRING up = p.get_nt_native_path ();
2927         buf = tp.c_get ();
2928         sys_wcstombs (buf, NT_MAX_PATH, up->Buffer, up->Length / sizeof (WCHAR));
2929         /* Convert native path to standard DOS path. */
2930         if (!strncmp (buf, "\\??\\", 4))
2931           {
2932             buf += 4;
2933             if (buf[1] != ':') /* native UNC path */
2934               *(buf += 2) = '\\';
2935           }
2936         else if (*buf == '\\')
2937           {
2938             /* Device name points to somewhere else in the NT namespace. 
2939                Use GLOBALROOT prefix to convert to Win32 path. */
2940             char *p = stpcpy (buf, "\\\\.\\GLOBALROOT");
2941             sys_wcstombs (p, NT_MAX_PATH - (p - buf),
2942                           up->Buffer, up->Length / sizeof (WCHAR));
2943           }
2944         lsiz = strlen (buf) + 1;
2945         /* TODO: Incoming "." is a special case which leads to a trailing
2946            backslash ".\\" in the Win32 path.  That's a result of the
2947            conversion in normalize_posix_path.  This should not occur
2948            so the below code is just a band-aid. */
2949         if (relative && !strcmp ((const char *) from, ".")
2950             && !strcmp (buf, ".\\"))
2951           {
2952             lsiz = 2;
2953             buf[1] = '\0';
2954           }
2955       }
2956       break;
2957     case CCP_POSIX_TO_WIN_W:
2958       p.check ((const char *) from,
2959                PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2960                | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2961       if (p.error)
2962         return_with_errno (p.error);
2963       /* Relative Windows paths are always restricted to MAX_PATH chars. */
2964       if (relative && !isabspath (p.get_win32 ())
2965           && sys_mbstowcs (NULL, 0, p.get_win32 ()) > MAX_PATH)
2966         {
2967           /* Recreate as absolute path. */
2968           p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW
2969                                         | PC_NO_ACCESS_CHECK | PC_NOWARN);
2970           if (p.error)
2971             return_with_errno (p.error);
2972         }
2973       lsiz = p.get_wide_win32_path_len () + 1;
2974       path = p.get_nt_native_path ()->Buffer;
2975
2976       /* Convert native path to standard DOS path. */
2977       if (!wcsncmp (path, L"\\??\\", 4))
2978         {
2979           path[1] = L'\\';
2980
2981           /* Drop long path prefix for short pathnames.  Unfortunately there's
2982              quite a bunch of Win32 functions, especially in user32.dll,
2983              apparently, which don't grok long path names at all, not even
2984              in the UNICODE API. */
2985           if ((path[5] == L':' && lsiz <= MAX_PATH + 4)
2986               || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6))
2987             {
2988               path += 4;
2989               lsiz -= 4;
2990               if (path[1] != L':')
2991                 {
2992                   *(path += 2) = '\\';
2993                   lsiz -= 2;
2994                 }
2995             }
2996         }
2997       else if (*path == L'\\')
2998         {
2999           /* Device name points to somewhere else in the NT namespace. 
3000              Use GLOBALROOT prefix to convert to Win32 path. */
3001           to = (void *) wcpcpy ((wchar_t *) to, L"\\\\.\\GLOBALROOT");
3002           lsiz += sizeof ("\\\\.\\GLOBALROOT") - 1;
3003         }
3004       /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */
3005       if (relative && !strcmp ((const char *) from, ".")
3006           && !wcscmp (path, L".\\"))
3007         {
3008           lsiz = 2;
3009           path[1] = L'\0';
3010         }
3011       lsiz *= sizeof (WCHAR);
3012       break;
3013     case CCP_WIN_A_TO_POSIX:
3014       buf = tp.c_get ();
3015       error = mount_table->conv_to_posix_path ((const char *) from, buf,
3016                                                relative);
3017       if (error)
3018         return_with_errno (error);
3019       lsiz = strlen (buf) + 1;
3020       break;
3021     case CCP_WIN_W_TO_POSIX:
3022       buf = tp.c_get ();
3023       error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf,
3024                                                relative);
3025       if (error)
3026         return_with_errno (error);
3027       lsiz = strlen (buf) + 1;
3028       break;
3029     default:
3030       set_errno (EINVAL);
3031       return -1;
3032     }
3033   if (!size)
3034     return lsiz;
3035   if (size < lsiz)
3036     {
3037       set_errno (ENOSPC);
3038       return -1;
3039     }
3040   switch (what)
3041     {
3042     case CCP_POSIX_TO_WIN_A:
3043     case CCP_WIN_A_TO_POSIX:
3044     case CCP_WIN_W_TO_POSIX:
3045       stpcpy ((char *) to, buf);
3046       break;
3047     case CCP_POSIX_TO_WIN_W:
3048       wcpcpy ((PWCHAR) to, path);
3049       break;
3050     }
3051   return 0;
3052 }
3053
3054 extern "C" void *
3055 cygwin_create_path (cygwin_conv_path_t what, const void *from)
3056 {
3057   void *to;
3058   ssize_t size = cygwin_conv_path (what, from, NULL, 0);
3059   if (size <= 0)
3060     to = NULL;
3061   else if (!(to = malloc (size)))
3062     to = NULL;
3063   if (cygwin_conv_path (what, from, to, size) == -1)
3064     {
3065       free (to);
3066       to = NULL;
3067     }
3068   return to;
3069 }
3070
3071
3072 extern "C" int
3073 cygwin_conv_to_win32_path (const char *path, char *win32_path)
3074 {
3075   return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, path, win32_path,
3076                            MAX_PATH);
3077 }
3078
3079 extern "C" int
3080 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
3081 {
3082   return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path, win32_path,
3083                            MAX_PATH);
3084 }
3085
3086 /* This is exported to the world as cygwin_foo by cygwin.din.  */
3087
3088 extern "C" int
3089 cygwin_conv_to_posix_path (const char *path, char *posix_path)
3090 {
3091   return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, path, posix_path,
3092                            MAX_PATH);
3093 }
3094
3095 extern "C" int
3096 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
3097 {
3098   return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, path, posix_path,
3099                            MAX_PATH);
3100 }
3101
3102 /* The realpath function is required by POSIX:2008.  */
3103
3104 extern "C" char *
3105 realpath (const char *path, char *resolved)
3106 {
3107   /* Make sure the right errno is returned if path is NULL. */
3108   if (!path)
3109     {
3110       set_errno (EINVAL);
3111       return NULL;
3112     }
3113
3114   /* Guard reading from a potentially invalid path and writing to a
3115      potentially invalid resolved. */
3116   tmp_pathbuf tp;
3117   myfault efault;
3118   if (efault.faulted (EFAULT))
3119     return NULL;
3120
3121   char *tpath;
3122   if (isdrive (path))
3123     {
3124       tpath = tp.c_get ();
3125       mount_table->cygdrive_posix_path (path, tpath, 0);
3126     }
3127   else
3128     tpath = (char *) path;
3129
3130   path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
3131
3132
3133   /* POSIX 2008 requires malloc'ing if resolved is NULL, and states
3134      that using non-NULL resolved is asking for portability
3135      problems.  */
3136
3137   if (!real_path.error && real_path.exists ())
3138     {
3139       if (!resolved)
3140         {
3141           resolved = (char *) malloc (strlen (real_path.normalized_path) + 1);
3142           if (!resolved)
3143             return NULL;
3144         }
3145       strcpy (resolved, real_path.normalized_path);
3146       return resolved;
3147     }
3148
3149   /* FIXME: on error, Linux puts the name of the path
3150      component which could not be resolved into RESOLVED, but POSIX
3151      does not require this.  */
3152   if (resolved)
3153     resolved[0] = '\0';
3154   set_errno (real_path.error ?: ENOENT);
3155   return NULL;
3156 }
3157
3158 /* Linux provides this extension.  Since the only portable use of
3159    realpath requires a NULL second argument, we might as well have a
3160    one-argument wrapper.  */
3161 extern "C" char *
3162 canonicalize_file_name (const char *path)
3163 {
3164   return realpath (path, NULL);
3165 }
3166
3167 /* Return non-zero if path is a POSIX path list.
3168    This is exported to the world as cygwin_foo by cygwin.din.
3169
3170 DOCTOOL-START
3171 <sect1 id="add-func-cygwin-posix-path-list-p">
3172   <para>Rather than use a mode to say what the "proper" path list
3173   format is, we allow any, and give apps the tools they need to
3174   convert between the two.  If a ';' is present in the path list it's
3175   a Win32 path list.  Otherwise, if the first path begins with
3176   [letter]: (in which case it can be the only element since if it
3177   wasn't a ';' would be present) it's a Win32 path list.  Otherwise,
3178   it's a POSIX path list.</para>
3179 </sect1>
3180 DOCTOOL-END
3181   */
3182
3183 extern "C" int
3184 cygwin_posix_path_list_p (const char *path)
3185 {
3186   int posix_p = !(strchr (path, ';') || isdrive (path));
3187   return posix_p;
3188 }
3189
3190 /* These are used for apps that need to convert env vars like PATH back and
3191    forth.  The conversion is a two step process.  First, an upper bound on the
3192    size of the buffer needed is computed.  Then the conversion is done.  This
3193    allows the caller to use alloca if it wants.  */
3194
3195 static int
3196 conv_path_list_buf_size (const char *path_list, bool to_posix)
3197 {
3198   int i, num_elms, max_mount_path_len, size;
3199   const char *p;
3200
3201   path_conv pc(".", PC_POSIX);
3202   /* The theory is that an upper bound is
3203      current_size + (num_elms * max_mount_path_len)  */
3204   /* FIXME: This method is questionable in the long run. */
3205
3206   unsigned nrel;
3207   char delim = to_posix ? ';' : ':';
3208   for (p = path_list, num_elms = nrel = 0; p; num_elms++)
3209     {
3210       if (!isabspath (p))
3211         nrel++;
3212       p = strchr (++p, delim);
3213     }
3214
3215   /* 7: strlen ("//c") + slop, a conservative initial value */
3216   for (max_mount_path_len = sizeof ("/cygdrive/X"), i = 0;
3217        i < mount_table->nmounts; i++)
3218     {
3219       int mount_len = (to_posix
3220                        ? mount_table->mount[i].posix_pathlen
3221                        : mount_table->mount[i].native_pathlen);
3222       if (max_mount_path_len < mount_len)
3223         max_mount_path_len = mount_len;
3224     }
3225
3226   /* 100: slop */
3227   size = strlen (path_list)
3228     + (num_elms * max_mount_path_len)
3229     + (nrel * strlen (to_posix ? pc.normalized_path : pc.get_win32 ()))
3230     + 100;
3231
3232   return size;
3233 }
3234
3235
3236 extern "C" int
3237 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
3238 {
3239   return conv_path_list_buf_size (path_list, true);
3240 }
3241
3242 extern "C" int
3243 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
3244 {
3245   return conv_path_list_buf_size (path_list, false);
3246 }
3247
3248 extern "C" ssize_t
3249 env_PATH_to_posix (const void *win32, void *posix, size_t size)
3250 {
3251   return_with_errno (conv_path_list ((const char *) win32, (char *) posix,
3252                                      size, ENV_CVT));
3253 }
3254
3255 extern "C" int
3256 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
3257 {
3258   return_with_errno (conv_path_list (win32, posix, MAX_PATH, 1));
3259 }
3260
3261 extern "C" int
3262 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
3263 {
3264   return_with_errno (conv_path_list (posix, win32, MAX_PATH, 0));
3265 }
3266
3267 extern "C" ssize_t
3268 cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
3269                        size_t size)
3270 {
3271   /* FIXME: Path lists are (so far) always retaining relative paths. */
3272   what &= ~CCP_RELATIVE;
3273   switch (what)
3274     {
3275     case CCP_WIN_W_TO_POSIX:
3276     case CCP_POSIX_TO_WIN_W:
3277       /*FIXME*/
3278       api_fatal ("wide char path lists not yet supported");
3279       break;
3280     case CCP_WIN_A_TO_POSIX:
3281     case CCP_POSIX_TO_WIN_A:
3282       if (size == 0)
3283         return conv_path_list_buf_size ((const char *) from,
3284                                         what == CCP_WIN_A_TO_POSIX);
3285       return_with_errno (conv_path_list ((const char *) from, (char *) to,
3286                                          size, what == CCP_WIN_A_TO_POSIX));
3287       break;
3288     default:
3289       break;
3290     }
3291   set_errno (EINVAL);
3292   return -1;
3293 }
3294
3295 /* cygwin_split_path: Split a path into directory and file name parts.
3296    Buffers DIR and FILE are assumed to be big enough.
3297
3298    Examples (path -> `dir' / `file'):
3299    / -> `/' / `'
3300    "" -> `.' / `'
3301    . -> `.' / `.' (FIXME: should this be `.' / `'?)
3302    .. -> `.' / `..' (FIXME: should this be `..' / `'?)
3303    foo -> `.' / `foo'
3304    foo/bar -> `foo' / `bar'
3305    foo/bar/ -> `foo' / `bar'
3306    /foo -> `/' / `foo'
3307    /foo/bar -> `/foo' / `bar'
3308    c: -> `c:/' / `'
3309    c:/ -> `c:/' / `'
3310    c:foo -> `c:/' / `foo'
3311    c:/foo -> `c:/' / `foo'
3312  */
3313
3314 extern "C" void
3315 cygwin_split_path (const char *path, char *dir, char *file)
3316 {
3317   int dir_started_p = 0;
3318
3319   /* Deal with drives.
3320      Remember that c:foo <==> c:/foo.  */
3321   if (isdrive (path))
3322     {
3323       *dir++ = *path++;
3324       *dir++ = *path++;
3325       *dir++ = '/';
3326       if (!*path)
3327         {
3328           *dir = 0;
3329           *file = 0;
3330           return;
3331         }
3332       if (isdirsep (*path))
3333         ++path;
3334       dir_started_p = 1;
3335     }
3336
3337   /* Determine if there are trailing slashes and "delete" them if present.
3338      We pretend as if they don't exist.  */
3339   const char *end = path + strlen (path);
3340   /* path + 1: keep leading slash.  */
3341   while (end > path + 1 && isdirsep (end[-1]))
3342     --end;
3343
3344   /* At this point, END points to one beyond the last character
3345      (with trailing slashes "deleted").  */
3346
3347   /* Point LAST_SLASH at the last slash (duh...).  */
3348   const char *last_slash;
3349   for (last_slash = end - 1; last_slash >= path; --last_slash)
3350     if (isdirsep (*last_slash))
3351       break;
3352
3353   if (last_slash == path)
3354     {
3355       *dir++ = '/';
3356       *dir = 0;
3357     }
3358   else if (last_slash > path)
3359     {
3360       memcpy (dir, path, last_slash - path);
3361       dir[last_slash - path] = 0;
3362     }
3363   else
3364     {
3365       if (dir_started_p)
3366         ; /* nothing to do */
3367       else
3368         *dir++ = '.';
3369       *dir = 0;
3370     }
3371
3372   memcpy (file, last_slash + 1, end - last_slash - 1);
3373   file[end - last_slash - 1] = 0;
3374 }
3375
3376 /*****************************************************************************/
3377
3378 /* The find_fast_cwd_pointers function and parts of the
3379    cwdstuff::override_win32_cwd method are based on code using the
3380    following license:
3381
3382    Copyright 2010 John Carey. All rights reserved.
3383
3384    Redistribution and use in source and binary forms, with or without
3385    modification, are permitted provided that the following conditions
3386    are met:
3387
3388       1. Redistributions of source code must retain the above
3389       copyright notice, this list of conditions and the following
3390       disclaimer.
3391
3392       2. Redistributions in binary form must reproduce the above
3393       copyright notice, this list of conditions and the following
3394       disclaimer in the documentation and/or other materials provided
3395       with the distribution.
3396
3397    THIS SOFTWARE IS PROVIDED BY JOHN CAREY ``AS IS'' AND ANY EXPRESS
3398    OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3399    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3400    ARE DISCLAIMED. IN NO EVENT SHALL JOHN CAREY OR CONTRIBUTORS BE
3401    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3402    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
3403    OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
3404    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3405    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3406    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3407    USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3408    DAMAGE. */
3409
3410 /* This structure is used to store the CWD starting with Windows Vista.
3411    The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only
3412    an afterthought now.  The actual CWD storage is a FAST_CWD structure
3413    which is allocated on the process heap.  The new method only requires
3414    minimal locking and it's much more multi-thread friendly.  Presumably
3415    it minimizes contention when accessing the CWD. */
3416 typedef struct _FAST_CWD {
3417   LONG           ReferenceCount;        /* Only release when this is 0. */
3418   HANDLE         DirectoryHandle;
3419   ULONG          OldDismountCount;      /* Reflects the system DismountCount
3420                                            at the time the CWD has been set. */
3421   UNICODE_STRING Path;                  /* Path's Buffer member always refers
3422                                            to the following Buffer array. */
3423   WCHAR          Buffer[MAX_PATH];
3424 } FAST_CWD, *PFAST_CWD;
3425
3426 /* fast_cwd_ptr is a pointer to the global pointer in ntdll.dll pointing
3427    to the FAST_CWD structure which constitutes the CWD.
3428
3429    We put the pointer into the common shared DLL segment.  This allows to
3430    restrict the call to find_fast_cwd_pointers() to once per Cygwin session
3431    per user session.  This works, because ASLR randomizes the load address
3432    of DLLs only once at boot time. */
3433 static PFAST_CWD *fast_cwd_ptr
3434   __attribute__((section (".cygwin_dll_common"), shared)) = (PFAST_CWD *) -1;
3435
3436 /* This is the mapping of the KUSER_SHARED_DATA structure into the 32 bit
3437    user address space.  We need it here to access the current DismountCount. */
3438 static KUSER_SHARED_DATA &SharedUserData
3439                          = *(volatile PKUSER_SHARED_DATA) 0x7ffe0000;
3440
3441 #define peek32(x)       (*(uint32_t *)(x))
3442
3443 /* This function scans the code in ntdll.dll to find the address of the
3444    global variable used to access the CWD starting with Vista.  While the
3445    pointer is global, it's not exported from the DLL, unfortunately.
3446    Therefore we have to use some knowledge to figure out the address.
3447
3448    This code has been tested on Vista 32/64 bit, Server 2008 32/64 bit,
3449    Windows 7 32/64 bit, and Server 2008 R2 (which is only 64 bit anyway).
3450    There's some hope that this will still work for Windows 8... */
3451 static void
3452 find_fast_cwd_pointers ()
3453 {
3454   /* Note that we have been called. */
3455   fast_cwd_ptr = NULL;
3456   /* Fetch entry points of relevant functions in ntdll.dll. */
3457   HMODULE ntdll = GetModuleHandle ("ntdll.dll");
3458   if (!ntdll)
3459     return;
3460   const uint8_t *get_dir = (const uint8_t *)
3461                            GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
3462   const uint8_t *ent_crit = (const uint8_t *)
3463                             GetProcAddress (ntdll, "RtlEnterCriticalSection");
3464   if (!get_dir || !ent_crit)
3465     return;
3466   /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
3467   const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 32);
3468   if (!rcall)
3469     return;
3470   /* Fetch offset from instruction and compute address of called function.
3471      This function actually fetches the current FAST_CWD instance and
3472      performs some other actions, not important to us. */
3473   ptrdiff_t offset = (ptrdiff_t) peek32 (rcall + 1);
3474   const uint8_t *use_cwd = rcall + 5 + offset;
3475   /* Find first "push edi" instruction. */
3476   const uint8_t *pushedi = (const uint8_t *) memchr (use_cwd, 0x57, 32);
3477   /* ...which should be followed by "mov edi, crit-sect-addr" then
3478      "push edi". */
3479   const uint8_t *movedi = pushedi + 1;
3480   if (movedi[0] != 0xbf || movedi[5] != 0x57)
3481     return;
3482   /* Compare the address used for the critical section with the known
3483      PEB lock as stored in the PEB. */
3484   if ((PRTL_CRITICAL_SECTION) peek32 (movedi + 1)
3485       != NtCurrentTeb ()->Peb->FastPebLock)
3486     return;
3487   /* To check we are seeing the right code, we check our expectation that
3488      the next instruction is a relative call into RtlEnterCriticalSection. */
3489   rcall = movedi + 6;
3490   if (rcall[0] != 0xe8)
3491     return;
3492   /* Check that this is a relative call to RtlEnterCriticalSection. */
3493   offset = (ptrdiff_t) peek32 (rcall + 1);
3494   if (rcall + 5 + offset != ent_crit)
3495     return;
3496   /* After locking the critical section, the code should read the global
3497      PFAST_CWD * pointer that is guarded by that critical section. */
3498   const uint8_t *movesi = rcall + 5;
3499   if (movesi[0] != 0x8b)
3500     return;
3501   fast_cwd_ptr = (PFAST_CWD *) peek32 (movesi + 2);
3502 }
3503
3504 static inline void
3505 copy_cwd_str (PUNICODE_STRING tgt, PUNICODE_STRING src)
3506 {
3507   RtlCopyUnicodeString (tgt, src);
3508   if (tgt->Buffer[tgt->Length / sizeof (WCHAR) - 1] != L'\\')
3509     {
3510       tgt->Buffer[tgt->Length / sizeof (WCHAR)] = L'\\';
3511       tgt->Length += sizeof (WCHAR);
3512     }
3513 }
3514
3515 void
3516 cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
3517 {
3518   NTSTATUS status;
3519   HANDLE h = NULL;
3520
3521   PEB &peb = *NtCurrentTeb ()->Peb;
3522   UNICODE_STRING &upp_cwd_str = peb.ProcessParameters->CurrentDirectoryName;
3523   HANDLE &upp_cwd_hdl = peb.ProcessParameters->CurrentDirectoryHandle;
3524
3525   if (wincap.has_fast_cwd ())
3526     {
3527       if (fast_cwd_ptr == (PFAST_CWD *) -1)
3528         {
3529           find_fast_cwd_pointers ();
3530           if (!fast_cwd_ptr)
3531             system_printf ("WARNING: Couldn't compute FAST_CWD pointer.  "
3532                            "Please report this problem to\nthe public mailing "
3533                            "list cygwin@cygwin.com");
3534         }
3535       if (fast_cwd_ptr)
3536         {
3537           /* Default method starting with Vista.  If we got a valid value for
3538              fast_cwd_ptr, we can simply replace the RtlSetCurrentDirectory_U
3539              function entirely, just as on pre-Vista. */
3540           PVOID heap = peb.ProcessHeap;
3541           /* First allocate a new FAST_CWD strcuture on the heap. */
3542           PFAST_CWD f_cwd = (PFAST_CWD)
3543                             RtlAllocateHeap (heap, 0, sizeof (FAST_CWD));
3544           if (!f_cwd)
3545             {
3546               debug_printf ("RtlAllocateHeap failed");
3547               return;
3548             }
3549           /* Fill in the values. */
3550           f_cwd->ReferenceCount = 1;
3551           f_cwd->DirectoryHandle = dir;
3552           f_cwd->OldDismountCount = old_dismount_count;
3553           RtlInitEmptyUnicodeString (&f_cwd->Path, f_cwd->Buffer,
3554                                      MAX_PATH * sizeof (WCHAR));
3555           copy_cwd_str (&f_cwd->Path, error ? &ro_u_pipedir : &win32);
3556           /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
3557              structure and writing the CWD to the user process parameter
3558              block.  This is equivalent to calling RtlAcquirePebLock/
3559              RtlReleasePebLock, but without having to go through the FS
3560              selector again. */
3561           RtlEnterCriticalSection (peb.FastPebLock);
3562           PFAST_CWD old_cwd = *fast_cwd_ptr;
3563           *fast_cwd_ptr = f_cwd;
3564           upp_cwd_str = f_cwd->Path;
3565           upp_cwd_hdl = dir;
3566           RtlLeaveCriticalSection (peb.FastPebLock);
3567           /* Decrement the reference count.  If it's down to 0, free structure
3568              from heap. */
3569           if (old_cwd && InterlockedDecrement (&old_cwd->ReferenceCount) == 0)
3570             {
3571               /* In contrast to pre-Vista, the handle on init is always a fresh
3572                  one and not the handle inherited from the parent process.  So
3573                  we always have to close it here.  However, the handle could
3574                  be NULL, if we cd'ed into a virtual dir. */
3575               if (old_cwd->DirectoryHandle)
3576                 NtClose (old_cwd->DirectoryHandle);
3577               RtlFreeHeap (heap, 0, old_cwd);
3578             }
3579         }
3580       else
3581         {
3582           /* This is more a hack, and it's only used on Vista and later if we
3583              failed to find the fast_cwd_ptr value.  What we do here is to call
3584              RtlSetCurrentDirectory_U and let it set up a new FAST_CWD
3585              structure.  Afterwards, compute the address of that structure
3586              utilizing the fact that the buffer address in the user process
3587              parameter block is actually pointing to the buffer in that
3588              FAST_CWD structure.  Then replace the directory handle in that
3589              structure with our own handle and close the original one.
3590
3591              Note that the call to RtlSetCurrentDirectory_U also closes our
3592              old dir handle, so there won't be any handle left open.
3593
3594              This method is prone to two race conditions:
3595
3596              - Due to the way RtlSetCurrentDirectory_U opens the directory
3597                handle, the directory is locked against deletion or renaming
3598                between the RtlSetCurrentDirectory_U and the subsequent NtClose
3599                call.
3600              
3601              - When another thread calls SetCurrentDirectory at exactly the
3602                same time, a crash might occur, or worse, unrelated data could
3603                be overwritten or NtClose could be called on an unrelated handle.
3604              
3605              Therefore, use this *only* as a fallback. */
3606           if (!init)
3607             {
3608               status = RtlSetCurrentDirectory_U (error ? &ro_u_pipedir
3609                                                        : &win32);
3610               if (!NT_SUCCESS (status))
3611                 {
3612                   debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %p",
3613                                 error ? &ro_u_pipedir : &win32, status);
3614                   return;
3615                 }
3616             }
3617           RtlEnterCriticalSection (peb.FastPebLock);
3618           PFAST_CWD f_cwd = (PFAST_CWD)
3619                             ((PBYTE) upp_cwd_str.Buffer
3620                              - __builtin_offsetof (struct _FAST_CWD, Buffer));
3621           h = upp_cwd_hdl;
3622           f_cwd->DirectoryHandle = upp_cwd_hdl = dir;
3623           RtlLeaveCriticalSection (peb.FastPebLock);
3624           /* In contrast to pre-Vista, the handle on init is always a fresh one
3625              and not the handle inherited from the parent process.  So we always
3626              have to close it here. */
3627           NtClose (h);
3628         }
3629     }
3630   else
3631     {
3632       /* This method is used for all pre-Vista OSes.  We simply set the values
3633          for the CWD in the user process parameter block entirely by ourselves
3634          under PEB lock condition.  This is how RtlSetCurrentDirectory_U worked
3635          in these older OSes, so we're safe.
3636          
3637          Note that we can't just RtlEnterCriticalSection (peb.FastPebLock)
3638          on pre-Vista.  RtlAcquirePebLock was way more complicated back then. */
3639       RtlAcquirePebLock ();
3640       if (!init)
3641         copy_cwd_str (&upp_cwd_str, error ? &ro_u_pipedir : &win32);
3642       h = upp_cwd_hdl;
3643       upp_cwd_hdl = dir;
3644       RtlReleasePebLock ();
3645       /* Only on init, the handle is potentially a native handle.  However,
3646          if it's identical to dir, it's the inherited handle from a Cygwin
3647          parent process and must not be closed. */
3648       if (h && h != dir)
3649         NtClose (h);
3650     }
3651 }
3652
3653 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
3654 void
3655 cwdstuff::init ()
3656 {
3657   cwd_lock.init ("cwd_lock");
3658
3659   /* Cygwin processes inherit the cwd from their parent.  If the win32 path
3660      buffer is not NULL, the cwd struct is already set up, and we only
3661      have to override the Win32 CWD with ours. */
3662   if (win32.Buffer)
3663     override_win32_cwd (true, SharedUserData.DismountCount);
3664   else
3665     /* Initially re-open the cwd to allow POSIX semantics. */
3666     set (NULL, NULL);
3667 }
3668
3669 /* Chdir and fill out the elements of a cwdstuff struct. */
3670 int
3671 cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
3672 {
3673   NTSTATUS status;
3674   UNICODE_STRING upath;
3675   PEB &peb = *NtCurrentTeb ()->Peb;
3676   bool virtual_path = false;
3677   bool unc_path = false;
3678   bool inaccessible_path = false;
3679
3680   /* Here are the problems with using SetCurrentDirectory.  Just skip this
3681      comment if you don't like whining.
3682      
3683      - SetCurrentDirectory only supports paths of up to MAX_PATH - 1 chars,
3684        including a trailing backslash.  That's an absolute restriction, even
3685        in the UNICODE API.
3686
3687      - SetCurrentDirectory fails for directories with strict permissions even
3688        for processes with the SE_BACKUP_NAME privilege enabled.  The reason
3689        is apparently that SetCurrentDirectory calls NtOpenFile without the
3690        FILE_OPEN_FOR_BACKUP_INTENT flag set.
3691
3692      - SetCurrentDirectory does not support case-sensitivity.
3693
3694      - Unlinking a cwd fails because SetCurrentDirectory seems to open
3695        directories so that deleting the directory is disallowed.
3696
3697      - SetCurrentDirectory can naturally not work on virtual Cygwin paths
3698        like /proc or /cygdrive.
3699
3700      Unfortunately, even though we have access to the Win32 process parameter
3701      block, we can't just replace the directory handle.  Starting with Vista,
3702      the handle is used elsewhere, and just replacing the handle in the process
3703      parameter block shows quite surprising results.
3704      FIXME: If we ever find a *safe* way to replace the directory handle in
3705      the process parameter block, we're back in business.
3706
3707      Nevertheless, doing entirely without SetCurrentDirectory is not really
3708      feasible, because it breaks too many mixed applications using the Win32
3709      API.
3710
3711      Therefore we handle the CWD all by ourselves and just keep the Win32
3712      CWD in sync.  However, to avoid surprising behaviour in the Win32 API
3713      when we are in a CWD which is inaccessible as Win32 CWD, we set the
3714      Win32 CWD to a "weird" directory in which all relative filesystem-related
3715      calls fail. */
3716
3717   cwd_lock.acquire ();
3718
3719   if (nat_cwd)
3720     {
3721       upath = *nat_cwd->get_nt_native_path ();
3722       if (nat_cwd->isspecial ())
3723         virtual_path = true;
3724     }
3725
3726   /* Memorize old DismountCount before opening the dir.  This value is
3727      stored in the FAST_CWD structure on Vista and later.  It would be
3728      simpler to fetch the old DismountCount in override_win32_cwd, but
3729      Windows also fetches it before opening the directory handle.  It's
3730      not quite clear if that's really required, but since we don't know
3731      the side effects of this action, we better follow Windows' lead. */
3732   ULONG old_dismount_count = SharedUserData.DismountCount;
3733   /* Open a directory handle with FILE_OPEN_FOR_BACKUP_INTENT and with all
3734      sharing flags set.  The handle is right now used in exceptions.cc only,
3735      but that might change in future. */
3736   HANDLE h = NULL;
3737   if (!virtual_path)
3738     {
3739       IO_STATUS_BLOCK io;
3740       OBJECT_ATTRIBUTES attr;
3741
3742       if (!nat_cwd)
3743         {
3744           /* On init, just reopen Win32 CWD with desired access flags.
3745              We can access the PEB without lock, because no other thread
3746              can change the CWD. */
3747           RtlInitUnicodeString (&upath, L"");
3748           InitializeObjectAttributes (&attr, &upath,
3749                         OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
3750                         peb.ProcessParameters->CurrentDirectoryHandle, NULL);
3751         }
3752       else
3753         InitializeObjectAttributes (&attr, &upath,
3754                         nat_cwd->objcaseinsensitive () | OBJ_INHERIT,
3755                         NULL, NULL);
3756       /* First try without FILE_OPEN_FOR_BACKUP_INTENT, to find out if the
3757          directory is valid for Win32 apps.  And, no, we can't just call
3758          SetCurrentDirectory here, since that would potentially break
3759          case-sensitivity. */
3760       status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
3761                            FILE_SHARE_VALID_FLAGS,
3762                            FILE_DIRECTORY_FILE
3763                            | FILE_SYNCHRONOUS_IO_NONALERT);
3764       if (status == STATUS_ACCESS_DENIED)
3765         {
3766           status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
3767                                FILE_SHARE_VALID_FLAGS,
3768                                FILE_DIRECTORY_FILE
3769                                | FILE_SYNCHRONOUS_IO_NONALERT
3770                                | FILE_OPEN_FOR_BACKUP_INTENT);
3771           inaccessible_path = true;
3772         }
3773       if (!NT_SUCCESS (status))
3774         {
3775           cwd_lock.release ();
3776           __seterrno_from_nt_status (status);
3777           return -1;
3778         }
3779     }
3780   /* Set new handle.  Note that we simply overwrite the old handle here
3781      without closing it.  The handle is also used as Win32 CWD handle in
3782      the user parameter block, and it will be closed in override_win32_cwd,
3783      if required. */
3784   dir = h;
3785
3786   if (!nat_cwd)
3787     {
3788       /* On init, just fetch the Win32 dir from the PEB.  We can access
3789          the PEB without lock, because no other thread can change the CWD
3790          at that time. */
3791       PUNICODE_STRING pdir = &peb.ProcessParameters->CurrentDirectoryName;
3792       RtlInitEmptyUnicodeString (&win32,
3793                                  (PWCHAR) crealloc_abort (win32.Buffer,
3794                                                           pdir->Length
3795                                                           + sizeof (WCHAR)),
3796                                  pdir->Length + sizeof (WCHAR));
3797       RtlCopyUnicodeString (&win32, pdir);
3798
3799       PWSTR eoBuffer = win32.Buffer + (win32.Length / sizeof (WCHAR));
3800       /* Remove trailing slash if one exists. */
3801       if ((eoBuffer - win32.Buffer) > 3 && eoBuffer[-1] == L'\\')
3802         win32.Length -= sizeof (WCHAR);
3803       if (eoBuffer[0] == L'\\')
3804         unc_path = true;
3805
3806       posix_cwd = NULL;
3807     }
3808   else
3809     {
3810       if (virtual_path) /* don't mangle virtual path. */
3811         ;
3812       else
3813         {
3814           /* Compute length on Win32 path. */
3815           size_t len = upath.Length / sizeof (WCHAR) - 4;
3816           if (RtlEqualUnicodePathPrefix (&upath, &ro_u_uncp, TRUE))
3817             {
3818               len -= 2;
3819               unc_path = true;
3820             }
3821           /* Convert to a Win32 path. */
3822           upath.Buffer += upath.Length / sizeof (WCHAR) - len;
3823           upath.Length = len * sizeof (WCHAR);
3824
3825           PWSTR eoBuffer = upath.Buffer + (upath.Length / sizeof (WCHAR));
3826           /* Remove trailing slash if one exists. */
3827           if ((eoBuffer - upath.Buffer) > 3 && eoBuffer[-1] == L'\\')
3828             upath.Length -= sizeof (WCHAR);
3829         }
3830       RtlInitEmptyUnicodeString (&win32,
3831                                  (PWCHAR) crealloc_abort (win32.Buffer,
3832                                                           upath.Length
3833                                                           + sizeof (WCHAR)),
3834                                  upath.Length + sizeof (WCHAR));
3835       RtlCopyUnicodeString (&win32, &upath);
3836       if (unc_path)
3837         win32.Buffer[0] = L'\\';
3838     }
3839   /* Make sure it's NUL-terminated. */
3840   win32.Buffer[win32.Length / sizeof (WCHAR)] = L'\0';
3841
3842   /* Set drive_length, used in path conversion, and error code, used in
3843      spawn_guts to decide whether a native Win32 app can be started or not. */
3844   if (virtual_path)
3845     {
3846       drive_length = 0;
3847       error = ENOTDIR;
3848     }
3849   else
3850     {
3851       if (!unc_path)
3852         drive_length = 2;
3853       else
3854         {
3855           PWCHAR ptr = wcschr (win32.Buffer + 2, L'\\');
3856           if (ptr)
3857             ptr = wcschr (ptr + 1, L'\\');
3858           if (ptr)
3859             drive_length = ptr - win32.Buffer;
3860           else
3861             drive_length = win32.Length / sizeof (WCHAR);
3862         }
3863       if (inaccessible_path)
3864         error = EACCES;
3865       else if (win32.Length > (MAX_PATH - 2) * sizeof (WCHAR))
3866         error = ENAMETOOLONG;
3867       else
3868         error = 0;
3869     }
3870   /* Keep the Win32 CWD in sync.  Don't check for error, other than for
3871      strace output.  Try to keep overhead low. */
3872   override_win32_cwd (!nat_cwd, old_dismount_count);
3873
3874   /* Eventually, create POSIX path if it's not set on entry. */
3875   tmp_pathbuf tp;
3876   if (!posix_cwd)
3877     {
3878       posix_cwd = (const char *) tp.c_get ();
3879       mount_table->conv_to_posix_path (win32.Buffer, (char *) posix_cwd, 0);
3880     }
3881   posix = (char *) crealloc_abort (posix, strlen (posix_cwd) + 1);
3882   stpcpy (posix, posix_cwd);
3883
3884   cwd_lock.release ();
3885   return 0;
3886 }
3887
3888 const char *
3889 cwdstuff::get_error_desc () const
3890 {
3891   switch (cygheap->cwd.get_error ())
3892     {
3893     case EACCES:
3894       return "has restricted permissions which render it\n"
3895              "inaccessible as Win32 working directory";
3896     case ENOTDIR:
3897       return "is a virtual Cygwin directory which does\n"
3898              "not exist for a native Windows application";
3899     case ENAMETOOLONG:
3900       return "has a path longer than allowed for a\n"
3901              "Win32 working directory";
3902     default:
3903       break;
3904     }
3905   /* That shouldn't occur, unless we defined a new error code
3906      in cwdstuff::set. */
3907   return "is not accessible for some unknown reason";
3908 }
3909
3910 /* Store incoming wchar_t path as current posix cwd.  This is called from
3911    setlocale so that the cwd is always stored in the right charset. */
3912 void
3913 cwdstuff::reset_posix (wchar_t *w_cwd)
3914 {
3915   size_t len = sys_wcstombs (NULL, (size_t) -1, w_cwd);
3916   posix = (char *) crealloc_abort (posix, len + 1);
3917   sys_wcstombs (posix, len + 1, w_cwd);
3918 }
3919
3920 char *
3921 cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
3922 {
3923   MALLOC_CHECK;
3924
3925   tmp_pathbuf tp;
3926   if (ulen)
3927     /* nothing */;
3928   else if (buf == NULL)
3929     ulen = (unsigned) -1;
3930   else
3931     {
3932       set_errno (EINVAL);
3933       goto out;
3934     }
3935
3936   cwd_lock.acquire ();
3937
3938   char *tocopy;
3939   if (!need_posix)
3940     {
3941       tocopy = tp.c_get ();
3942       sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer,
3943                     win32.Length / sizeof (WCHAR));
3944     }
3945   else
3946     tocopy = posix;
3947
3948   debug_printf ("posix %s", posix);
3949   if (strlen (tocopy) >= ulen)
3950     {
3951       set_errno (ERANGE);
3952       buf = NULL;
3953     }
3954   else
3955     {
3956       if (!buf)
3957         buf = (char *) malloc (strlen (tocopy) + 1);
3958       strcpy (buf, tocopy);
3959       if (!buf[0])      /* Should only happen when chroot */
3960         strcpy (buf, "/");
3961     }
3962
3963   cwd_lock.release ();
3964
3965 out:
3966   syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
3967                   buf, buf, ulen, need_posix, with_chroot, errno);
3968   MALLOC_CHECK;
3969   return buf;
3970 }
3971
3972 int etc::curr_ix = 0;
3973 /* Note that the first elements of the below arrays are unused */
3974 bool etc::change_possible[MAX_ETC_FILES + 1];
3975 OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1];
3976 LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1];
3977
3978 int
3979 etc::init (int n, POBJECT_ATTRIBUTES attr)
3980 {
3981   if (n > 0)
3982     /* ok */;
3983   else if (++curr_ix <= MAX_ETC_FILES)
3984     n = curr_ix;
3985   else
3986     api_fatal ("internal error");
3987
3988   fn[n] = *attr;
3989   change_possible[n] = false;
3990   test_file_change (n);
3991   paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix);
3992   return n;
3993 }
3994
3995 bool
3996 etc::test_file_change (int n)
3997 {
3998   NTSTATUS status;
3999   FILE_NETWORK_OPEN_INFORMATION fnoi;
4000   bool res;
4001
4002   status = NtQueryFullAttributesFile (&fn[n], &fnoi);
4003   if (!NT_SUCCESS (status))
4004     {
4005       res = true;
4006       memset (last_modified + n, 0, sizeof (last_modified[n]));
4007       debug_printf ("NtQueryFullAttributesFile (%S) failed, %p",
4008                     fn[n].ObjectName, status);
4009     }
4010   else
4011     {
4012       res = CompareFileTime ((FILETIME *) &fnoi.LastWriteTime,
4013                              (FILETIME *) last_modified + n) > 0;
4014       last_modified[n].QuadPart = fnoi.LastWriteTime.QuadPart;
4015     }
4016
4017   paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4018   return res;
4019 }
4020
4021 bool
4022 etc::dir_changed (int n)
4023 {
4024   if (!change_possible[n])
4025     {
4026       static HANDLE changed_h NO_COPY;
4027       NTSTATUS status;
4028       IO_STATUS_BLOCK io;
4029
4030       if (!changed_h)
4031         {
4032           OBJECT_ATTRIBUTES attr;
4033
4034           path_conv dir ("/etc");
4035           status = NtOpenFile (&changed_h, SYNCHRONIZE | FILE_LIST_DIRECTORY,
4036                                dir.get_object_attr (attr, sec_none_nih), &io,
4037                                FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE);
4038           if (!NT_SUCCESS (status))
4039             {
4040 #ifdef DEBUGGING
4041               system_printf ("NtOpenFile (%S) failed, %p",
4042                              dir.get_nt_native_path (), status);
4043 #endif
4044               changed_h = INVALID_HANDLE_VALUE;
4045             }
4046           else
4047             {
4048               status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4049                                                 NULL, &io, NULL, 0,
4050                                                 FILE_NOTIFY_CHANGE_LAST_WRITE
4051                                                 | FILE_NOTIFY_CHANGE_FILE_NAME,
4052                                                 FALSE);
4053               if (!NT_SUCCESS (status))
4054                 {
4055 #ifdef DEBUGGING
4056                   system_printf ("NtNotifyChangeDirectoryFile (1) failed, %p",
4057                                  status);
4058 #endif
4059                   NtClose (changed_h);
4060                   changed_h = INVALID_HANDLE_VALUE;
4061                 }
4062             }
4063           memset (change_possible, true, sizeof (change_possible));
4064         }
4065
4066       if (changed_h == INVALID_HANDLE_VALUE)
4067         change_possible[n] = true;
4068       else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
4069         {
4070           status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4071                                                 NULL, &io, NULL, 0,
4072                                                 FILE_NOTIFY_CHANGE_LAST_WRITE
4073                                                 | FILE_NOTIFY_CHANGE_FILE_NAME,
4074                                                 FALSE);
4075           if (!NT_SUCCESS (status))
4076             {
4077 #ifdef DEBUGGING
4078               system_printf ("NtNotifyChangeDirectoryFile (2) failed, %p",
4079                              status);
4080 #endif
4081               NtClose (changed_h);
4082               changed_h = INVALID_HANDLE_VALUE;
4083             }
4084           memset (change_possible, true, sizeof change_possible);
4085         }
4086     }
4087
4088   paranoid_printf ("fn[%d] %S change_possible %d",
4089                    n, fn[n].ObjectName, change_possible[n]);
4090   return change_possible[n];
4091 }
4092
4093 bool
4094 etc::file_changed (int n)
4095 {
4096   bool res = false;
4097   if (dir_changed (n) && test_file_change (n))
4098     res = true;
4099   change_possible[n] = false;   /* Change is no longer possible */
4100   paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4101   return res;
4102 }
4103
4104 /* No need to be reentrant or thread-safe according to SUSv3.
4105    / and \\ are treated equally.  Leading drive specifiers are
4106    kept intact as far as it makes sense.  Everything else is
4107    POSIX compatible. */
4108 extern "C" char *
4109 basename (char *path)
4110 {
4111   static char buf[4];
4112   char *c, *d, *bs = path;
4113
4114   if (!path || !*path)
4115     return strcpy (buf, ".");
4116   if (isalpha (path[0]) && path[1] == ':')
4117     bs += 2;
4118   else if (strspn (path, "/\\") > 1)
4119     ++bs;
4120   c = strrchr (bs, '/');
4121   if ((d = strrchr (c ?: bs, '\\')) > c)
4122     c = d;
4123   if (c)
4124     {
4125       /* Trailing (back)slashes are eliminated. */
4126       while (c && c > bs && c[1] == '\0')
4127         {
4128           *c = '\0';
4129           c = strrchr (bs, '/');
4130           if ((d = strrchr (c ?: bs, '\\')) > c)
4131             c = d;
4132         }
4133       if (c && (c > bs || c[1]))
4134         return c + 1;
4135     }
4136   else if (!bs[0])
4137     {
4138       stpncpy (buf, path, bs - path);
4139       stpcpy (buf + (bs - path), ".");
4140       return buf;
4141     }
4142   return path;
4143 }
4144
4145 /* No need to be reentrant or thread-safe according to SUSv3.
4146    / and \\ are treated equally.  Leading drive specifiers and
4147    leading double (back)slashes are kept intact as far as it
4148    makes sense.  Everything else is POSIX compatible. */
4149 extern "C" char *
4150 dirname (char *path)
4151 {
4152   static char buf[4];
4153   char *c, *d, *bs = path;
4154
4155   if (!path || !*path)
4156     return strcpy (buf, ".");
4157   if (isalpha (path[0]) && path[1] == ':')
4158     bs += 2;
4159   else if (strspn (path, "/\\") > 1)
4160     ++bs;
4161   c = strrchr (bs, '/');
4162   if ((d = strrchr (c ?: bs, '\\')) > c)
4163     c = d;
4164   if (c)
4165     {
4166       /* Trailing (back)slashes are eliminated. */
4167       while (c && c > bs && c[1] == '\0')
4168         {
4169           *c = '\0';
4170           c = strrchr (bs, '/');
4171           if ((d = strrchr (c ?: bs, '\\')) > c)
4172             c = d;
4173         }
4174       if (!c)
4175         strcpy (bs, ".");
4176       else if (c > bs)
4177         {
4178           /* More trailing (back)slashes are eliminated. */
4179           while (c > bs && (*c == '/' || *c == '\\'))
4180             *c-- = '\0';
4181         }
4182       else
4183         c[1] = '\0';
4184     }
4185   else
4186     {
4187       stpncpy (buf, path, bs - path);
4188       stpcpy (buf + (bs - path), ".");
4189       return buf;
4190     }
4191   return path;
4192 }