OSDN Git Service

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