1 /* path.cc: path support.
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
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
17 Pathnames are handled as follows:
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.
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.
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>:
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.
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.
43 The semantics of mounting file systems is not intended to precisely
44 follow normal UNIX systems.
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
52 #include "miscfuncs.h"
59 #include <sys/cygwin.h>
66 #include "shared_info.h"
75 bool dos_file_warning = true;
77 suffix_info stat_suffixes[] =
80 suffix_info (".exe", 1),
86 char contents[SYMLINK_MAX + 1];
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);
110 muto NO_COPY cwdstuff::cwd_lock;
112 static const GUID GUID_shortcut
113 = { 0x00021401L, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
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. */
125 struct win_shortcut_hdr
127 DWORD size; /* Header size in bytes. Must contain 0x4c. */
128 GUID magic; /* GUID of shortcut files. */
129 DWORD flags; /* Content flags. See above. */
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. */
137 DWORD filesize; /* Target filesize. */
138 DWORD icon_no; /* Icon number. */
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. */
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.
148 LEN1 = strlen (PATH1). It's passed because often it's already known.
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
160 path_prefix_p (const char *path1, const char *path2, int len1,
161 bool caseinsensitive)
163 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
164 if (len1 > 0 && isdirsep (path1[len1 - 1]))
168 return isdirsep (path2[0]) && !isdirsep (path2[1]);
170 if (isdirsep (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':')
171 return caseinsensitive ? strncasematch (path1, path2, len1)
172 : !strncmp (path1, path2, len1);
177 /* Return non-zero if paths match in first len chars.
178 Check is dependent of the case sensitivity setting. */
180 pathnmatch (const char *path1, const char *path2, int len, bool caseinsensitive)
182 return caseinsensitive
183 ? strncasematch (path1, path2, len) : !strncmp (path1, path2, len);
186 /* Return non-zero if paths match. Check is dependent of the case
187 sensitivity setting. */
189 pathmatch (const char *path1, const char *path2, bool caseinsensitive)
191 return caseinsensitive
192 ? strcasematch (path1, path2) : !strcmp (path1, path2);
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. */
200 has_dot_last_component (const char *dir, bool test_dot_dot)
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');
207 if (last_comp == dir)
208 return false; /* Empty string. Probably shouldn't happen here? */
210 /* Detect run of trailing slashes */
211 while (last_comp > dir && *--last_comp == '/')
214 /* Detect just a run of slashes or a path that does not end with a slash. */
215 if (*last_comp != '.')
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
221 if (last_comp == dir || *--last_comp == '/')
224 /* If we're not checking for '..' we're done. Ditto if we're now pointing to
226 if (!test_dot_dot || *last_comp != '.')
227 return false; /* either not testing for .. or this was not '..' */
229 /* Repeat previous test for standalone or path component. */
230 return last_comp == dir || last_comp[-1] == '/';
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. */
238 normalize_posix_path (const char *src, char *dst, char *&tail)
240 const char *in_src = src;
241 char *dst_start = dst;
242 syscall_printf ("src %s", src);
244 if ((isdrive (src) && isdirsep (src[2])) || *src == '\\')
248 if (!isslash (src[0]))
250 if (!cygheap->cwd.get (dst))
252 tail = strchr (tail, '\0');
253 if (isslash (dst[0]) && isslash (dst[1]))
257 if (tail == dst_start + 1 && *dst_start == '/')
261 if (tail > dst && !isslash (tail[-1]))
264 /* Two leading /'s? If so, preserve them. */
265 else if (isslash (src[1]) && !isslash (src[2]))
269 /* Is that a //?/ or //./ prefix into the native NT namespace?
270 If so, preserve it. */
271 if ((src[1] == '.' || src[1] == '?') && isslash (src[2]))
283 /* Strip runs of /'s. */
304 if (!isslash (src[1]))
307 else if (src[2] && !isslash (src[2]))
311 while (tail > dst_start && !isslash (*--tail))
319 if ((tail - dst) >= NT_MAX_PATH)
321 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
329 debug_printf ("%s = normalize_posix_path (%s)", dst, in_src);
333 int err = normalize_win32_path (in_src, dst, tail);
335 for (char *p = dst; (p = strchr (p, '\\')); p++)
341 path_conv::add_ext_from_sym (symlink_info &sym)
343 if (sym.ext_here && *sym.ext_here)
345 known_suffix = path + sym.extn;
346 if (sym.ext_tacked_on)
347 strcpy ((char *) known_suffix, sym.ext_here);
351 static void __stdcall mkrelpath (char *dst, bool caseinsensitive)
352 __attribute__ ((regparm (2)));
354 static void __stdcall
355 mkrelpath (char *path, bool caseinsensitive)
358 char *cwd_win32 = tp.c_get ();
359 if (!cygheap->cwd.get (cwd_win32, 0))
362 unsigned cwdlen = strlen (cwd_win32);
363 if (!path_prefix_p (cwd_win32, path, cwdlen, caseinsensitive))
366 size_t n = strlen (path);
374 tail += isdirsep (cwd_win32[cwdlen - 1]) ? cwdlen : cwdlen + 1;
376 memmove (path, tail, strlen (tail) + 1);
382 path_conv::set_normalized_path (const char *path_copy)
386 size_t n = strlen (path_copy) + 1;
387 char *p = (char *) crealloc_abort ((void *) normalized_path, n);
388 normalized_path = (const char *) memcpy (p, path_copy, n);
393 str2uni_cat (UNICODE_STRING &tgt, const char *srcstr)
395 int len = sys_mbstowcs (tgt.Buffer + tgt.Length / sizeof (WCHAR),
396 (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR),
399 tgt.Length += (len - 1) * sizeof (WCHAR);
403 get_nt_native_path (const char *path, UNICODE_STRING& upath, bool dos)
406 if (path[0] == '/') /* special path w/o NT path representation. */
407 str2uni_cat (upath, path);
408 else if (path[0] != '\\') /* X:\... or relative path. */
410 if (path[1] == ':') /* X:\... */
412 RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
413 str2uni_cat (upath, path);
414 /* The drive letter must be upper case. */
415 upath.Buffer[4] = towupper (upath.Buffer[4]);
418 str2uni_cat (upath, path);
419 transform_chars (&upath, 7);
421 else if (path[1] != '\\') /* \Device\... */
422 str2uni_cat (upath, path);
423 else if ((path[2] != '.' && path[2] != '?')
424 || path[3] != '\\') /* \\server\share\... */
426 RtlAppendUnicodeStringToString (&upath, &ro_u_uncp);
427 str2uni_cat (upath, path + 2);
428 transform_chars (&upath, 8);
430 else /* \\.\device or \\?\foo */
432 RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
433 str2uni_cat (upath, path + 4);
437 /* Unfortunately we can't just use transform_chars with the tfx_rev_chars
438 table since only leading and trainlig spaces and dots are affected.
439 So we step to every backslash and fix surrounding dots and spaces.
440 That makes these broken filesystems a bit slower, but, hey. */
441 PWCHAR cp = upath.Buffer + 7;
442 PWCHAR cend = upath.Buffer + upath.Length / sizeof (WCHAR);
447 while (*ccp == L'.' || *ccp == L' ')
449 while (cp[1] == L' ')
452 while (*--cp == L'.' || *cp == L' ')
459 path_conv::get_nt_native_path ()
464 uni_path.MaximumLength = (strlen (path) + 10) * sizeof (WCHAR);
465 wide_path = (PWCHAR) cmalloc_abort (HEAP_STR, uni_path.MaximumLength);
466 uni_path.Buffer = wide_path;
467 ::get_nt_native_path (path, uni_path, has_dos_filenames_only ());
473 path_conv::get_wide_win32_path (PWCHAR wc)
475 get_nt_native_path ();
478 wcpcpy (wc, wide_path);
485 warn_msdos (const char *src)
487 if (user_shared->warned_msdos || !dos_file_warning || !cygwin_finished_initializing)
490 char *posix_path = tp.c_get ();
491 small_printf ("cygwin warning:\n");
492 if (cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, src,
493 posix_path, NT_MAX_PATH))
494 small_printf (" MS-DOS style path detected: %ls\n POSIX equivalent preferred.\n",
497 small_printf (" MS-DOS style path detected: %ls\n Preferred POSIX equivalent is: %ls\n",
499 small_printf (" CYGWIN environment variable option \"nodosfilewarning\" turns off this warning.\n"
500 " Consult the user's guide for more details about POSIX paths:\n"
501 " http://cygwin.com/cygwin-ug-net/using.html#using-pathnames\n");
502 user_shared->warned_msdos = true;
506 getfileattr (const char *path, bool caseinsensitive) /* path has to be always absolute. */
509 UNICODE_STRING upath;
510 OBJECT_ATTRIBUTES attr;
511 FILE_BASIC_INFORMATION fbi;
516 InitializeObjectAttributes (&attr, &upath,
517 caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
519 get_nt_native_path (path, upath, false);
521 status = NtQueryAttributesFile (&attr, &fbi);
522 if (NT_SUCCESS (status))
523 return fbi.FileAttributes;
525 if (status != STATUS_OBJECT_NAME_NOT_FOUND
526 && status != STATUS_NO_SUCH_FILE) /* File not found on 9x share */
528 /* File exists but access denied. Try to get attribute through
530 UNICODE_STRING dirname, basename;
532 FILE_BOTH_DIRECTORY_INFORMATION fdi;
534 RtlSplitUnicodePath (&upath, &dirname, &basename);
535 InitializeObjectAttributes (&attr, &dirname,
536 caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
538 status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
539 &attr, &io, FILE_SHARE_VALID_FLAGS,
540 FILE_SYNCHRONOUS_IO_NONALERT
541 | FILE_OPEN_FOR_BACKUP_INTENT
542 | FILE_DIRECTORY_FILE);
543 if (NT_SUCCESS (status))
545 status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io,
547 FileBothDirectoryInformation,
548 TRUE, &basename, TRUE);
550 if (NT_SUCCESS (status) || status == STATUS_BUFFER_OVERFLOW)
551 return fdi.FileAttributes;
554 SetLastError (RtlNtStatusToDosError (status));
555 return INVALID_FILE_ATTRIBUTES;
558 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
559 passing to Win32 API routines.
561 If an error occurs, `error' is set to the errno value.
562 Otherwise it is set to 0.
565 SYMLINK_FOLLOW - convert to PATH symlink points to
566 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
567 SYMLINK_IGNORE - do not check PATH for symlinks
568 SYMLINK_CONTENTS - just return symlink contents
571 /* TODO: This implementation is only preliminary. For internal
572 purposes it's necessary to have a path_conv::check function which
573 takes a UNICODE_STRING src path, otherwise we waste a lot of time
574 for converting back and forth. The below implementation does
575 realy nothing but converting to char *, until path_conv handles
576 wide-char paths directly. */
578 path_conv::check (const UNICODE_STRING *src, unsigned opt,
579 const suffix_info *suffixes)
582 char *path = tp.c_get ();
584 user_shared->warned_msdos = true;
585 sys_wcstombs (path, NT_MAX_PATH, src->Buffer, src->Length / sizeof (WCHAR));
586 path_conv::check (path, opt, suffixes);
590 path_conv::check (const char *src, unsigned opt,
591 const suffix_info *suffixes)
593 /* The tmp_buf array is used when expanding symlinks. It is NT_MAX_PATH * 2
594 in length so that we can hold the expanded symlink plus a trailer. */
596 char *path_copy = tp.c_get ();
597 char *pathbuf = tp.c_get ();
598 char *tmp_buf = tp.t_get ();
599 char *THIS_path = tp.c_get ();
601 bool need_directory = 0;
602 bool saw_symlinks = 0;
603 bool add_ext = false;
605 char *tail, *path_end;
608 static path_conv last_path_conv;
609 static char last_src[CYG_MAX_PATH];
611 if (*last_src && strcmp (last_src, src) == 0)
613 *this = last_path_conv;
619 if (efault.faulted ())
627 fileattr = INVALID_FILE_ATTRIBUTES;
628 caseinsensitive = OBJ_CASE_INSENSITIVE;
634 cfree (modifiable_path ());
637 close_conv_handle ();
638 memset (&dev, 0, sizeof (dev));
642 cfree ((void *) normalized_path);
643 normalized_path = NULL;
645 int component = 0; // Number of translated components
647 if (!(opt & PC_NULLEMPTY))
655 bool is_msdos = false;
656 /* This loop handles symlink expansion. */
662 is_relpath = !isabspath (src);
663 error = normalize_posix_path (src, path_copy, tail);
673 /* Detect if the user was looking for a directory. We have to strip the
674 trailing slash initially while trying to add extensions but take it
675 into account during processing */
676 if (tail > path_copy + 2 && isslash (tail[-1]))
683 /* Scan path_copy from right to left looking either for a symlink
684 or an actual existing file. If an existing file is found, just
685 return. If a symlink is found, exit the for loop.
686 Also: be careful to preserve the errno returned from
687 symlink.check as the caller may need it. */
688 /* FIXME: Do we have to worry about multiple \'s here? */
689 component = 0; // Number of translated components
690 sym.contents[0] = '\0';
694 for (unsigned pflags_or = opt & (PC_NO_ACCESS_CHECK | PC_KEEP_HANDLE);
698 const suffix_info *suff;
701 /* Don't allow symlink.check to set anything in the path_conv
702 class if we're working on an inner component of the path */
711 full_path = THIS_path;
714 /* Convert to native path spec sans symbolic link info. */
715 error = mount_table->conv_to_win32_path (path_copy, full_path, dev,
721 sym.pflags |= pflags_or;
723 if (dev.major == DEV_CYGDRIVE_MAJOR)
726 fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY;
729 fileattr = getfileattr (THIS_path,
730 sym.pflags & MOUNT_NOPOSIX);
735 else if (dev == FH_DEV)
739 fileattr = getfileattr (THIS_path, sym.pflags & MOUNT_NOPOSIX);
740 if (!component && fileattr == INVALID_FILE_ATTRIBUTES)
742 fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY;
747 else if (isvirtual_dev (dev.devn))
749 /* FIXME: Calling build_fhandler here is not the right way to handle this. */
750 fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy);
751 virtual_ftype_t file_type = fh->exists ();
752 if (file_type == virt_symlink)
755 symlen = sym.set (fh->get_filebuf ());
763 fileattr = FILE_ATTRIBUTE_DIRECTORY;
770 goto is_virtual_symlink;
787 /* Access to real file or directory via block device
788 entry in /proc/sys. Convert to real file and go with
791 goto is_fs_via_procsys;
793 /* Block special device. If the trailing slash has been
794 requested, the target is the root directory of the
795 filesystem on this block device. So we convert this to
796 a real file and attach the backslash. */
797 if (component || need_directory)
802 strcat (full_path, "\\");
803 fileattr = FILE_ATTRIBUTE_DIRECTORY
804 | FILE_ATTRIBUTE_DEVICE;
813 fileattr = FILE_ATTRIBUTE_DEVICE;
817 fileattr = INVALID_FILE_ATTRIBUTES;
818 goto virtual_component_retry;
820 if (component == 0 || dev.devn != FH_NETDRIVE)
821 path_flags |= PATH_RO;
824 /* devn should not be a device. If it is, then stop parsing now. */
825 else if (dev.devn != FH_FS)
828 path_flags = sym.pflags;
834 goto out; /* Found a device. Stop parsing. */
837 /* If path is only a drivename, Windows interprets it as the
838 current working directory on this drive instead of the root
839 dir which is what we want. So we need the trailing backslash
841 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
846 /* Otherwise, if the user requires a directory and explicitely
847 specified a path into the native NT namespace, add the trailing
848 backslash. It's needed to access the root dir. */
849 else if (need_directory
850 && full_path[0] == '\\' && full_path[1] == '\\'
851 && (full_path[2] == '.' || full_path[2] == '?'))
852 strcat (full_path, "\\");
854 /* If the incoming path was given in DOS notation, always treat
855 it as caseinsensitive,noacl path. This must be set before
856 calling sym.check, otherwise the path is potentially treated
859 sym.pflags |= PATH_NOPOSIX | PATH_NOACL;
863 symlen = sym.check (full_path, suff, fs, conv_handle);
874 dev.parse (sym.major, sym.minor);
877 fileattr = sym.fileattr;
881 if (sym.pflags & PATH_SOCKET)
888 fileattr = sym.fileattr;
896 fileattr = sym.fileattr;
897 path_flags = sym.pflags;
900 /* If symlink.check found an existing non-symlink file, then
901 it sets the appropriate flag. It also sets any suffix found
903 if (!sym.issymlink && sym.fileattr != INVALID_FILE_ATTRIBUTES)
908 else if (!(sym.fileattr & FILE_ATTRIBUTE_DIRECTORY))
913 goto out; // file found
915 /* Found a symlink if symlen > 0. If component == 0, then the
916 src path itself was a symlink. If !follow_mode then
917 we're done. Otherwise we have to insert the path found
918 into the full path that we are building and perform all of
919 these operations again on the newly derived path. */
923 if (component == 0 && !need_directory
924 && (!(opt & PC_SYM_FOLLOW)
925 || (is_rep_symlink () && (opt & PC_SYM_NOFOLLOW_REP))))
927 set_symlink (symlen); // last component of path is a symlink.
928 if (opt & PC_SYM_CONTENTS)
930 strcpy (THIS_path, sym.contents);
936 /* Following a symlink we can't trust the collected filesystem
937 information any longer. */
939 /* Close handle, if we have any. Otherwise we're collecting
940 handles while following symlinks. */
941 conv_handle.close ();
944 else if (sym.error && sym.error != ENOENT)
949 /* No existing file found. */
951 virtual_component_retry:
952 /* Find the new "tail" of the path, e.g. in '/for/bar/baz',
954 if (tail != path_end)
956 while (--tail > path_copy + 1 && *tail != '/') {}
957 /* Exit loop if there is no tail or we are at the
958 beginning of a UNC path */
959 if (tail <= path_copy + 1)
960 goto out; // all done
962 /* Haven't found an existing pathname component yet.
963 Pinch off the tail and try again. */
968 /* Arrive here if above loop detected a symlink. */
969 if (++loop > SYMLOOP_MAX)
971 error = ELOOP; // Eep.
978 /* Place the link content, possibly with head and/or tail, in tmp_buf */
981 if (isabspath (sym.contents))
982 headptr = tmp_buf; /* absolute path */
985 /* Copy the first part of the path (with ending /) and point to the end. */
986 char *prevtail = tail;
987 while (--prevtail > path_copy && *prevtail != '/') {}
988 int headlen = prevtail - path_copy + 1;;
989 memcpy (tmp_buf, path_copy, headlen);
990 headptr = &tmp_buf[headlen];
993 /* Make sure there is enough space */
994 if (headptr + symlen >= tmp_buf + (2 * NT_MAX_PATH))
997 error = ENAMETOOLONG;
998 set_path ("::ENAMETOOLONG::");
1002 /* Copy the symlink contents to the end of tmp_buf.
1004 for (char *p = sym.contents; *p; p++)
1005 *headptr++ = *p == '\\' ? '/' : *p;
1008 /* Copy any tail component (with the 0) */
1009 if (tail++ < path_end)
1011 /* Add a slash if needed. There is space. */
1012 if (*(headptr - 1) != '/')
1014 int taillen = path_end - tail + 1;
1015 if (headptr + taillen > tmp_buf + (2 * NT_MAX_PATH))
1017 memcpy (headptr, tail, taillen);
1020 /* Evaluate everything all over again. */
1024 if (!(opt & PC_SYM_CONTENTS))
1028 set_path (THIS_path);
1030 add_ext_from_sym (sym);
1031 if (dev.devn == FH_NETDRIVE && component)
1033 /* This case indicates a non-existant resp. a non-retrievable
1034 share. This happens for instance if the share is a printer.
1035 In this case the path must not be treated like a FH_NETDRIVE,
1036 but like a FH_FS instead, so the usual open call for files
1040 else if (isproc_dev (dev.devn) && fileattr == INVALID_FILE_ATTRIBUTES)
1042 /* FIXME: Usually we don't set error to ENOENT if a file doesn't
1043 exist. This is typically indicated by the fileattr content.
1044 So, why here? The downside is that cygwin_conv_path just gets
1045 an error for these paths so it reports the error back to the
1046 application. Unlike in all other cases of non-existant files,
1047 for which check doesn't set error, so cygwin_conv_path just
1048 returns the path, as intended. */
1052 else if (!need_directory || error)
1053 /* nothing to do */;
1054 else if (fileattr == INVALID_FILE_ATTRIBUTES)
1055 strcat (modifiable_path (), "\\"); /* Reattach trailing dirsep in native path. */
1056 else if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
1057 path_flags &= ~PATH_SYMLINK;
1060 debug_printf ("%s is a non-directory", path);
1067 if (strncmp (path, "\\\\.\\", 4))
1069 if (!tail || tail == path)
1071 else if (tail[-1] != '\\')
1080 /* If FS hasn't been checked already in symlink_info::check, do so now. */
1081 if (fs.inited ()|| fs.update (get_nt_native_path (), NULL))
1083 /* Incoming DOS paths are treated like DOS paths in native
1084 Windows applications. No ACLs, just default settings. */
1086 fs.has_acls (false);
1087 debug_printf ("this->path(%s), has_acls(%d)", path, fs.has_acls ());
1088 /* CV: We could use this->has_acls() but I want to make sure that
1089 we don't forget that the PATH_NOACL flag must be taken into
1091 if (!(path_flags & PATH_NOACL) && fs.has_acls ())
1092 set_exec (0); /* We really don't know if this is executable or not here
1093 but set it to not executable since it will be figured out
1094 later by anything which cares about this. */
1096 /* If the FS has been found to have unrelibale inodes, note
1097 that in path_flags. */
1098 if (!fs.hasgood_inode ())
1099 path_flags |= PATH_IHASH;
1100 /* If the OS is caseinsensitive or the FS is caseinsensitive,
1101 don't handle path casesensitive. */
1102 if (cygwin_shared->obcaseinsensitive || fs.caseinsensitive ())
1103 path_flags |= PATH_NOPOSIX;
1104 caseinsensitive = (path_flags & PATH_NOPOSIX)
1105 ? OBJ_CASE_INSENSITIVE : 0;
1106 if (exec_state () != dont_know_if_executable)
1110 else if (issymlink () || issocket ())
1114 if (opt & PC_NOFULL)
1118 mkrelpath (this->modifiable_path (), !!caseinsensitive);
1119 /* Invalidate wide_path so that wide relpath can be created
1120 in later calls to get_nt_native_path or get_wide_win32_path. */
1127 size_t n = strlen (this->path);
1128 /* Do not add trailing \ to UNC device names like \\.\a: */
1129 if (this->path[n - 1] != '\\' &&
1130 (strncmp (this->path, "\\\\.\\", 4) != 0))
1132 this->modifiable_path ()[n] = '\\';
1133 this->modifiable_path ()[n + 1] = '\0';
1139 set_has_symlinks ();
1141 if ((opt & PC_POSIX))
1143 if (tail < path_end && tail > path_copy + 1)
1145 set_normalized_path (path_copy);
1146 if (is_msdos && !(opt & PC_NOWARN))
1153 last_path_conv = *this;
1154 strcpy (last_src, src);
1159 path_conv::~path_conv ()
1161 if (normalized_path)
1163 cfree ((void *) normalized_path);
1164 normalized_path = NULL;
1168 cfree (modifiable_path ());
1176 close_conv_handle ();
1180 path_conv::is_binary ()
1183 PWCHAR bintest = tp.w_get ();
1186 return GetBinaryTypeW (get_wide_win32_path (bintest), &bin)
1187 && (bin == SCS_32BIT_BINARY || bin == SCS_64BIT_BINARY);
1190 /* Normalize a Win32 path.
1191 /'s are converted to \'s in the process.
1192 All duplicate \'s, except for 2 leading \'s, are deleted.
1194 The result is 0 for success, or an errno error value.
1195 FIXME: A lot of this should be mergeable with the POSIX critter. */
1197 normalize_win32_path (const char *src, char *dst, char *&tail)
1199 const char *src_start = src;
1200 bool beg_src_slash = isdirsep (src[0]);
1203 /* Skip long path name prefixes in Win32 or NT syntax. */
1204 if (beg_src_slash && (src[1] == '?' || isdirsep (src[1]))
1205 && src[2] == '?' && isdirsep (src[3]))
1208 if (src[1] != ':') /* native UNC path */
1209 src += 2; /* Fortunately the first char is not copied... */
1211 beg_src_slash = false;
1213 if (beg_src_slash && isdirsep (src[1]))
1215 if (isdirsep (src[2]))
1217 /* More than two slashes are just folded into one. */
1219 while (isdirsep (src[1]))
1224 /* Two slashes start a network or device path. */
1227 if (src[1] == '.' && isdirsep (src[2]))
1238 /* Always convert drive letter to uppercase for case sensitivity. */
1239 *tail++ = cyg_toupper (*src++);
1240 else if (*src != '/')
1243 tail += cygheap->cwd.get_drive (dst);
1244 else if (!cygheap->cwd.get (dst, 0))
1245 return get_errno ();
1248 tail = strchr (tail, '\0');
1249 if (tail[-1] != '\\')
1257 /* Strip duplicate /'s. */
1258 if (isdirsep (src[0]) && isdirsep (src[1]))
1261 else if (src[0] == '.' && isdirsep (src[1])
1262 && (src == src_start || isdirsep (src[-1])))
1265 /* Backup if "..". */
1266 else if (src[0] == '.' && src[1] == '.'
1267 /* dst must be greater than dst_start */
1268 && tail[-1] == '\\')
1270 if (!isdirsep (src[2]) && src[2] != '\0')
1274 /* Back up over /, but not if it's the first one. */
1277 /* Now back up to the next /. */
1278 while (tail > dst + 1 && tail[-1] != '\\' && tail[-2] != ':')
1281 if (isdirsep (*src))
1285 /* Otherwise, add char to result. */
1294 if ((tail - dst) >= NT_MAX_PATH)
1295 return ENAMETOOLONG;
1297 if (tail > dst + 1 && tail[-1] == '.' && tail[-2] == '\\')
1300 debug_printf ("%s = normalize_win32_path (%s)", dst, src_start);
1304 /* Various utilities. */
1306 /* nofinalslash: Remove trailing / and \ from SRC (except for the
1307 first one). It is ok for src == dst. */
1310 nofinalslash (const char *src, char *dst)
1312 int len = strlen (src);
1314 memcpy (dst, src, len + 1);
1315 while (len > 1 && isdirsep (dst[--len]))
1319 /* conv_path_list: Convert a list of path names to/from Win32/POSIX. */
1322 conv_path_list (const char *src, char *dst, size_t size, int to_posix)
1325 char src_delim, dst_delim;
1326 cygwin_conv_path_t conv_fn;
1333 conv_fn = CCP_WIN_A_TO_POSIX | CCP_RELATIVE;
1339 conv_fn = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
1343 len = strlen (src) + 1;
1344 if (len <= NT_MAX_PATH * sizeof (WCHAR))
1345 srcbuf = (char *) tp.w_get ();
1347 srcbuf = (char *) alloca (len);
1351 bool saw_empty = false;
1354 char *srcpath = srcbuf;
1355 char *s = strccpy (srcpath, &src, src_delim);
1356 size_t len = s - srcpath;
1357 if (len >= NT_MAX_PATH)
1362 /* Paths in Win32 path lists in the environment (%Path%), are often
1363 enclosed in quotes (usually paths with spaces). Trailing backslashes
1364 are common, too. Remove them. */
1365 if (to_posix == ENV_CVT && len)
1367 if (*srcpath == '"')
1373 while (len && s[-1] == '\\')
1382 err = cygwin_conv_path (conv_fn, srcpath, d, size - (d - dst));
1387 err = cygwin_conv_path (conv_fn, ".", d, size - (d - dst));
1391 if (to_posix == ENV_CVT)
1397 d = strchr (d, '\0');
1411 /********************** Symbolic Link Support **************************/
1413 /* Create a symlink from FROMPATH to TOPATH. */
1415 /* If TRUE create symlinks as Windows shortcuts, if false create symlinks
1416 as normal files with magic number and system bit set. */
1417 bool allow_winsymlinks = false;
1420 symlink (const char *oldpath, const char *newpath)
1422 return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
1426 symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
1431 path_conv win32_newpath, win32_oldpath;
1433 SECURITY_ATTRIBUTES sa = sec_none_nih;
1434 OBJECT_ATTRIBUTES attr;
1440 bool mk_winsym = use_winsym;
1441 bool has_trailing_dirsep = false;
1443 /* POSIX says that empty 'newpath' is invalid input while empty
1444 'oldpath' is valid -- it's symlink resolver job to verify if
1445 symlink contents point to existing filesystem object */
1447 if (efault.faulted (EFAULT))
1449 if (!*oldpath || !*newpath)
1455 if (strlen (oldpath) > SYMLINK_MAX)
1457 set_errno (ENAMETOOLONG);
1461 /* Trailing dirsep is a no-no. */
1462 len = strlen (newpath);
1463 has_trailing_dirsep = isdirsep (newpath[len - 1]);
1464 if (has_trailing_dirsep)
1466 newpath = strdup (newpath);
1467 ((char *) newpath)[len - 1] = '\0';
1470 check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0);
1471 /* We need the normalized full path below. */
1472 win32_newpath.check (newpath, check_opt, stat_suffixes);
1473 /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O
1474 attribute. Therefore we create symlinks on MVFS always as shortcuts. */
1475 mk_winsym |= win32_newpath.fs_is_mvfs ();
1477 if (mk_winsym && !win32_newpath.exists ()
1478 && (isdevice || !win32_newpath.fs_is_nfs ()))
1480 char *newplnk = tp.c_get ();
1481 stpcpy (stpcpy (newplnk, newpath), ".lnk");
1482 win32_newpath.check (newplnk, check_opt);
1485 if (win32_newpath.error)
1487 set_errno (win32_newpath.error);
1491 syscall_printf ("symlink (%s, %S)", oldpath,
1492 win32_newpath.get_nt_native_path ());
1494 if ((!isdevice && win32_newpath.exists ())
1495 || win32_newpath.is_auto_device ())
1500 if (has_trailing_dirsep && !win32_newpath.exists ())
1506 if (!isdevice && win32_newpath.fs_is_nfs ())
1508 /* On NFS, create symlinks by calling NtCreateFile with an EA of type
1509 NfsSymlinkTargetName containing ... the symlink target name. */
1510 PFILE_FULL_EA_INFORMATION pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1511 pffei->NextEntryOffset = 0;
1513 pffei->EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1514 char *EaValue = stpcpy (pffei->EaName, NFS_SYML_TARGET) + 1;
1515 pffei->EaValueLength = sizeof (WCHAR) *
1516 (sys_mbstowcs ((PWCHAR) EaValue, NT_MAX_PATH, oldpath) - 1);
1517 status = NtCreateFile (&fh, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE,
1518 win32_newpath.get_object_attr (attr, sa),
1519 &io, NULL, FILE_ATTRIBUTE_SYSTEM,
1520 FILE_SHARE_VALID_FLAGS, FILE_CREATE,
1521 FILE_SYNCHRONOUS_IO_NONALERT
1522 | FILE_OPEN_FOR_BACKUP_INTENT,
1523 pffei, NT_MAX_PATH * sizeof (WCHAR));
1524 if (!NT_SUCCESS (status))
1526 __seterrno_from_nt_status (status);
1536 ITEMIDLIST *pidl = NULL;
1537 size_t full_len = 0;
1538 unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
1539 char desc[MAX_PATH + 1], *relpath;
1543 /* First create an IDLIST to learn how big our shortcut is
1547 /* The symlink target is relative to the directory in which
1548 the symlink gets created, not relative to the cwd. Therefore
1549 we have to mangle the path quite a bit before calling path_conv. */
1550 if (isabspath (oldpath))
1551 win32_oldpath.check (oldpath,
1556 len = strrchr (win32_newpath.normalized_path, '/')
1557 - win32_newpath.normalized_path + 1;
1558 char *absoldpath = tp.t_get ();
1559 stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
1561 win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1563 if (SUCCEEDED (SHGetDesktopFolder (&psl)))
1565 WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
1566 win32_oldpath.get_wide_win32_path (wc_path);
1567 /* Amazing but true: Even though the ParseDisplayName method
1568 takes a wide char path name, it does not understand the
1569 Win32 prefix for long pathnames! So we have to tack off
1570 the prefix and convert the path to the "normal" syntax
1571 for ParseDisplayName. */
1572 WCHAR *wc = wc_path + 4;
1573 if (wc[1] != L':') /* native UNC path */
1576 if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
1581 for (p = pidl; p->mkid.cb > 0;
1582 p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
1584 pidl_len = (char *) p - (char *) pidl + 2;
1589 /* Compute size of shortcut file. */
1590 full_len = sizeof (win_shortcut_hdr);
1592 full_len += sizeof (unsigned short) + pidl_len;
1593 oldpath_len = strlen (oldpath);
1594 /* Unfortunately the length of the description is restricted to a
1595 length of MAX_PATH up to NT4, and to a length of 2000 bytes
1596 since W2K. We don't want to add considerations for the different
1597 lengths and even 2000 bytes is not enough for long path names.
1598 So what we do here is to set the description to the POSIX path
1599 only if the path is not longer than MAX_PATH characters. We
1600 append the full path name after the regular shortcut data
1601 (see below), which works fine with Windows Explorer as well
1602 as older Cygwin versions (as long as the whole file isn't bigger
1603 than 8K). The description field is only used for backward
1604 compatibility to older Cygwin versions and those versions are
1605 not capable of handling long path names anyway. */
1606 desc_len = stpcpy (desc, oldpath_len > MAX_PATH
1607 ? "[path too long]" : oldpath) - desc;
1608 full_len += sizeof (unsigned short) + desc_len;
1609 /* Devices get the oldpath string unchanged as relative path. */
1612 relpath_len = oldpath_len;
1613 stpcpy (relpath = tp.c_get (), oldpath);
1617 relpath_len = strlen (win32_oldpath.get_win32 ());
1618 stpcpy (relpath = tp.c_get (), win32_oldpath.get_win32 ());
1620 full_len += sizeof (unsigned short) + relpath_len;
1621 full_len += sizeof (unsigned short) + oldpath_len;
1622 /* 1 byte more for trailing 0 written by stpcpy. */
1623 if (full_len < NT_MAX_PATH * sizeof (WCHAR))
1624 buf = (char *) tp.w_get ();
1626 buf = (char *) alloca (full_len + 1);
1628 /* Create shortcut header */
1629 win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf;
1630 memset (shortcut_header, 0, sizeof *shortcut_header);
1631 shortcut_header->size = sizeof *shortcut_header;
1632 shortcut_header->magic = GUID_shortcut;
1633 shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH);
1635 shortcut_header->flags |= WSH_FLAG_IDLIST;
1636 shortcut_header->run = SW_NORMAL;
1637 cp = buf + sizeof (win_shortcut_hdr);
1642 *(unsigned short *)cp = pidl_len;
1643 memcpy (cp += 2, pidl, pidl_len);
1645 CoTaskMemFree (pidl);
1648 /* Create description */
1649 *(unsigned short *)cp = desc_len;
1650 cp = stpcpy (cp += 2, desc);
1652 /* Create relpath */
1653 *(unsigned short *)cp = relpath_len;
1654 cp = stpcpy (cp += 2, relpath);
1656 /* Append the POSIX path after the regular shortcut data for
1657 the long path support. */
1658 unsigned short *plen = (unsigned short *) cp;
1660 *(PWCHAR) cp = 0xfeff; /* BOM */
1662 *plen = sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1667 /* Default technique creating a symlink. */
1668 buf = (char *) tp.w_get ();
1669 cp = stpcpy (buf, SYMLINK_COOKIE);
1670 *(PWCHAR) cp = 0xfeff; /* BOM */
1672 /* Note that the terminating nul is written. */
1673 cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1676 if (isdevice && win32_newpath.exists ())
1678 status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
1679 win32_newpath.get_object_attr (attr, sa),
1680 &io, 0, FILE_OPEN_FOR_BACKUP_INTENT);
1681 if (!NT_SUCCESS (status))
1683 __seterrno_from_nt_status (status);
1686 status = NtSetAttributesFile (fh, FILE_ATTRIBUTE_NORMAL);
1688 if (!NT_SUCCESS (status))
1690 __seterrno_from_nt_status (status);
1694 status = NtCreateFile (&fh, DELETE | FILE_GENERIC_WRITE,
1695 win32_newpath.get_object_attr (attr, sa),
1696 &io, NULL, FILE_ATTRIBUTE_NORMAL,
1697 FILE_SHARE_VALID_FLAGS,
1698 isdevice ? FILE_OVERWRITE_IF : FILE_CREATE,
1699 FILE_SYNCHRONOUS_IO_NONALERT
1700 | FILE_NON_DIRECTORY_FILE
1701 | FILE_OPEN_FOR_BACKUP_INTENT,
1703 if (!NT_SUCCESS (status))
1705 __seterrno_from_nt_status (status);
1708 if (win32_newpath.has_acls ())
1709 set_file_attribute (fh, win32_newpath, ILLEGAL_UID, ILLEGAL_GID,
1710 (io.Information == FILE_CREATED ? S_JUSTCREATED : 0)
1711 | S_IFLNK | STD_RBITS | STD_WBITS);
1712 status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL);
1713 if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf))
1715 status = NtSetAttributesFile (fh, mk_winsym ? FILE_ATTRIBUTE_READONLY
1716 : FILE_ATTRIBUTE_SYSTEM);
1717 if (!NT_SUCCESS (status))
1718 debug_printf ("Setting attributes failed, status = %p", status);
1723 __seterrno_from_nt_status (status);
1724 FILE_DISPOSITION_INFORMATION fdi = { TRUE };
1725 status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
1726 FileDispositionInformation);
1727 if (!NT_SUCCESS (status))
1728 debug_printf ("Setting delete dispostion failed, status = %p", status);
1733 syscall_printf ("%d = symlink_worker (%s, %s, %d, %d)", res, oldpath,
1734 newpath, mk_winsym, isdevice);
1735 if (has_trailing_dirsep)
1736 free ((void *) newpath);
1741 cmp_shortcut_header (win_shortcut_hdr *file_header)
1743 /* A Cygwin or U/Win shortcut only contains a description and a relpath.
1744 Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
1745 always set to SW_NORMAL. */
1746 return file_header->size == sizeof (win_shortcut_hdr)
1747 && !memcmp (&file_header->magic, &GUID_shortcut, sizeof GUID_shortcut)
1748 && (file_header->flags & ~WSH_FLAG_IDLIST)
1749 == (WSH_FLAG_DESC | WSH_FLAG_RELPATH)
1750 && file_header->run == SW_NORMAL;
1754 symlink_info::check_shortcut (HANDLE h)
1757 win_shortcut_hdr *file_header;
1763 FILE_STANDARD_INFORMATION fsi;
1764 LARGE_INTEGER off = { QuadPart:0LL };
1766 status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
1767 FileStandardInformation);
1768 if (!NT_SUCCESS (status))
1773 if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
1774 || fsi.EndOfFile.QuadPart > 4 * 65536)
1776 if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
1777 buf = (char *) tp.w_get ();
1779 buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
1780 status = NtReadFile (h, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
1782 if (!NT_SUCCESS (status))
1784 if (status != STATUS_END_OF_FILE)
1788 file_header = (win_shortcut_hdr *) buf;
1789 if (io.Information != fsi.EndOfFile.LowPart
1790 || !cmp_shortcut_header (file_header))
1792 cp = buf + sizeof (win_shortcut_hdr);
1793 if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
1794 cp += *(unsigned short *) cp + 2;
1795 if (!(len = *(unsigned short *) cp))
1798 /* Check if this is a device file - these start with the sequence :\\ */
1799 if (strncmp (cp, ":\\", 2) == 0)
1800 res = strlen (strcpy (contents, cp)); /* Don't mess with device files */
1803 /* Has appended full path? If so, use it instead of description. */
1804 unsigned short relpath_len = *(unsigned short *) (cp + len);
1805 if (cp + len + 2 + relpath_len < buf + fsi.EndOfFile.LowPart)
1807 cp += len + 2 + relpath_len;
1808 len = *(unsigned short *) cp;
1811 if (*(PWCHAR) cp == 0xfeff) /* BOM */
1813 char *tmpbuf = tp.c_get ();
1814 if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2))
1817 res = posixify (tmpbuf);
1819 else if (len > SYMLINK_MAX)
1824 res = posixify (cp);
1827 if (res) /* It's a symlink. */
1828 pflags |= PATH_SYMLINK | PATH_LNK;
1833 symlink_info::check_sysfile (HANDLE h)
1836 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
1837 char *srcbuf = tp.c_get ();
1841 bool interix_symlink = false;
1842 LARGE_INTEGER off = { QuadPart:0LL };
1844 status = NtReadFile (h, NULL, NULL, NULL, &io, cookie_buf,
1845 sizeof (cookie_buf), &off, NULL);
1846 if (!NT_SUCCESS (status))
1848 debug_printf ("ReadFile1 failed %p", status);
1849 if (status != STATUS_END_OF_FILE)
1853 off.QuadPart = io.Information;
1854 if (io.Information == sizeof (cookie_buf)
1855 && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
1857 /* It's a symlink. */
1858 pflags |= PATH_SYMLINK;
1860 else if (io.Information == sizeof (cookie_buf)
1861 && memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
1862 pflags |= PATH_SOCKET;
1863 else if (io.Information >= sizeof (INTERIX_SYMLINK_COOKIE)
1864 && memcmp (cookie_buf, INTERIX_SYMLINK_COOKIE,
1865 sizeof (INTERIX_SYMLINK_COOKIE) - 1) == 0)
1867 /* It's an Interix symlink. */
1868 pflags |= PATH_SYMLINK;
1869 interix_symlink = true;
1870 /* Interix symlink cookies are shorter than Cygwin symlink cookies, so
1871 in case of an Interix symlink cooky we have read too far into the
1872 file. Set file pointer back to the position right after the cookie. */
1873 off.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1;
1875 if (pflags & PATH_SYMLINK)
1877 status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
1878 NT_MAX_PATH, &off, NULL);
1879 if (!NT_SUCCESS (status))
1881 debug_printf ("ReadFile2 failed");
1882 if (status != STATUS_END_OF_FILE)
1885 else if (*(PWCHAR) srcbuf == 0xfeff /* BOM */
1888 /* Add trailing 0 to Interix symlink target. Skip BOM in Cygwin
1890 if (interix_symlink)
1891 ((PWCHAR) srcbuf)[io.Information / sizeof (WCHAR)] = L'\0';
1894 char *tmpbuf = tp.c_get ();
1895 if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) srcbuf)
1897 debug_printf ("symlink string too long");
1899 res = posixify (tmpbuf);
1901 else if (io.Information > SYMLINK_MAX + 1)
1902 debug_printf ("symlink string too long");
1904 res = posixify (srcbuf);
1910 symlink_info::check_reparse_point (HANDLE h)
1915 PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) tp.c_get ();
1916 UNICODE_STRING subst;
1917 char srcbuf[SYMLINK_MAX + 7];
1919 status = NtFsControlFile (h, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT,
1920 NULL, 0, (LPVOID) rp,
1921 MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1922 if (!NT_SUCCESS (status))
1924 debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %p",
1929 if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
1930 RtlInitCountedUnicodeString (&subst,
1931 (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
1932 + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset),
1933 rp->SymbolicLinkReparseBuffer.SubstituteNameLength);
1934 else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
1936 RtlInitCountedUnicodeString (&subst,
1937 (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
1938 + rp->MountPointReparseBuffer.SubstituteNameOffset),
1939 rp->MountPointReparseBuffer.SubstituteNameLength);
1940 if (RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE))
1942 /* Volume mount point. Not treated as symlink. The return
1943 value of -1 is a hint for the caller to treat this as a
1944 volume mount point. */
1950 /* Maybe it's a reparse point, but it's certainly not one we
1951 recognize. Drop the REPARSE file attribute so we don't even
1952 try to use the flag for some special handling. It's just some
1953 arbitrary file or directory for us. */
1954 fileattr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1957 sys_wcstombs (srcbuf, SYMLINK_MAX + 7, subst.Buffer,
1958 subst.Length / sizeof (WCHAR));
1959 pflags |= PATH_SYMLINK | PATH_REP;
1960 /* A symlink is never a directory. */
1961 fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
1962 return posixify (srcbuf);
1966 symlink_info::check_nfs_symlink (HANDLE h)
1972 FILE_GET_EA_INFORMATION fgei;
1973 char buf[sizeof (NFS_SYML_TARGET)];
1975 PFILE_FULL_EA_INFORMATION pffei;
1978 /* To find out if the file is a symlink and to get the symlink target,
1979 try to fetch the NfsSymlinkTargetName EA. */
1980 fgei_buf.fgei.NextEntryOffset = 0;
1981 fgei_buf.fgei.EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1982 stpcpy (fgei_buf.fgei.EaName, NFS_SYML_TARGET);
1983 pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1984 status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE,
1985 &fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
1986 if (NT_SUCCESS (status) && pffei->EaValueLength > 0)
1988 PWCHAR spath = (PWCHAR)
1989 (pffei->EaName + pffei->EaNameLength + 1);
1990 res = sys_wcstombs (contents, SYMLINK_MAX + 1,
1991 spath, pffei->EaValueLength) - 1;
1992 pflags |= PATH_SYMLINK;
1998 symlink_info::posixify (char *srcbuf)
2000 /* The definition for a path in a native symlink is a bit weird. The Flags
2001 value seem to contain 0 for absolute paths (stored as NT native path)
2002 and 1 for relative paths. Relative paths are paths not starting with a
2003 drive letter. These are not converted to NT native, but stored as
2004 given. A path starting with a single backslash is relative to the
2005 current drive thus a "relative" value (Flags == 1).
2006 Funny enough it's possible to store paths with slashes instead of
2007 backslashes, but they are evaluated incorrectly by subsequent Windows
2008 calls like CreateFile (ERROR_INVALID_NAME). So, what we do here is to
2009 take paths starting with slashes at face value, evaluating them as
2010 Cygwin specific POSIX paths.
2011 A path starting with two slashes(!) or backslashes is converted into an
2012 NT UNC path. Unfortunately, in contrast to POSIX rules, paths starting
2013 with three or more (back)slashes are also converted into UNC paths,
2014 just incorrectly sticking to one redundant leading backslashe. We go
2015 along with this behaviour to avoid scenarios in which native tools access
2016 other files than Cygwin.
2017 The above rules are used exactly the same way on Cygwin specific symlinks
2018 (sysfiles and shortcuts) to eliminate non-POSIX paths in the output. */
2020 /* Eliminate native NT prefixes. */
2021 if (srcbuf[0] == '\\' && !strncmp (srcbuf + 1, "??\\", 3))
2024 if (srcbuf[1] != ':') /* native UNC path */
2025 *(srcbuf += 2) = '\\';
2027 if (isdrive (srcbuf))
2028 mount_table->conv_to_posix_path (srcbuf, contents, 0);
2029 else if (srcbuf[0] == '\\')
2031 if (srcbuf[1] == '\\') /* UNC path */
2032 slashify (srcbuf, contents, 0);
2033 else /* Paths starting with \ are current drive relative. */
2035 char cvtbuf[SYMLINK_MAX + 1];
2037 stpcpy (cvtbuf + cygheap->cwd.get_drive (cvtbuf), srcbuf);
2038 mount_table->conv_to_posix_path (cvtbuf, contents, 0);
2041 else /* Everything else is taken as is. */
2042 slashify (srcbuf, contents, 0);
2043 return strlen (contents);
2052 SCAN_JUSTCHECKTHIS, /* Never try to append a suffix. */
2060 const suffix_info *suffixes, *suffixes_start;
2065 char *has (const char *, const suffix_info *);
2067 int lnk_match () {return nextstate >= SCAN_APPENDLNK;}
2071 suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
2073 nextstate = SCAN_BEG;
2074 suffixes = suffixes_start = in_suffixes;
2076 const char *fname = strrchr (in_path, '\\');
2077 fname = fname ? fname + 1 : in_path;
2078 char *ext_here = strrchr (fname, '.');
2080 eopath = strchr (path, '\0');
2087 /* Check if the extension matches a known extension */
2088 for (const suffix_info *ex = in_suffixes; ex->name != NULL; ex++)
2089 if (ascii_strcasematch (ext_here, ex->name))
2091 nextstate = SCAN_JUSTCHECK;
2092 suffixes = NULL; /* Has an extension so don't scan for one. */
2097 /* Didn't match. Use last resort -- .lnk. */
2098 if (ascii_strcasematch (ext_here, ".lnk"))
2100 nextstate = SCAN_HASLNK;
2108 /* Avoid attaching suffixes if the resulting filename would be invalid. */
2109 if (eopath - fname > NAME_MAX - 4)
2111 nextstate = SCAN_JUSTCHECKTHIS;
2118 suffix_scan::next ()
2126 suffixes = suffixes_start;
2129 nextstate = SCAN_LNK;
2132 nextstate = SCAN_EXTRALNK;
2133 /* fall through to suffix checking below */
2136 nextstate = SCAN_APPENDLNK; /* Skip SCAN_BEG */
2139 nextstate = SCAN_DONE;
2142 case SCAN_JUSTCHECK:
2143 nextstate = SCAN_LNK;
2145 case SCAN_JUSTCHECKTHIS:
2146 nextstate = SCAN_DONE;
2149 case SCAN_APPENDLNK:
2150 strcat (eopath, ".lnk");
2151 nextstate = SCAN_DONE;
2158 while (suffixes && suffixes->name)
2159 if (nextstate == SCAN_EXTRALNK && !suffixes->addon)
2163 strcpy (eopath, suffixes->name);
2164 if (nextstate == SCAN_EXTRALNK)
2165 strcat (eopath, ".lnk");
2174 symlink_info::set_error (int in_errno)
2177 if (!(pflags & PATH_NO_ACCESS_CHECK) || in_errno == ENAMETOOLONG || in_errno == EIO)
2182 else if (in_errno == ENOENT)
2186 fileattr = FILE_ATTRIBUTE_NORMAL;
2193 symlink_info::parse_device (const char *contents)
2200 mymajor = strtol (contents += 2, &endptr, 16);
2201 if (endptr == contents)
2202 return isdevice = false;
2205 myminor = strtol (++contents, &endptr, 16);
2206 if (endptr == contents)
2207 return isdevice = false;
2210 mymode = strtol (++contents, &endptr, 16);
2211 if (endptr == contents)
2212 return isdevice = false;
2214 if ((mymode & S_IFMT) == S_IFIFO)
2216 mymajor = _major (FH_FIFO);
2217 myminor = _minor (FH_FIFO);
2223 return isdevice = true;
2226 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2228 If PATH is a symlink, put the value of the symlink--the file to
2229 which it points--into BUF. The value stored in BUF is not
2230 necessarily null terminated. BUFLEN is the length of BUF; only up
2231 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2232 which case nothing will be stored.
2234 Set *SYML if PATH is a symlink.
2236 Set *EXEC if PATH appears to be executable. This is an efficiency
2237 hack because we sometimes have to open the file anyhow. *EXEC will
2238 not be set for every executable file.
2240 Return -1 on error, 0 if PATH is not a symlink, or the length
2241 stored into BUF if PATH is a symlink. */
2244 symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs,
2245 path_conv_handle &conv_hdl)
2250 UNICODE_STRING upath;
2251 OBJECT_ATTRIBUTES attr;
2255 const ULONG ci_flag = cygwin_shared->obcaseinsensitive
2256 || (pflags & PATH_NOPOSIX) ? OBJ_CASE_INSENSITIVE : 0;
2257 /* TODO: Temporarily do all char->UNICODE conversion here. This should
2258 already be slightly faster than using Ascii functions. */
2261 InitializeObjectAttributes (&attr, &upath, ci_flag, NULL, NULL);
2263 /* This label is used in case we encounter a FS which only handles
2264 DOS paths. See below. */
2265 bool restarted = false;
2276 pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
2278 ext_here = suffix.has (path, suffixes);
2279 extn = ext_here - path;
2281 PVOID eabuf = &nfs_aol_ffei;
2282 ULONG easize = sizeof nfs_aol_ffei;
2284 bool had_ext = !!*ext_here;
2285 while (suffix.next ())
2290 get_nt_native_path (suffix.path, upath, pflags & PATH_DOS);
2296 /* The EA given to NtCreateFile allows to get a handle to a symlink on
2297 an NFS share, rather than getting a handle to the target of the
2298 symlink (which would spoil the task of this method quite a bit).
2299 Fortunately it's ignored on most other file systems so we don't have
2300 to special case NFS too much. */
2301 status = NtCreateFile (&h,
2302 READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA,
2303 &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS,
2305 FILE_OPEN_REPARSE_POINT
2306 | FILE_OPEN_FOR_BACKUP_INTENT,
2308 debug_printf ("%p = NtCreateFile (%S)", status, &upath);
2309 /* No right to access EAs or EAs not supported? */
2310 if (!NT_SUCCESS (status)
2311 && (status == STATUS_ACCESS_DENIED
2312 || status == STATUS_EAS_NOT_SUPPORTED
2313 || status == STATUS_NOT_SUPPORTED
2314 || status == STATUS_INVALID_NETWORK_RESPONSE
2315 /* Or a bug in Samba 3.2.x (x <= 7) when accessing a share's
2316 root dir which has EAs enabled? */
2317 || status == STATUS_INVALID_PARAMETER))
2320 /* If EAs are not supported, there's no sense to check them again
2321 with suffixes attached. So we set eabuf/easize to 0 here once. */
2322 if (status == STATUS_EAS_NOT_SUPPORTED
2323 || status == STATUS_NOT_SUPPORTED)
2328 status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2329 &attr, &io, FILE_SHARE_VALID_FLAGS,
2330 FILE_OPEN_REPARSE_POINT
2331 | FILE_OPEN_FOR_BACKUP_INTENT);
2332 debug_printf ("%p = NtOpenFile (no-EAs %S)", status, &upath);
2334 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
2336 if (ci_flag == 0 && wincap.has_broken_udf ()
2337 && (!fs.inited () || fs.is_udf ()))
2339 /* On NT 5.x UDF is broken (at least) in terms of case
2340 sensitivity. When trying to open a file case sensitive,
2341 the file appears to be non-existant. Another bug is
2342 described in fs_info::update. */
2343 attr.Attributes = OBJ_CASE_INSENSITIVE;
2344 status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2345 &attr, &io, FILE_SHARE_VALID_FLAGS,
2346 FILE_OPEN_REPARSE_POINT
2347 | FILE_OPEN_FOR_BACKUP_INTENT);
2348 debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath);
2349 attr.Attributes = 0;
2350 if (NT_SUCCESS (status))
2353 fs.update (&upath, h);
2358 status = STATUS_OBJECT_NAME_NOT_FOUND;
2362 /* There are filesystems out in the wild (Netapp, NWFS, and others)
2363 which are uncapable of generating pathnames outside the Win32
2364 rules. That means, filenames on these FSes must not have a
2365 leading space or trailing dots and spaces. This code snippet
2366 manages them. I really hope it's streamlined enough not to
2367 slow down normal operation. This extra check only kicks in if
2368 we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't
2369 already attach a suffix *and* the above special case for UDF
2370 on XP didn't succeeed. */
2371 if (!restarted && !*ext_here && !(pflags & PATH_DOS) && !fs.inited ())
2373 /* Check for trailing dot or space or leading space in
2375 char *p = ext_here - 1;
2376 if (*p != '.' && *p != ' ')
2378 while (*--p != '\\')
2385 /* If so, check if file resides on one of the known broken
2386 FSes only supporting filenames following DOS rules. */
2388 fs.update (&upath, NULL);
2389 if (fs.has_dos_filenames_only ())
2391 /* If so, try again. Since we now know the FS, the
2392 filenames will be tweaked to follow DOS rules via the
2393 third parameter in the call to get_nt_native_path. */
2402 if (NT_SUCCESS (status)
2403 /* Check file system while we're having the file open anyway.
2404 This speeds up path_conv noticably (~10%). */
2405 && (fs.inited () || fs.update (&upath, h)))
2409 status = nfs_fetch_fattr3 (h, conv_hdl.nfsattr ());
2410 if (NT_SUCCESS (status))
2411 fileattr = ((conv_hdl.nfsattr ()->type & 7) == NF3DIR)
2412 ? FILE_ATTRIBUTE_DIRECTORY : 0;
2416 PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2418 /* Netapps don't implement FileNetworkOpenInformation. */
2419 status = fs.is_netapp ()
2420 ? STATUS_INVALID_PARAMETER
2421 : NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi,
2422 FileNetworkOpenInformation);
2423 if (status == STATUS_INVALID_PARAMETER
2424 || status == STATUS_NOT_IMPLEMENTED)
2426 /* Apart from accessing Netapps, this also occurs when
2427 accessing SMB share root dirs hosted on NT4
2428 (STATUS_INVALID_PARAMETER), or when trying to access
2429 SMB share root dirs from NT4 (STATUS_NOT_IMPLEMENTED). */
2430 FILE_BASIC_INFORMATION fbi;
2431 FILE_STANDARD_INFORMATION fsi;
2433 status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
2434 FileBasicInformation);
2435 if (NT_SUCCESS (status))
2437 memcpy (pfnoi, &fbi, 4 * sizeof (LARGE_INTEGER));
2438 if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fsi,
2440 FileStandardInformation)))
2442 pfnoi->EndOfFile.QuadPart = fsi.EndOfFile.QuadPart;
2443 pfnoi->AllocationSize.QuadPart
2444 = fsi.AllocationSize.QuadPart;
2447 pfnoi->EndOfFile.QuadPart
2448 = pfnoi->AllocationSize.QuadPart = 0;
2449 pfnoi->FileAttributes = fbi.FileAttributes;
2452 if (NT_SUCCESS (status))
2453 fileattr = pfnoi->FileAttributes;
2456 if (!NT_SUCCESS (status))
2458 debug_printf ("%p = NtQueryInformationFile (%S)", status, &upath);
2459 fileattr = INVALID_FILE_ATTRIBUTES;
2461 /* One of the inner path components is invalid, or the path contains
2462 invalid characters. Bail out with ENOENT.
2464 Note that additional STATUS_OBJECT_PATH_INVALID and
2465 STATUS_OBJECT_PATH_SYNTAX_BAD status codes exist. The first one
2466 is seemingly not generated by NtQueryInformationFile, the latter
2467 is only generated if the path is no absolute path within the
2468 NT name space, which should not happen and would point to an
2469 error in get_nt_native_path. Both status codes are deliberately
2470 not tested here unless proved necessary. */
2471 if (status == STATUS_OBJECT_PATH_NOT_FOUND
2472 || status == STATUS_OBJECT_NAME_INVALID
2473 || status == STATUS_BAD_NETWORK_PATH
2474 || status == STATUS_BAD_NETWORK_NAME
2475 || status == STATUS_NO_MEDIA_IN_DEVICE)
2478 goto file_not_symlink;
2480 if (status != STATUS_OBJECT_NAME_NOT_FOUND
2481 && status != STATUS_NO_SUCH_FILE) /* ENOENT on NFS or 9x share */
2483 /* The file exists, but the user can't access it for one reason
2484 or the other. To get the file attributes we try to access the
2485 information by opening the parent directory and getting the
2486 file attributes using a matching NtQueryDirectoryFile call. */
2487 UNICODE_STRING dirname, basename;
2488 OBJECT_ATTRIBUTES dattr;
2491 FILE_BOTH_DIRECTORY_INFORMATION fdi;
2492 WCHAR dummy_buf[NAME_MAX + 1];
2495 RtlSplitUnicodePath (&upath, &dirname, &basename);
2496 InitializeObjectAttributes (&dattr, &dirname, ci_flag,
2498 status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
2499 &dattr, &io, FILE_SHARE_VALID_FLAGS,
2500 FILE_SYNCHRONOUS_IO_NONALERT
2501 | FILE_OPEN_FOR_BACKUP_INTENT
2502 | FILE_DIRECTORY_FILE);
2503 if (!NT_SUCCESS (status))
2505 debug_printf ("%p = NtOpenFile(%S)", status, &dirname);
2506 /* There's a special case if the file is itself the root
2507 of a drive which is not accessible by the current user.
2508 This case is only recognized by the length of the
2509 basename part. If it's 0, the incoming file is the
2510 root of a drive. So we at least know it's a directory. */
2511 fileattr = basename.Length ? 0 : FILE_ATTRIBUTE_DIRECTORY;
2515 status = NtQueryDirectoryFile (dir, NULL, NULL, NULL, &io,
2516 &fdi_buf, sizeof fdi_buf,
2517 FileBothDirectoryInformation,
2518 TRUE, &basename, TRUE);
2519 /* Take the opportunity to check file system while we're
2520 having the handle to the parent dir. */
2521 fs.update (&upath, dir);
2523 if (!NT_SUCCESS (status))
2525 debug_printf ("%p = NtQueryDirectoryFile(%S)",
2527 if (status == STATUS_NO_SUCH_FILE)
2529 /* This can happen when trying to access files
2530 which match DOS device names on SMB shares.
2531 NtOpenFile failed with STATUS_ACCESS_DENIED,
2532 but the NtQueryDirectoryFile tells us the
2533 file doesn't exist. We're suspicious in this
2534 case and retry with the next suffix instead of
2543 PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2545 fileattr = fdi_buf.fdi.FileAttributes;
2546 memcpy (pfnoi, &fdi_buf.fdi.CreationTime, sizeof *pfnoi);
2547 /* Amazing, but true: The FILE_NETWORK_OPEN_INFORMATION
2548 structure has the AllocationSize and EndOfFile members
2549 interchanged relative to the directory information
2551 pfnoi->AllocationSize.QuadPart
2552 = fdi_buf.fdi.AllocationSize.QuadPart;
2553 pfnoi->EndOfFile.QuadPart
2554 = fdi_buf.fdi.EndOfFile.QuadPart;
2557 ext_tacked_on = !!*ext_here;
2558 goto file_not_symlink;
2564 ext_tacked_on = !!*ext_here;
2565 /* Don't allow to returns directories with appended suffix. If we found
2566 a directory with a suffix which has been appended here, then this
2567 directory doesn't match the request. So, just do as usual if file
2568 hasn't been found. */
2569 if (ext_tacked_on && !had_ext && (fileattr & FILE_ATTRIBUTE_DIRECTORY))
2577 /* Reparse points are potentially symlinks. This check must be
2578 performed before checking the SYSTEM attribute for sysfile
2579 symlinks, since reparse points can have this flag set, too.
2580 For instance, Vista starts to create a couple of reparse points
2581 with SYSTEM and HIDDEN flags set. */
2582 if ((fileattr & FILE_ATTRIBUTE_REPARSE_POINT))
2584 /* Don't check reparse points on remote filesystems. A reparse point
2585 pointing to another file on the remote system will be mistreated
2586 as pointing to a local file on the local system. This breaks the
2587 way reparse points are transparently handled on remote systems. */
2588 if (fs.is_remote_drive())
2591 res = check_reparse_point (h);
2594 /* Volume mount point. The filesystem information for the top
2595 level directory should be for the volume top level directory,
2596 rather than for the reparse point itself. So we fetch the
2597 filesystem information again, but with a NULL handle.
2598 This does what we want because fs_info::update opens the
2599 handle without FILE_OPEN_REPARSE_POINT. */
2600 fs.update (&upath, NULL);
2601 /* Make sure the open handle is not used in later stat calls.
2602 The handle has been opened with the FILE_OPEN_REPARSE_POINT
2603 flag, so it's a handle to the reparse point, not a handle
2604 to the volumes root dir. */
2605 pflags &= ~PC_KEEP_HANDLE;
2609 /* A symlink is never a directory. */
2610 conv_hdl.fnoi ()->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
2615 /* Windows shortcuts are potentially treated as symlinks. Valid Cygwin
2616 & U/WIN shortcuts are R/O, but definitely not directories. */
2617 else if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
2618 == FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
2622 status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2623 FILE_SHARE_VALID_FLAGS,
2624 FILE_OPEN_FOR_BACKUP_INTENT
2625 | FILE_SYNCHRONOUS_IO_NONALERT);
2626 if (!NT_SUCCESS (status))
2630 res = check_shortcut (sym_h);
2635 /* If searching for `foo' and then finding a `foo.lnk' which
2636 is no shortcut, return the same as if file not found. */
2639 fileattr = INVALID_FILE_ATTRIBUTES;
2644 else if (contents[0] != ':' || contents[1] != '\\'
2645 || !parse_device (contents))
2649 /* If searching for `foo' and then finding a `foo.lnk' which is
2650 no shortcut, return the same as if file not found. */
2651 else if (suffix.lnk_match () && ext_tacked_on)
2653 fileattr = INVALID_FILE_ATTRIBUTES;
2658 /* This is the old Cygwin method creating symlinks. A symlink will
2659 have the `system' file attribute. Only files can be symlinks
2660 (which can be symlinks to directories). */
2661 else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))
2662 == FILE_ATTRIBUTE_SYSTEM)
2666 status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2667 FILE_SHARE_VALID_FLAGS,
2668 FILE_OPEN_FOR_BACKUP_INTENT
2669 | FILE_SYNCHRONOUS_IO_NONALERT);
2671 if (!NT_SUCCESS (status))
2675 res = check_sysfile (sym_h);
2682 /* If the file is on an NFS share and could be opened with extended
2683 attributes, check if it's a symlink. Only files can be symlinks
2684 (which can be symlinks to directories). */
2685 else if (fs.is_nfs () && (conv_hdl.nfsattr ()->type & 7) == NF3LNK)
2687 res = check_nfs_symlink (h);
2695 syscall_printf ("%s", isdevice ? "is a device" : "not a symlink");
2702 if (pflags & PC_KEEP_HANDLE)
2708 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2709 res, suffix.path, contents, pflags);
2713 /* "path" is the path in a virtual symlink. Set a symlink_info struct from
2714 that and proceed with further path checking afterwards. */
2716 symlink_info::set (char *path)
2718 strcpy (contents, path);
2719 pflags = PATH_SYMLINK;
2720 fileattr = FILE_ATTRIBUTE_NORMAL;
2724 ext_tacked_on = false;
2726 extn = major = minor = mode = 0;
2727 return strlen (path);
2730 /* readlink system call */
2733 readlink (const char *path, char *buf, size_t buflen)
2737 set_errno (ENAMETOOLONG);
2741 path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2745 set_errno (pathbuf.error);
2746 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2750 if (!pathbuf.exists ())
2756 if (!pathbuf.issymlink ())
2758 if (pathbuf.exists ())
2763 ssize_t len = min (buflen, strlen (pathbuf.get_win32 ()));
2764 memcpy (buf, pathbuf.get_win32 (), len);
2766 /* errno set by symlink.check if error */
2770 /* Some programs rely on st_dev/st_ino being unique for each file.
2771 Hash the path name and hope for the best. The hash arg is not
2772 always initialized to zero since readdir needs to compute the
2773 dirent ino_t based on a combination of the hash of the directory
2774 done during the opendir call and the hash or the filename within
2775 the directory. FIXME: Not bullet-proof. */
2776 /* Cygwin internal */
2778 hash_path_name (__ino64_t hash, PUNICODE_STRING name)
2780 if (name->Length == 0)
2783 /* Build up hash. Name is already normalized */
2784 USHORT len = name->Length / sizeof (WCHAR);
2785 for (USHORT idx = 0; idx < len; ++idx)
2786 hash = RtlUpcaseUnicodeChar (name->Buffer[idx])
2787 + (hash << 6) + (hash << 16) - hash;
2792 hash_path_name (__ino64_t hash, PCWSTR name)
2794 UNICODE_STRING uname;
2795 RtlInitUnicodeString (&uname, name);
2796 return hash_path_name (hash, &uname);
2800 hash_path_name (__ino64_t hash, const char *name)
2802 UNICODE_STRING uname;
2803 RtlCreateUnicodeStringFromAsciiz (&uname, name);
2804 __ino64_t ret = hash_path_name (hash, &uname);
2805 RtlFreeUnicodeString (&uname);
2810 getcwd (char *buf, size_t ulen)
2814 if (efault.faulted (EFAULT))
2816 else if (ulen == 0 && buf)
2819 res = cygheap->cwd.get (buf, 1, 1, ulen);
2823 /* getwd: Legacy. */
2827 return getcwd (buf, PATH_MAX + 1); /*Per SuSv3!*/
2830 /* chdir: POSIX 5.2.1.1 */
2832 chdir (const char *in_dir)
2835 if (efault.faulted (EFAULT))
2843 syscall_printf ("dir '%s'", in_dir);
2845 /* Convert path. First argument ensures that we don't check for NULL/empty/invalid
2847 path_conv path (PC_NONULLEMPTY, in_dir, PC_SYM_FOLLOW | PC_POSIX);
2850 set_errno (path.error);
2851 syscall_printf ("-1 = chdir (%s)", in_dir);
2856 const char *posix_cwd = NULL;
2857 int devn = path.get_devn ();
2858 if (!path.exists ())
2860 else if (!path.isdir ())
2861 set_errno (ENOTDIR);
2862 else if (!isvirtual_dev (devn))
2864 /* The sequence chdir("xx"); chdir(".."); must be a noop if xx
2865 is not a symlink. This is exploited by find.exe.
2866 The posix_cwd is just path.normalized_path.
2867 In other cases we let cwd.set obtain the Posix path through
2869 if (!isdrive(path.normalized_path))
2870 posix_cwd = path.normalized_path;
2875 posix_cwd = path.normalized_path;
2880 res = cygheap->cwd.set (&path, posix_cwd);
2882 /* Note that we're accessing cwd.posix without a lock here. I didn't think
2883 it was worth locking just for strace. */
2884 syscall_printf ("%d = chdir() cygheap->cwd.posix '%s' native '%S'", res,
2885 cygheap->cwd.get_posix (), path.get_nt_native_path ());
2894 cygheap_fdget cfd (fd);
2896 res = chdir (cfd->get_name ());
2900 syscall_printf ("%d = fchdir (%d)", res, fd);
2904 /******************** Exported Path Routines *********************/
2906 /* Cover functions to the path conversion routines.
2907 These are exported to the world as cygwin_foo by cygwin.din. */
2909 #define return_with_errno(x) \
2919 cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to,
2924 if (efault.faulted (EFAULT))
2932 bool relative = !!(what & CCP_RELATIVE);
2933 what &= ~CCP_RELATIVE;
2937 case CCP_POSIX_TO_WIN_A:
2939 p.check ((const char *) from,
2940 PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2941 | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2943 return_with_errno (p.error);
2944 PUNICODE_STRING up = p.get_nt_native_path ();
2946 sys_wcstombs (buf, NT_MAX_PATH, up->Buffer, up->Length / sizeof (WCHAR));
2947 /* Convert native path to standard DOS path. */
2948 if (!strncmp (buf, "\\??\\", 4))
2951 if (buf[1] != ':') /* native UNC path */
2954 else if (*buf == '\\')
2956 /* Device name points to somewhere else in the NT namespace.
2957 Use GLOBALROOT prefix to convert to Win32 path. */
2958 char *p = stpcpy (buf, "\\\\.\\GLOBALROOT");
2959 sys_wcstombs (p, NT_MAX_PATH - (p - buf),
2960 up->Buffer, up->Length / sizeof (WCHAR));
2962 lsiz = strlen (buf) + 1;
2963 /* TODO: Incoming "." is a special case which leads to a trailing
2964 backslash ".\\" in the Win32 path. That's a result of the
2965 conversion in normalize_posix_path. This should not occur
2966 so the below code is just a band-aid. */
2967 if (relative && !strcmp ((const char *) from, ".")
2968 && !strcmp (buf, ".\\"))
2975 case CCP_POSIX_TO_WIN_W:
2976 p.check ((const char *) from,
2977 PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2978 | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2980 return_with_errno (p.error);
2981 /* Relative Windows paths are always restricted to MAX_PATH chars. */
2982 if (relative && !isabspath (p.get_win32 ())
2983 && sys_mbstowcs (NULL, 0, p.get_win32 ()) > MAX_PATH)
2985 /* Recreate as absolute path. */
2986 p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW
2987 | PC_NO_ACCESS_CHECK | PC_NOWARN);
2989 return_with_errno (p.error);
2991 lsiz = p.get_wide_win32_path_len () + 1;
2992 path = p.get_nt_native_path ()->Buffer;
2994 /* Convert native path to standard DOS path. */
2995 if (!wcsncmp (path, L"\\??\\", 4))
2999 /* Drop long path prefix for short pathnames. Unfortunately there's
3000 quite a bunch of Win32 functions, especially in user32.dll,
3001 apparently, which don't grok long path names at all, not even
3002 in the UNICODE API. */
3003 if ((path[5] == L':' && lsiz <= MAX_PATH + 4)
3004 || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6))
3008 if (path[1] != L':')
3010 *(path += 2) = '\\';
3015 else if (*path == L'\\')
3017 /* Device name points to somewhere else in the NT namespace.
3018 Use GLOBALROOT prefix to convert to Win32 path. */
3019 to = (void *) wcpcpy ((wchar_t *) to, L"\\\\.\\GLOBALROOT");
3020 lsiz += sizeof ("\\\\.\\GLOBALROOT") - 1;
3022 /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */
3023 if (relative && !strcmp ((const char *) from, ".")
3024 && !wcscmp (path, L".\\"))
3029 lsiz *= sizeof (WCHAR);
3031 case CCP_WIN_A_TO_POSIX:
3033 error = mount_table->conv_to_posix_path ((const char *) from, buf,
3036 return_with_errno (error);
3037 lsiz = strlen (buf) + 1;
3039 case CCP_WIN_W_TO_POSIX:
3041 error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf,
3044 return_with_errno (error);
3045 lsiz = strlen (buf) + 1;
3060 case CCP_POSIX_TO_WIN_A:
3061 case CCP_WIN_A_TO_POSIX:
3062 case CCP_WIN_W_TO_POSIX:
3063 stpcpy ((char *) to, buf);
3065 case CCP_POSIX_TO_WIN_W:
3066 wcpcpy ((PWCHAR) to, path);
3073 cygwin_create_path (cygwin_conv_path_t what, const void *from)
3076 ssize_t size = cygwin_conv_path (what, from, NULL, 0);
3079 else if (!(to = malloc (size)))
3081 if (cygwin_conv_path (what, from, to, size) == -1)
3091 cygwin_conv_to_win32_path (const char *path, char *win32_path)
3093 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, path, win32_path,
3098 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
3100 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path, win32_path,
3104 /* This is exported to the world as cygwin_foo by cygwin.din. */
3107 cygwin_conv_to_posix_path (const char *path, char *posix_path)
3109 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, path, posix_path,
3114 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
3116 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, path, posix_path,
3120 /* The realpath function is required by POSIX:2008. */
3123 realpath (const char *path, char *resolved)
3125 /* Make sure the right errno is returned if path is NULL. */
3132 /* Guard reading from a potentially invalid path and writing to a
3133 potentially invalid resolved. */
3136 if (efault.faulted (EFAULT))
3142 tpath = tp.c_get ();
3143 mount_table->cygdrive_posix_path (path, tpath, 0);
3146 tpath = (char *) path;
3148 path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
3151 /* POSIX 2008 requires malloc'ing if resolved is NULL, and states
3152 that using non-NULL resolved is asking for portability
3155 if (!real_path.error && real_path.exists ())
3159 resolved = (char *) malloc (strlen (real_path.normalized_path) + 1);
3163 strcpy (resolved, real_path.normalized_path);
3167 /* FIXME: on error, Linux puts the name of the path
3168 component which could not be resolved into RESOLVED, but POSIX
3169 does not require this. */
3172 set_errno (real_path.error ?: ENOENT);
3176 /* Linux provides this extension. Since the only portable use of
3177 realpath requires a NULL second argument, we might as well have a
3178 one-argument wrapper. */
3180 canonicalize_file_name (const char *path)
3182 return realpath (path, NULL);
3185 /* Return non-zero if path is a POSIX path list.
3186 This is exported to the world as cygwin_foo by cygwin.din.
3189 <sect1 id="add-func-cygwin-posix-path-list-p">
3190 <para>Rather than use a mode to say what the "proper" path list
3191 format is, we allow any, and give apps the tools they need to
3192 convert between the two. If a ';' is present in the path list it's
3193 a Win32 path list. Otherwise, if the first path begins with
3194 [letter]: (in which case it can be the only element since if it
3195 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
3196 it's a POSIX path list.</para>
3202 cygwin_posix_path_list_p (const char *path)
3204 int posix_p = !(strchr (path, ';') || isdrive (path));
3208 /* These are used for apps that need to convert env vars like PATH back and
3209 forth. The conversion is a two step process. First, an upper bound on the
3210 size of the buffer needed is computed. Then the conversion is done. This
3211 allows the caller to use alloca if it wants. */
3214 conv_path_list_buf_size (const char *path_list, bool to_posix)
3216 int i, num_elms, max_mount_path_len, size;
3219 path_conv pc(".", PC_POSIX);
3220 /* The theory is that an upper bound is
3221 current_size + (num_elms * max_mount_path_len) */
3222 /* FIXME: This method is questionable in the long run. */
3225 char delim = to_posix ? ';' : ':';
3226 for (p = path_list, num_elms = nrel = 0; p; num_elms++)
3230 p = strchr (++p, delim);
3233 /* 7: strlen ("//c") + slop, a conservative initial value */
3234 for (max_mount_path_len = sizeof ("/cygdrive/X"), i = 0;
3235 i < mount_table->nmounts; i++)
3237 int mount_len = (to_posix
3238 ? mount_table->mount[i].posix_pathlen
3239 : mount_table->mount[i].native_pathlen);
3240 if (max_mount_path_len < mount_len)
3241 max_mount_path_len = mount_len;
3245 size = strlen (path_list)
3246 + (num_elms * max_mount_path_len)
3247 + (nrel * strlen (to_posix ? pc.normalized_path : pc.get_win32 ()))
3255 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
3257 return conv_path_list_buf_size (path_list, true);
3261 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
3263 return conv_path_list_buf_size (path_list, false);
3267 env_PATH_to_posix (const void *win32, void *posix, size_t size)
3269 return_with_errno (conv_path_list ((const char *) win32, (char *) posix,
3274 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
3276 return_with_errno (conv_path_list (win32, posix, MAX_PATH, 1));
3280 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
3282 return_with_errno (conv_path_list (posix, win32, MAX_PATH, 0));
3286 cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
3289 /* FIXME: Path lists are (so far) always retaining relative paths. */
3290 what &= ~CCP_RELATIVE;
3293 case CCP_WIN_W_TO_POSIX:
3294 case CCP_POSIX_TO_WIN_W:
3296 api_fatal ("wide char path lists not yet supported");
3298 case CCP_WIN_A_TO_POSIX:
3299 case CCP_POSIX_TO_WIN_A:
3301 return conv_path_list_buf_size ((const char *) from,
3302 what == CCP_WIN_A_TO_POSIX);
3303 return_with_errno (conv_path_list ((const char *) from, (char *) to,
3304 size, what == CCP_WIN_A_TO_POSIX));
3313 /* cygwin_split_path: Split a path into directory and file name parts.
3314 Buffers DIR and FILE are assumed to be big enough.
3316 Examples (path -> `dir' / `file'):
3319 . -> `.' / `.' (FIXME: should this be `.' / `'?)
3320 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
3322 foo/bar -> `foo' / `bar'
3323 foo/bar/ -> `foo' / `bar'
3325 /foo/bar -> `/foo' / `bar'
3328 c:foo -> `c:/' / `foo'
3329 c:/foo -> `c:/' / `foo'
3333 cygwin_split_path (const char *path, char *dir, char *file)
3335 int dir_started_p = 0;
3337 /* Deal with drives.
3338 Remember that c:foo <==> c:/foo. */
3350 if (isdirsep (*path))
3355 /* Determine if there are trailing slashes and "delete" them if present.
3356 We pretend as if they don't exist. */
3357 const char *end = path + strlen (path);
3358 /* path + 1: keep leading slash. */
3359 while (end > path + 1 && isdirsep (end[-1]))
3362 /* At this point, END points to one beyond the last character
3363 (with trailing slashes "deleted"). */
3365 /* Point LAST_SLASH at the last slash (duh...). */
3366 const char *last_slash;
3367 for (last_slash = end - 1; last_slash >= path; --last_slash)
3368 if (isdirsep (*last_slash))
3371 if (last_slash == path)
3376 else if (last_slash > path)
3378 memcpy (dir, path, last_slash - path);
3379 dir[last_slash - path] = 0;
3384 ; /* nothing to do */
3390 memcpy (file, last_slash + 1, end - last_slash - 1);
3391 file[end - last_slash - 1] = 0;
3394 /*****************************************************************************/
3396 /* The find_fast_cwd_pointers function and parts of the
3397 cwdstuff::override_win32_cwd method are based on code using the
3400 Copyright 2010 John Carey. All rights reserved.
3402 Redistribution and use in source and binary forms, with or without
3403 modification, are permitted provided that the following conditions
3406 1. Redistributions of source code must retain the above
3407 copyright notice, this list of conditions and the following
3410 2. Redistributions in binary form must reproduce the above
3411 copyright notice, this list of conditions and the following
3412 disclaimer in the documentation and/or other materials provided
3413 with the distribution.
3415 THIS SOFTWARE IS PROVIDED BY JOHN CAREY ``AS IS'' AND ANY EXPRESS
3416 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3417 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3418 ARE DISCLAIMED. IN NO EVENT SHALL JOHN CAREY OR CONTRIBUTORS BE
3419 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3420 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
3421 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
3422 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3423 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3424 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3425 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3428 /* This structure is used to store the CWD starting with Windows Vista.
3429 The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only
3430 an afterthought now. The actual CWD storage is a FAST_CWD structure
3431 which is allocated on the process heap. The new method only requires
3432 minimal locking and it's much more multi-thread friendly. Presumably
3433 it minimizes contention when accessing the CWD. */
3434 typedef struct _FAST_CWD {
3435 LONG ReferenceCount; /* Only release when this is 0. */
3436 HANDLE DirectoryHandle;
3437 ULONG OldDismountCount; /* Reflects the system DismountCount
3438 at the time the CWD has been set. */
3439 UNICODE_STRING Path; /* Path's Buffer member always refers
3440 to the following Buffer array. */
3441 WCHAR Buffer[MAX_PATH];
3442 } FAST_CWD, *PFAST_CWD;
3444 /* fast_cwd_ptr is a pointer to the global pointer in ntdll.dll pointing
3445 to the FAST_CWD structure which constitutes the CWD.
3447 We put the pointer into the common shared DLL segment. This allows to
3448 restrict the call to find_fast_cwd_pointers() to once per Cygwin session
3449 per user session. This works, because ASLR randomizes the load address
3450 of DLLs only once at boot time. */
3451 static PFAST_CWD *fast_cwd_ptr
3452 __attribute__((section (".cygwin_dll_common"), shared)) = (PFAST_CWD *) -1;
3454 /* This is the mapping of the KUSER_SHARED_DATA structure into the 32 bit
3455 user address space. We need it here to access the current DismountCount. */
3456 static KUSER_SHARED_DATA &SharedUserData
3457 = *(volatile PKUSER_SHARED_DATA) 0x7ffe0000;
3459 #define peek32(x) (*(uint32_t *)(x))
3461 /* This function scans the code in ntdll.dll to find the address of the
3462 global variable used to access the CWD starting with Vista. While the
3463 pointer is global, it's not exported from the DLL, unfortunately.
3464 Therefore we have to use some knowledge to figure out the address.
3466 This code has been tested on Vista 32/64 bit, Server 2008 32/64 bit,
3467 Windows 7 32/64 bit, and Server 2008 R2 (which is only 64 bit anyway).
3468 There's some hope that this will still work for Windows 8... */
3470 find_fast_cwd_pointers ()
3472 /* Note that we have been called. */
3473 fast_cwd_ptr = NULL;
3474 /* Fetch entry points of relevant functions in ntdll.dll. */
3475 HMODULE ntdll = GetModuleHandle ("ntdll.dll");
3478 const uint8_t *get_dir = (const uint8_t *)
3479 GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
3480 const uint8_t *ent_crit = (const uint8_t *)
3481 GetProcAddress (ntdll, "RtlEnterCriticalSection");
3482 if (!get_dir || !ent_crit)
3484 /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
3485 const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 32);
3488 /* Fetch offset from instruction and compute address of called function.
3489 This function actually fetches the current FAST_CWD instance and
3490 performs some other actions, not important to us. */
3491 ptrdiff_t offset = (ptrdiff_t) peek32 (rcall + 1);
3492 const uint8_t *use_cwd = rcall + 5 + offset;
3493 /* Find first "push edi" instruction. */
3494 const uint8_t *pushedi = (const uint8_t *) memchr (use_cwd, 0x57, 32);
3495 /* ...which should be followed by "mov edi, crit-sect-addr" then
3497 const uint8_t *movedi = pushedi + 1;
3498 if (movedi[0] != 0xbf || movedi[5] != 0x57)
3500 /* Compare the address used for the critical section with the known
3501 PEB lock as stored in the PEB. */
3502 if ((PRTL_CRITICAL_SECTION) peek32 (movedi + 1)
3503 != NtCurrentTeb ()->Peb->FastPebLock)
3505 /* To check we are seeing the right code, we check our expectation that
3506 the next instruction is a relative call into RtlEnterCriticalSection. */
3508 if (rcall[0] != 0xe8)
3510 /* Check that this is a relative call to RtlEnterCriticalSection. */
3511 offset = (ptrdiff_t) peek32 (rcall + 1);
3512 if (rcall + 5 + offset != ent_crit)
3514 /* After locking the critical section, the code should read the global
3515 PFAST_CWD * pointer that is guarded by that critical section. */
3516 const uint8_t *movesi = rcall + 5;
3517 if (movesi[0] != 0x8b)
3519 fast_cwd_ptr = (PFAST_CWD *) peek32 (movesi + 2);
3523 copy_cwd_str (PUNICODE_STRING tgt, PUNICODE_STRING src)
3525 RtlCopyUnicodeString (tgt, src);
3526 if (tgt->Buffer[tgt->Length / sizeof (WCHAR) - 1] != L'\\')
3528 tgt->Buffer[tgt->Length / sizeof (WCHAR)] = L'\\';
3529 tgt->Length += sizeof (WCHAR);
3534 cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
3539 PEB &peb = *NtCurrentTeb ()->Peb;
3540 UNICODE_STRING &upp_cwd_str = peb.ProcessParameters->CurrentDirectoryName;
3541 HANDLE &upp_cwd_hdl = peb.ProcessParameters->CurrentDirectoryHandle;
3543 if (wincap.has_fast_cwd ())
3545 if (fast_cwd_ptr == (PFAST_CWD *) -1)
3547 find_fast_cwd_pointers ();
3549 system_printf ("WARNING: Couldn't compute FAST_CWD pointer. "
3550 "Please report this problem to\nthe public mailing "
3551 "list cygwin@cygwin.com");
3555 /* Default method starting with Vista. If we got a valid value for
3556 fast_cwd_ptr, we can simply replace the RtlSetCurrentDirectory_U
3557 function entirely, just as on pre-Vista. */
3558 PVOID heap = peb.ProcessHeap;
3559 /* First allocate a new FAST_CWD strcuture on the heap. */
3560 PFAST_CWD f_cwd = (PFAST_CWD)
3561 RtlAllocateHeap (heap, 0, sizeof (FAST_CWD));
3564 debug_printf ("RtlAllocateHeap failed");
3567 /* Fill in the values. */
3568 f_cwd->ReferenceCount = 1;
3569 f_cwd->DirectoryHandle = dir;
3570 f_cwd->OldDismountCount = old_dismount_count;
3571 RtlInitEmptyUnicodeString (&f_cwd->Path, f_cwd->Buffer,
3572 MAX_PATH * sizeof (WCHAR));
3573 copy_cwd_str (&f_cwd->Path, error ? &ro_u_pipedir : &win32);
3574 /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
3575 structure and writing the CWD to the user process parameter
3576 block. This is equivalent to calling RtlAcquirePebLock/
3577 RtlReleasePebLock, but without having to go through the FS
3579 RtlEnterCriticalSection (peb.FastPebLock);
3580 PFAST_CWD old_cwd = *fast_cwd_ptr;
3581 *fast_cwd_ptr = f_cwd;
3582 upp_cwd_str = f_cwd->Path;
3584 RtlLeaveCriticalSection (peb.FastPebLock);
3585 /* Decrement the reference count. If it's down to 0, free structure
3587 if (old_cwd && InterlockedDecrement (&old_cwd->ReferenceCount) == 0)
3589 /* In contrast to pre-Vista, the handle on init is always a fresh
3590 one and not the handle inherited from the parent process. So
3591 we always have to close it here. However, the handle could
3592 be NULL, if we cd'ed into a virtual dir. */
3593 if (old_cwd->DirectoryHandle)
3594 NtClose (old_cwd->DirectoryHandle);
3595 RtlFreeHeap (heap, 0, old_cwd);
3600 /* This is more a hack, and it's only used on Vista and later if we
3601 failed to find the fast_cwd_ptr value. What we do here is to call
3602 RtlSetCurrentDirectory_U and let it set up a new FAST_CWD
3603 structure. Afterwards, compute the address of that structure
3604 utilizing the fact that the buffer address in the user process
3605 parameter block is actually pointing to the buffer in that
3606 FAST_CWD structure. Then replace the directory handle in that
3607 structure with our own handle and close the original one.
3609 Note that the call to RtlSetCurrentDirectory_U also closes our
3610 old dir handle, so there won't be any handle left open.
3612 This method is prone to two race conditions:
3614 - Due to the way RtlSetCurrentDirectory_U opens the directory
3615 handle, the directory is locked against deletion or renaming
3616 between the RtlSetCurrentDirectory_U and the subsequent NtClose
3619 - When another thread calls SetCurrentDirectory at exactly the
3620 same time, a crash might occur, or worse, unrelated data could
3621 be overwritten or NtClose could be called on an unrelated handle.
3623 Therefore, use this *only* as a fallback. */
3626 status = RtlSetCurrentDirectory_U (error ? &ro_u_pipedir
3628 if (!NT_SUCCESS (status))
3630 debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %p",
3631 error ? &ro_u_pipedir : &win32, status);
3635 RtlEnterCriticalSection (peb.FastPebLock);
3636 PFAST_CWD f_cwd = (PFAST_CWD)
3637 ((PBYTE) upp_cwd_str.Buffer
3638 - __builtin_offsetof (struct _FAST_CWD, Buffer));
3640 f_cwd->DirectoryHandle = upp_cwd_hdl = dir;
3641 RtlLeaveCriticalSection (peb.FastPebLock);
3642 /* In contrast to pre-Vista, the handle on init is always a fresh one
3643 and not the handle inherited from the parent process. So we always
3644 have to close it here. */
3650 /* This method is used for all pre-Vista OSes. We simply set the values
3651 for the CWD in the user process parameter block entirely by ourselves
3652 under PEB lock condition. This is how RtlSetCurrentDirectory_U worked
3653 in these older OSes, so we're safe.
3655 Note that we can't just RtlEnterCriticalSection (peb.FastPebLock)
3656 on pre-Vista. RtlAcquirePebLock was way more complicated back then. */
3657 RtlAcquirePebLock ();
3659 copy_cwd_str (&upp_cwd_str, error ? &ro_u_pipedir : &win32);
3662 RtlReleasePebLock ();
3663 /* Only on init, the handle is potentially a native handle. However,
3664 if it's identical to dir, it's the inherited handle from a Cygwin
3665 parent process and must not be closed. */
3671 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
3675 cwd_lock.init ("cwd_lock");
3677 /* Cygwin processes inherit the cwd from their parent. If the win32 path
3678 buffer is not NULL, the cwd struct is already set up, and we only
3679 have to override the Win32 CWD with ours. */
3681 override_win32_cwd (true, SharedUserData.DismountCount);
3683 /* Initially re-open the cwd to allow POSIX semantics. */
3687 /* Chdir and fill out the elements of a cwdstuff struct. */
3689 cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
3692 UNICODE_STRING upath;
3693 PEB &peb = *NtCurrentTeb ()->Peb;
3694 bool virtual_path = false;
3695 bool unc_path = false;
3696 bool inaccessible_path = false;
3698 /* Here are the problems with using SetCurrentDirectory. Just skip this
3699 comment if you don't like whining.
3701 - SetCurrentDirectory only supports paths of up to MAX_PATH - 1 chars,
3702 including a trailing backslash. That's an absolute restriction, even
3705 - SetCurrentDirectory fails for directories with strict permissions even
3706 for processes with the SE_BACKUP_NAME privilege enabled. The reason
3707 is apparently that SetCurrentDirectory calls NtOpenFile without the
3708 FILE_OPEN_FOR_BACKUP_INTENT flag set.
3710 - SetCurrentDirectory does not support case-sensitivity.
3712 - Unlinking a cwd fails because SetCurrentDirectory seems to open
3713 directories so that deleting the directory is disallowed.
3715 - SetCurrentDirectory can naturally not work on virtual Cygwin paths
3716 like /proc or /cygdrive.
3718 Unfortunately, even though we have access to the Win32 process parameter
3719 block, we can't just replace the directory handle. Starting with Vista,
3720 the handle is used elsewhere, and just replacing the handle in the process
3721 parameter block shows quite surprising results.
3722 FIXME: If we ever find a *safe* way to replace the directory handle in
3723 the process parameter block, we're back in business.
3725 Nevertheless, doing entirely without SetCurrentDirectory is not really
3726 feasible, because it breaks too many mixed applications using the Win32
3729 Therefore we handle the CWD all by ourselves and just keep the Win32
3730 CWD in sync. However, to avoid surprising behaviour in the Win32 API
3731 when we are in a CWD which is inaccessible as Win32 CWD, we set the
3732 Win32 CWD to a "weird" directory in which all relative filesystem-related
3735 cwd_lock.acquire ();
3739 upath = *nat_cwd->get_nt_native_path ();
3740 if (nat_cwd->isspecial ())
3741 virtual_path = true;
3744 /* Memorize old DismountCount before opening the dir. This value is
3745 stored in the FAST_CWD structure on Vista and later. It would be
3746 simpler to fetch the old DismountCount in override_win32_cwd, but
3747 Windows also fetches it before opening the directory handle. It's
3748 not quite clear if that's really required, but since we don't know
3749 the side effects of this action, we better follow Windows' lead. */
3750 ULONG old_dismount_count = SharedUserData.DismountCount;
3751 /* Open a directory handle with FILE_OPEN_FOR_BACKUP_INTENT and with all
3752 sharing flags set. The handle is right now used in exceptions.cc only,
3753 but that might change in future. */
3758 OBJECT_ATTRIBUTES attr;
3762 /* On init, just reopen Win32 CWD with desired access flags.
3763 We can access the PEB without lock, because no other thread
3764 can change the CWD. */
3765 RtlInitUnicodeString (&upath, L"");
3766 InitializeObjectAttributes (&attr, &upath,
3767 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
3768 peb.ProcessParameters->CurrentDirectoryHandle, NULL);
3771 InitializeObjectAttributes (&attr, &upath,
3772 nat_cwd->objcaseinsensitive () | OBJ_INHERIT,
3774 /* First try without FILE_OPEN_FOR_BACKUP_INTENT, to find out if the
3775 directory is valid for Win32 apps. And, no, we can't just call
3776 SetCurrentDirectory here, since that would potentially break
3777 case-sensitivity. */
3778 status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
3779 FILE_SHARE_VALID_FLAGS,
3781 | FILE_SYNCHRONOUS_IO_NONALERT);
3782 if (status == STATUS_ACCESS_DENIED)
3784 status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
3785 FILE_SHARE_VALID_FLAGS,
3787 | FILE_SYNCHRONOUS_IO_NONALERT
3788 | FILE_OPEN_FOR_BACKUP_INTENT);
3789 inaccessible_path = true;
3791 if (!NT_SUCCESS (status))
3793 cwd_lock.release ();
3794 __seterrno_from_nt_status (status);
3798 /* Set new handle. Note that we simply overwrite the old handle here
3799 without closing it. The handle is also used as Win32 CWD handle in
3800 the user parameter block, and it will be closed in override_win32_cwd,
3806 /* On init, just fetch the Win32 dir from the PEB. We can access
3807 the PEB without lock, because no other thread can change the CWD
3809 PUNICODE_STRING pdir = &peb.ProcessParameters->CurrentDirectoryName;
3810 RtlInitEmptyUnicodeString (&win32,
3811 (PWCHAR) crealloc_abort (win32.Buffer,
3814 pdir->Length + sizeof (WCHAR));
3815 RtlCopyUnicodeString (&win32, pdir);
3817 PWSTR eoBuffer = win32.Buffer + (win32.Length / sizeof (WCHAR));
3818 /* Remove trailing slash if one exists. */
3819 if ((eoBuffer - win32.Buffer) > 3 && eoBuffer[-1] == L'\\')
3820 win32.Length -= sizeof (WCHAR);
3821 if (eoBuffer[0] == L'\\')
3828 if (virtual_path) /* don't mangle virtual path. */
3832 /* Compute length on Win32 path. */
3833 size_t len = upath.Length / sizeof (WCHAR) - 4;
3834 if (RtlEqualUnicodePathPrefix (&upath, &ro_u_uncp, TRUE))
3839 /* Convert to a Win32 path. */
3840 upath.Buffer += upath.Length / sizeof (WCHAR) - len;
3841 upath.Length = len * sizeof (WCHAR);
3843 PWSTR eoBuffer = upath.Buffer + (upath.Length / sizeof (WCHAR));
3844 /* Remove trailing slash if one exists. */
3845 if ((eoBuffer - upath.Buffer) > 3 && eoBuffer[-1] == L'\\')
3846 upath.Length -= sizeof (WCHAR);
3848 RtlInitEmptyUnicodeString (&win32,
3849 (PWCHAR) crealloc_abort (win32.Buffer,
3852 upath.Length + sizeof (WCHAR));
3853 RtlCopyUnicodeString (&win32, &upath);
3855 win32.Buffer[0] = L'\\';
3857 /* Make sure it's NUL-terminated. */
3858 win32.Buffer[win32.Length / sizeof (WCHAR)] = L'\0';
3860 /* Set drive_length, used in path conversion, and error code, used in
3861 spawn_guts to decide whether a native Win32 app can be started or not. */
3873 PWCHAR ptr = wcschr (win32.Buffer + 2, L'\\');
3875 ptr = wcschr (ptr + 1, L'\\');
3877 drive_length = ptr - win32.Buffer;
3879 drive_length = win32.Length / sizeof (WCHAR);
3881 if (inaccessible_path)
3883 else if (win32.Length > (MAX_PATH - 2) * sizeof (WCHAR))
3884 error = ENAMETOOLONG;
3888 /* Keep the Win32 CWD in sync. Don't check for error, other than for
3889 strace output. Try to keep overhead low. */
3890 override_win32_cwd (!nat_cwd, old_dismount_count);
3892 /* Eventually, create POSIX path if it's not set on entry. */
3896 posix_cwd = (const char *) tp.c_get ();
3897 mount_table->conv_to_posix_path (win32.Buffer, (char *) posix_cwd, 0);
3899 posix = (char *) crealloc_abort (posix, strlen (posix_cwd) + 1);
3900 stpcpy (posix, posix_cwd);
3902 cwd_lock.release ();
3907 cwdstuff::get_error_desc () const
3909 switch (cygheap->cwd.get_error ())
3912 return "has restricted permissions which render it\n"
3913 "inaccessible as Win32 working directory";
3915 return "is a virtual Cygwin directory which does\n"
3916 "not exist for a native Windows application";
3918 return "has a path longer than allowed for a\n"
3919 "Win32 working directory";
3923 /* That shouldn't occur, unless we defined a new error code
3924 in cwdstuff::set. */
3925 return "is not accessible for some unknown reason";
3928 /* Store incoming wchar_t path as current posix cwd. This is called from
3929 setlocale so that the cwd is always stored in the right charset. */
3931 cwdstuff::reset_posix (wchar_t *w_cwd)
3933 size_t len = sys_wcstombs (NULL, (size_t) -1, w_cwd);
3934 posix = (char *) crealloc_abort (posix, len + 1);
3935 sys_wcstombs (posix, len + 1, w_cwd);
3939 cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
3946 else if (buf == NULL)
3947 ulen = (unsigned) -1;
3954 cwd_lock.acquire ();
3959 tocopy = tp.c_get ();
3960 sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer,
3961 win32.Length / sizeof (WCHAR));
3966 debug_printf ("posix %s", posix);
3967 if (strlen (tocopy) >= ulen)
3975 buf = (char *) malloc (strlen (tocopy) + 1);
3976 strcpy (buf, tocopy);
3977 if (!buf[0]) /* Should only happen when chroot */
3981 cwd_lock.release ();
3984 syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
3985 buf, buf, ulen, need_posix, with_chroot, errno);
3990 int etc::curr_ix = 0;
3991 /* Note that the first elements of the below arrays are unused */
3992 bool etc::change_possible[MAX_ETC_FILES + 1];
3993 OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1];
3994 LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1];
3997 etc::init (int n, POBJECT_ATTRIBUTES attr)
4001 else if (++curr_ix <= MAX_ETC_FILES)
4004 api_fatal ("internal error");
4007 change_possible[n] = false;
4008 test_file_change (n);
4009 paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix);
4014 etc::test_file_change (int n)
4017 FILE_NETWORK_OPEN_INFORMATION fnoi;
4020 status = NtQueryFullAttributesFile (&fn[n], &fnoi);
4021 if (!NT_SUCCESS (status))
4024 memset (last_modified + n, 0, sizeof (last_modified[n]));
4025 debug_printf ("NtQueryFullAttributesFile (%S) failed, %p",
4026 fn[n].ObjectName, status);
4030 res = CompareFileTime ((FILETIME *) &fnoi.LastWriteTime,
4031 (FILETIME *) last_modified + n) > 0;
4032 last_modified[n].QuadPart = fnoi.LastWriteTime.QuadPart;
4035 paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4040 etc::dir_changed (int n)
4042 if (!change_possible[n])
4044 static HANDLE changed_h NO_COPY;
4050 OBJECT_ATTRIBUTES attr;
4052 path_conv dir ("/etc");
4053 status = NtOpenFile (&changed_h, SYNCHRONIZE | FILE_LIST_DIRECTORY,
4054 dir.get_object_attr (attr, sec_none_nih), &io,
4055 FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE);
4056 if (!NT_SUCCESS (status))
4059 system_printf ("NtOpenFile (%S) failed, %p",
4060 dir.get_nt_native_path (), status);
4062 changed_h = INVALID_HANDLE_VALUE;
4066 status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4068 FILE_NOTIFY_CHANGE_LAST_WRITE
4069 | FILE_NOTIFY_CHANGE_FILE_NAME,
4071 if (!NT_SUCCESS (status))
4074 system_printf ("NtNotifyChangeDirectoryFile (1) failed, %p",
4077 NtClose (changed_h);
4078 changed_h = INVALID_HANDLE_VALUE;
4081 memset (change_possible, true, sizeof (change_possible));
4084 if (changed_h == INVALID_HANDLE_VALUE)
4085 change_possible[n] = true;
4086 else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
4088 status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4090 FILE_NOTIFY_CHANGE_LAST_WRITE
4091 | FILE_NOTIFY_CHANGE_FILE_NAME,
4093 if (!NT_SUCCESS (status))
4096 system_printf ("NtNotifyChangeDirectoryFile (2) failed, %p",
4099 NtClose (changed_h);
4100 changed_h = INVALID_HANDLE_VALUE;
4102 memset (change_possible, true, sizeof change_possible);
4106 paranoid_printf ("fn[%d] %S change_possible %d",
4107 n, fn[n].ObjectName, change_possible[n]);
4108 return change_possible[n];
4112 etc::file_changed (int n)
4115 if (dir_changed (n) && test_file_change (n))
4117 change_possible[n] = false; /* Change is no longer possible */
4118 paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4122 /* No need to be reentrant or thread-safe according to SUSv3.
4123 / and \\ are treated equally. Leading drive specifiers are
4124 kept intact as far as it makes sense. Everything else is
4125 POSIX compatible. */
4127 basename (char *path)
4130 char *c, *d, *bs = path;
4132 if (!path || !*path)
4133 return strcpy (buf, ".");
4134 if (isalpha (path[0]) && path[1] == ':')
4136 else if (strspn (path, "/\\") > 1)
4138 c = strrchr (bs, '/');
4139 if ((d = strrchr (c ?: bs, '\\')) > c)
4143 /* Trailing (back)slashes are eliminated. */
4144 while (c && c > bs && c[1] == '\0')
4147 c = strrchr (bs, '/');
4148 if ((d = strrchr (c ?: bs, '\\')) > c)
4151 if (c && (c > bs || c[1]))
4156 stpncpy (buf, path, bs - path);
4157 stpcpy (buf + (bs - path), ".");
4163 /* No need to be reentrant or thread-safe according to SUSv3.
4164 / and \\ are treated equally. Leading drive specifiers and
4165 leading double (back)slashes are kept intact as far as it
4166 makes sense. Everything else is POSIX compatible. */
4168 dirname (char *path)
4171 char *c, *d, *bs = path;
4173 if (!path || !*path)
4174 return strcpy (buf, ".");
4175 if (isalpha (path[0]) && path[1] == ':')
4177 else if (strspn (path, "/\\") > 1)
4179 c = strrchr (bs, '/');
4180 if ((d = strrchr (c ?: bs, '\\')) > c)
4184 /* Trailing (back)slashes are eliminated. */
4185 while (c && c > bs && c[1] == '\0')
4188 c = strrchr (bs, '/');
4189 if ((d = strrchr (c ?: bs, '\\')) > c)
4196 /* More trailing (back)slashes are eliminated. */
4197 while (c > bs && (*c == '/' || *c == '\\'))
4205 stpncpy (buf, path, bs - path);
4206 stpcpy (buf + (bs - path), ".");