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 *s = strccpy (srcbuf, &src, src_delim);
1355 size_t len = s - srcbuf;
1356 if (len >= NT_MAX_PATH)
1364 err = cygwin_conv_path (conv_fn, srcbuf, d, size - (d - dst));
1369 err = cygwin_conv_path (conv_fn, ".", d, size - (d - dst));
1373 if (to_posix == ENV_CVT)
1379 d = strchr (d, '\0');
1393 /********************** Symbolic Link Support **************************/
1395 /* Create a symlink from FROMPATH to TOPATH. */
1397 /* If TRUE create symlinks as Windows shortcuts, if false create symlinks
1398 as normal files with magic number and system bit set. */
1399 bool allow_winsymlinks = false;
1402 symlink (const char *oldpath, const char *newpath)
1404 return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
1408 symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
1413 path_conv win32_newpath, win32_oldpath;
1415 SECURITY_ATTRIBUTES sa = sec_none_nih;
1416 OBJECT_ATTRIBUTES attr;
1422 bool mk_winsym = use_winsym;
1423 bool has_trailing_dirsep = false;
1425 /* POSIX says that empty 'newpath' is invalid input while empty
1426 'oldpath' is valid -- it's symlink resolver job to verify if
1427 symlink contents point to existing filesystem object */
1429 if (efault.faulted (EFAULT))
1431 if (!*oldpath || !*newpath)
1437 if (strlen (oldpath) > SYMLINK_MAX)
1439 set_errno (ENAMETOOLONG);
1443 /* Trailing dirsep is a no-no. */
1444 len = strlen (newpath);
1445 has_trailing_dirsep = isdirsep (newpath[len - 1]);
1446 if (has_trailing_dirsep)
1448 newpath = strdup (newpath);
1449 ((char *) newpath)[len - 1] = '\0';
1452 check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0);
1453 /* We need the normalized full path below. */
1454 win32_newpath.check (newpath, check_opt, stat_suffixes);
1455 /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O
1456 attribute. Therefore we create symlinks on MVFS always as shortcuts. */
1457 mk_winsym |= win32_newpath.fs_is_mvfs ();
1459 if (mk_winsym && !win32_newpath.exists ()
1460 && (isdevice || !win32_newpath.fs_is_nfs ()))
1462 char *newplnk = tp.c_get ();
1463 stpcpy (stpcpy (newplnk, newpath), ".lnk");
1464 win32_newpath.check (newplnk, check_opt);
1467 if (win32_newpath.error)
1469 set_errno (win32_newpath.error);
1473 syscall_printf ("symlink (%s, %S)", oldpath,
1474 win32_newpath.get_nt_native_path ());
1476 if ((!isdevice && win32_newpath.exists ())
1477 || win32_newpath.is_auto_device ())
1482 if (has_trailing_dirsep && !win32_newpath.exists ())
1488 if (!isdevice && win32_newpath.fs_is_nfs ())
1490 /* On NFS, create symlinks by calling NtCreateFile with an EA of type
1491 NfsSymlinkTargetName containing ... the symlink target name. */
1492 PFILE_FULL_EA_INFORMATION pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1493 pffei->NextEntryOffset = 0;
1495 pffei->EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1496 char *EaValue = stpcpy (pffei->EaName, NFS_SYML_TARGET) + 1;
1497 pffei->EaValueLength = sizeof (WCHAR) *
1498 (sys_mbstowcs ((PWCHAR) EaValue, NT_MAX_PATH, oldpath) - 1);
1499 status = NtCreateFile (&fh, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE,
1500 win32_newpath.get_object_attr (attr, sa),
1501 &io, NULL, FILE_ATTRIBUTE_SYSTEM,
1502 FILE_SHARE_VALID_FLAGS, FILE_CREATE,
1503 FILE_SYNCHRONOUS_IO_NONALERT
1504 | FILE_OPEN_FOR_BACKUP_INTENT,
1505 pffei, NT_MAX_PATH * sizeof (WCHAR));
1506 if (!NT_SUCCESS (status))
1508 __seterrno_from_nt_status (status);
1518 ITEMIDLIST *pidl = NULL;
1519 size_t full_len = 0;
1520 unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
1521 char desc[MAX_PATH + 1], *relpath;
1525 /* First create an IDLIST to learn how big our shortcut is
1529 /* The symlink target is relative to the directory in which
1530 the symlink gets created, not relative to the cwd. Therefore
1531 we have to mangle the path quite a bit before calling path_conv. */
1532 if (isabspath (oldpath))
1533 win32_oldpath.check (oldpath,
1538 len = strrchr (win32_newpath.normalized_path, '/')
1539 - win32_newpath.normalized_path + 1;
1540 char *absoldpath = tp.t_get ();
1541 stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
1543 win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1545 if (SUCCEEDED (SHGetDesktopFolder (&psl)))
1547 WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
1548 win32_oldpath.get_wide_win32_path (wc_path);
1549 /* Amazing but true: Even though the ParseDisplayName method
1550 takes a wide char path name, it does not understand the
1551 Win32 prefix for long pathnames! So we have to tack off
1552 the prefix and convert the path to the "normal" syntax
1553 for ParseDisplayName. */
1554 WCHAR *wc = wc_path + 4;
1555 if (wc[1] != L':') /* native UNC path */
1558 if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
1563 for (p = pidl; p->mkid.cb > 0;
1564 p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
1566 pidl_len = (char *) p - (char *) pidl + 2;
1571 /* Compute size of shortcut file. */
1572 full_len = sizeof (win_shortcut_hdr);
1574 full_len += sizeof (unsigned short) + pidl_len;
1575 oldpath_len = strlen (oldpath);
1576 /* Unfortunately the length of the description is restricted to a
1577 length of MAX_PATH up to NT4, and to a length of 2000 bytes
1578 since W2K. We don't want to add considerations for the different
1579 lengths and even 2000 bytes is not enough for long path names.
1580 So what we do here is to set the description to the POSIX path
1581 only if the path is not longer than MAX_PATH characters. We
1582 append the full path name after the regular shortcut data
1583 (see below), which works fine with Windows Explorer as well
1584 as older Cygwin versions (as long as the whole file isn't bigger
1585 than 8K). The description field is only used for backward
1586 compatibility to older Cygwin versions and those versions are
1587 not capable of handling long path names anyway. */
1588 desc_len = stpcpy (desc, oldpath_len > MAX_PATH
1589 ? "[path too long]" : oldpath) - desc;
1590 full_len += sizeof (unsigned short) + desc_len;
1591 /* Devices get the oldpath string unchanged as relative path. */
1594 relpath_len = oldpath_len;
1595 stpcpy (relpath = tp.c_get (), oldpath);
1599 relpath_len = strlen (win32_oldpath.get_win32 ());
1600 stpcpy (relpath = tp.c_get (), win32_oldpath.get_win32 ());
1602 full_len += sizeof (unsigned short) + relpath_len;
1603 full_len += sizeof (unsigned short) + oldpath_len;
1604 /* 1 byte more for trailing 0 written by stpcpy. */
1605 if (full_len < NT_MAX_PATH * sizeof (WCHAR))
1606 buf = (char *) tp.w_get ();
1608 buf = (char *) alloca (full_len + 1);
1610 /* Create shortcut header */
1611 win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf;
1612 memset (shortcut_header, 0, sizeof *shortcut_header);
1613 shortcut_header->size = sizeof *shortcut_header;
1614 shortcut_header->magic = GUID_shortcut;
1615 shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH);
1617 shortcut_header->flags |= WSH_FLAG_IDLIST;
1618 shortcut_header->run = SW_NORMAL;
1619 cp = buf + sizeof (win_shortcut_hdr);
1624 *(unsigned short *)cp = pidl_len;
1625 memcpy (cp += 2, pidl, pidl_len);
1627 CoTaskMemFree (pidl);
1630 /* Create description */
1631 *(unsigned short *)cp = desc_len;
1632 cp = stpcpy (cp += 2, desc);
1634 /* Create relpath */
1635 *(unsigned short *)cp = relpath_len;
1636 cp = stpcpy (cp += 2, relpath);
1638 /* Append the POSIX path after the regular shortcut data for
1639 the long path support. */
1640 unsigned short *plen = (unsigned short *) cp;
1642 *(PWCHAR) cp = 0xfeff; /* BOM */
1644 *plen = sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1649 /* Default technique creating a symlink. */
1650 buf = (char *) tp.w_get ();
1651 cp = stpcpy (buf, SYMLINK_COOKIE);
1652 *(PWCHAR) cp = 0xfeff; /* BOM */
1654 /* Note that the terminating nul is written. */
1655 cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1658 if (isdevice && win32_newpath.exists ())
1660 status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
1661 win32_newpath.get_object_attr (attr, sa),
1662 &io, 0, FILE_OPEN_FOR_BACKUP_INTENT);
1663 if (!NT_SUCCESS (status))
1665 __seterrno_from_nt_status (status);
1668 status = NtSetAttributesFile (fh, FILE_ATTRIBUTE_NORMAL);
1670 if (!NT_SUCCESS (status))
1672 __seterrno_from_nt_status (status);
1676 status = NtCreateFile (&fh, DELETE | FILE_GENERIC_WRITE,
1677 win32_newpath.get_object_attr (attr, sa),
1678 &io, NULL, FILE_ATTRIBUTE_NORMAL,
1679 FILE_SHARE_VALID_FLAGS,
1680 isdevice ? FILE_OVERWRITE_IF : FILE_CREATE,
1681 FILE_SYNCHRONOUS_IO_NONALERT
1682 | FILE_NON_DIRECTORY_FILE
1683 | FILE_OPEN_FOR_BACKUP_INTENT,
1685 if (!NT_SUCCESS (status))
1687 __seterrno_from_nt_status (status);
1690 if (win32_newpath.has_acls ())
1691 set_file_attribute (fh, win32_newpath, ILLEGAL_UID, ILLEGAL_GID,
1692 (io.Information == FILE_CREATED ? S_JUSTCREATED : 0)
1693 | S_IFLNK | STD_RBITS | STD_WBITS);
1694 status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL);
1695 if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf))
1697 status = NtSetAttributesFile (fh, mk_winsym ? FILE_ATTRIBUTE_READONLY
1698 : FILE_ATTRIBUTE_SYSTEM);
1699 if (!NT_SUCCESS (status))
1700 debug_printf ("Setting attributes failed, status = %p", status);
1705 __seterrno_from_nt_status (status);
1706 FILE_DISPOSITION_INFORMATION fdi = { TRUE };
1707 status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
1708 FileDispositionInformation);
1709 if (!NT_SUCCESS (status))
1710 debug_printf ("Setting delete dispostion failed, status = %p", status);
1715 syscall_printf ("%d = symlink_worker (%s, %s, %d, %d)", res, oldpath,
1716 newpath, mk_winsym, isdevice);
1717 if (has_trailing_dirsep)
1718 free ((void *) newpath);
1723 cmp_shortcut_header (win_shortcut_hdr *file_header)
1725 /* A Cygwin or U/Win shortcut only contains a description and a relpath.
1726 Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
1727 always set to SW_NORMAL. */
1728 return file_header->size == sizeof (win_shortcut_hdr)
1729 && !memcmp (&file_header->magic, &GUID_shortcut, sizeof GUID_shortcut)
1730 && (file_header->flags & ~WSH_FLAG_IDLIST)
1731 == (WSH_FLAG_DESC | WSH_FLAG_RELPATH)
1732 && file_header->run == SW_NORMAL;
1736 symlink_info::check_shortcut (HANDLE h)
1739 win_shortcut_hdr *file_header;
1745 FILE_STANDARD_INFORMATION fsi;
1746 LARGE_INTEGER off = { QuadPart:0LL };
1748 status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
1749 FileStandardInformation);
1750 if (!NT_SUCCESS (status))
1755 if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
1756 || fsi.EndOfFile.QuadPart > 4 * 65536)
1758 if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
1759 buf = (char *) tp.w_get ();
1761 buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
1762 status = NtReadFile (h, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
1764 if (!NT_SUCCESS (status))
1766 if (status != STATUS_END_OF_FILE)
1770 file_header = (win_shortcut_hdr *) buf;
1771 if (io.Information != fsi.EndOfFile.LowPart
1772 || !cmp_shortcut_header (file_header))
1774 cp = buf + sizeof (win_shortcut_hdr);
1775 if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
1776 cp += *(unsigned short *) cp + 2;
1777 if (!(len = *(unsigned short *) cp))
1780 /* Check if this is a device file - these start with the sequence :\\ */
1781 if (strncmp (cp, ":\\", 2) == 0)
1782 res = strlen (strcpy (contents, cp)); /* Don't mess with device files */
1785 /* Has appended full path? If so, use it instead of description. */
1786 unsigned short relpath_len = *(unsigned short *) (cp + len);
1787 if (cp + len + 2 + relpath_len < buf + fsi.EndOfFile.LowPart)
1789 cp += len + 2 + relpath_len;
1790 len = *(unsigned short *) cp;
1793 if (*(PWCHAR) cp == 0xfeff) /* BOM */
1795 char *tmpbuf = tp.c_get ();
1796 if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2))
1799 res = posixify (tmpbuf);
1801 else if (len > SYMLINK_MAX)
1806 res = posixify (cp);
1809 if (res) /* It's a symlink. */
1810 pflags |= PATH_SYMLINK | PATH_LNK;
1815 symlink_info::check_sysfile (HANDLE h)
1818 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
1819 char *srcbuf = tp.c_get ();
1823 bool interix_symlink = false;
1824 LARGE_INTEGER off = { QuadPart:0LL };
1826 status = NtReadFile (h, NULL, NULL, NULL, &io, cookie_buf,
1827 sizeof (cookie_buf), &off, NULL);
1828 if (!NT_SUCCESS (status))
1830 debug_printf ("ReadFile1 failed %p", status);
1831 if (status != STATUS_END_OF_FILE)
1835 off.QuadPart = io.Information;
1836 if (io.Information == sizeof (cookie_buf)
1837 && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
1839 /* It's a symlink. */
1840 pflags |= PATH_SYMLINK;
1842 else if (io.Information == sizeof (cookie_buf)
1843 && memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
1844 pflags |= PATH_SOCKET;
1845 else if (io.Information >= sizeof (INTERIX_SYMLINK_COOKIE)
1846 && memcmp (cookie_buf, INTERIX_SYMLINK_COOKIE,
1847 sizeof (INTERIX_SYMLINK_COOKIE) - 1) == 0)
1849 /* It's an Interix symlink. */
1850 pflags |= PATH_SYMLINK;
1851 interix_symlink = true;
1852 /* Interix symlink cookies are shorter than Cygwin symlink cookies, so
1853 in case of an Interix symlink cooky we have read too far into the
1854 file. Set file pointer back to the position right after the cookie. */
1855 off.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1;
1857 if (pflags & PATH_SYMLINK)
1859 status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
1860 NT_MAX_PATH, &off, NULL);
1861 if (!NT_SUCCESS (status))
1863 debug_printf ("ReadFile2 failed");
1864 if (status != STATUS_END_OF_FILE)
1867 else if (*(PWCHAR) srcbuf == 0xfeff /* BOM */
1870 /* Add trailing 0 to Interix symlink target. Skip BOM in Cygwin
1872 if (interix_symlink)
1873 ((PWCHAR) srcbuf)[io.Information / sizeof (WCHAR)] = L'\0';
1876 char *tmpbuf = tp.c_get ();
1877 if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) srcbuf)
1879 debug_printf ("symlink string too long");
1881 res = posixify (tmpbuf);
1883 else if (io.Information > SYMLINK_MAX + 1)
1884 debug_printf ("symlink string too long");
1886 res = posixify (srcbuf);
1892 symlink_info::check_reparse_point (HANDLE h)
1897 PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) tp.c_get ();
1898 UNICODE_STRING subst;
1899 char srcbuf[SYMLINK_MAX + 7];
1901 status = NtFsControlFile (h, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT,
1902 NULL, 0, (LPVOID) rp,
1903 MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1904 if (!NT_SUCCESS (status))
1906 debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %p",
1911 if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
1912 RtlInitCountedUnicodeString (&subst,
1913 (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
1914 + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset),
1915 rp->SymbolicLinkReparseBuffer.SubstituteNameLength);
1916 else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
1918 RtlInitCountedUnicodeString (&subst,
1919 (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
1920 + rp->MountPointReparseBuffer.SubstituteNameOffset),
1921 rp->MountPointReparseBuffer.SubstituteNameLength);
1922 if (RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE))
1924 /* Volume mount point. Not treated as symlink. The return
1925 value of -1 is a hint for the caller to treat this as a
1926 volume mount point. */
1932 /* Maybe it's a reparse point, but it's certainly not one we
1933 recognize. Drop the REPARSE file attribute so we don't even
1934 try to use the flag for some special handling. It's just some
1935 arbitrary file or directory for us. */
1936 fileattr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1939 sys_wcstombs (srcbuf, SYMLINK_MAX + 7, subst.Buffer,
1940 subst.Length / sizeof (WCHAR));
1941 pflags |= PATH_SYMLINK | PATH_REP;
1942 /* A symlink is never a directory. */
1943 fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
1944 return posixify (srcbuf);
1948 symlink_info::check_nfs_symlink (HANDLE h)
1954 FILE_GET_EA_INFORMATION fgei;
1955 char buf[sizeof (NFS_SYML_TARGET)];
1957 PFILE_FULL_EA_INFORMATION pffei;
1960 /* To find out if the file is a symlink and to get the symlink target,
1961 try to fetch the NfsSymlinkTargetName EA. */
1962 fgei_buf.fgei.NextEntryOffset = 0;
1963 fgei_buf.fgei.EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1964 stpcpy (fgei_buf.fgei.EaName, NFS_SYML_TARGET);
1965 pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1966 status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE,
1967 &fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
1968 if (NT_SUCCESS (status) && pffei->EaValueLength > 0)
1970 PWCHAR spath = (PWCHAR)
1971 (pffei->EaName + pffei->EaNameLength + 1);
1972 res = sys_wcstombs (contents, SYMLINK_MAX + 1,
1973 spath, pffei->EaValueLength) - 1;
1974 pflags |= PATH_SYMLINK;
1980 symlink_info::posixify (char *srcbuf)
1982 /* The definition for a path in a native symlink is a bit weird. The Flags
1983 value seem to contain 0 for absolute paths (stored as NT native path)
1984 and 1 for relative paths. Relative paths are paths not starting with a
1985 drive letter. These are not converted to NT native, but stored as
1986 given. A path starting with a single backslash is relative to the
1987 current drive thus a "relative" value (Flags == 1).
1988 Funny enough it's possible to store paths with slashes instead of
1989 backslashes, but they are evaluated incorrectly by subsequent Windows
1990 calls like CreateFile (ERROR_INVALID_NAME). So, what we do here is to
1991 take paths starting with slashes at face value, evaluating them as
1992 Cygwin specific POSIX paths.
1993 A path starting with two slashes(!) or backslashes is converted into an
1994 NT UNC path. Unfortunately, in contrast to POSIX rules, paths starting
1995 with three or more (back)slashes are also converted into UNC paths,
1996 just incorrectly sticking to one redundant leading backslashe. We go
1997 along with this behaviour to avoid scenarios in which native tools access
1998 other files than Cygwin.
1999 The above rules are used exactly the same way on Cygwin specific symlinks
2000 (sysfiles and shortcuts) to eliminate non-POSIX paths in the output. */
2002 /* Eliminate native NT prefixes. */
2003 if (srcbuf[0] == '\\' && !strncmp (srcbuf + 1, "??\\", 3))
2006 if (srcbuf[1] != ':') /* native UNC path */
2007 *(srcbuf += 2) = '\\';
2009 if (isdrive (srcbuf))
2010 mount_table->conv_to_posix_path (srcbuf, contents, 0);
2011 else if (srcbuf[0] == '\\')
2013 if (srcbuf[1] == '\\') /* UNC path */
2014 slashify (srcbuf, contents, 0);
2015 else /* Paths starting with \ are current drive relative. */
2017 char cvtbuf[SYMLINK_MAX + 1];
2019 stpcpy (cvtbuf + cygheap->cwd.get_drive (cvtbuf), srcbuf);
2020 mount_table->conv_to_posix_path (cvtbuf, contents, 0);
2023 else /* Everything else is taken as is. */
2024 slashify (srcbuf, contents, 0);
2025 return strlen (contents);
2034 SCAN_JUSTCHECKTHIS, /* Never try to append a suffix. */
2042 const suffix_info *suffixes, *suffixes_start;
2047 char *has (const char *, const suffix_info *);
2049 int lnk_match () {return nextstate >= SCAN_APPENDLNK;}
2053 suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
2055 nextstate = SCAN_BEG;
2056 suffixes = suffixes_start = in_suffixes;
2058 const char *fname = strrchr (in_path, '\\');
2059 fname = fname ? fname + 1 : in_path;
2060 char *ext_here = strrchr (fname, '.');
2062 eopath = strchr (path, '\0');
2069 /* Check if the extension matches a known extension */
2070 for (const suffix_info *ex = in_suffixes; ex->name != NULL; ex++)
2071 if (ascii_strcasematch (ext_here, ex->name))
2073 nextstate = SCAN_JUSTCHECK;
2074 suffixes = NULL; /* Has an extension so don't scan for one. */
2079 /* Didn't match. Use last resort -- .lnk. */
2080 if (ascii_strcasematch (ext_here, ".lnk"))
2082 nextstate = SCAN_HASLNK;
2090 /* Avoid attaching suffixes if the resulting filename would be invalid. */
2091 if (eopath - fname > NAME_MAX - 4)
2093 nextstate = SCAN_JUSTCHECKTHIS;
2100 suffix_scan::next ()
2108 suffixes = suffixes_start;
2111 nextstate = SCAN_LNK;
2114 nextstate = SCAN_EXTRALNK;
2115 /* fall through to suffix checking below */
2118 nextstate = SCAN_APPENDLNK; /* Skip SCAN_BEG */
2121 nextstate = SCAN_DONE;
2124 case SCAN_JUSTCHECK:
2125 nextstate = SCAN_LNK;
2127 case SCAN_JUSTCHECKTHIS:
2128 nextstate = SCAN_DONE;
2131 case SCAN_APPENDLNK:
2132 strcat (eopath, ".lnk");
2133 nextstate = SCAN_DONE;
2140 while (suffixes && suffixes->name)
2141 if (nextstate == SCAN_EXTRALNK && !suffixes->addon)
2145 strcpy (eopath, suffixes->name);
2146 if (nextstate == SCAN_EXTRALNK)
2147 strcat (eopath, ".lnk");
2156 symlink_info::set_error (int in_errno)
2159 if (!(pflags & PATH_NO_ACCESS_CHECK) || in_errno == ENAMETOOLONG || in_errno == EIO)
2164 else if (in_errno == ENOENT)
2168 fileattr = FILE_ATTRIBUTE_NORMAL;
2175 symlink_info::parse_device (const char *contents)
2182 mymajor = strtol (contents += 2, &endptr, 16);
2183 if (endptr == contents)
2184 return isdevice = false;
2187 myminor = strtol (++contents, &endptr, 16);
2188 if (endptr == contents)
2189 return isdevice = false;
2192 mymode = strtol (++contents, &endptr, 16);
2193 if (endptr == contents)
2194 return isdevice = false;
2196 if ((mymode & S_IFMT) == S_IFIFO)
2198 mymajor = _major (FH_FIFO);
2199 myminor = _minor (FH_FIFO);
2205 return isdevice = true;
2208 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2210 If PATH is a symlink, put the value of the symlink--the file to
2211 which it points--into BUF. The value stored in BUF is not
2212 necessarily null terminated. BUFLEN is the length of BUF; only up
2213 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2214 which case nothing will be stored.
2216 Set *SYML if PATH is a symlink.
2218 Set *EXEC if PATH appears to be executable. This is an efficiency
2219 hack because we sometimes have to open the file anyhow. *EXEC will
2220 not be set for every executable file.
2222 Return -1 on error, 0 if PATH is not a symlink, or the length
2223 stored into BUF if PATH is a symlink. */
2226 symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs,
2227 path_conv_handle &conv_hdl)
2232 UNICODE_STRING upath;
2233 OBJECT_ATTRIBUTES attr;
2237 const ULONG ci_flag = cygwin_shared->obcaseinsensitive
2238 || (pflags & PATH_NOPOSIX) ? OBJ_CASE_INSENSITIVE : 0;
2239 /* TODO: Temporarily do all char->UNICODE conversion here. This should
2240 already be slightly faster than using Ascii functions. */
2243 InitializeObjectAttributes (&attr, &upath, ci_flag, NULL, NULL);
2245 /* This label is used in case we encounter a FS which only handles
2246 DOS paths. See below. */
2247 bool restarted = false;
2258 pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
2260 ext_here = suffix.has (path, suffixes);
2261 extn = ext_here - path;
2263 PVOID eabuf = &nfs_aol_ffei;
2264 ULONG easize = sizeof nfs_aol_ffei;
2266 bool had_ext = !!*ext_here;
2267 while (suffix.next ())
2272 get_nt_native_path (suffix.path, upath, pflags & PATH_DOS);
2278 /* The EA given to NtCreateFile allows to get a handle to a symlink on
2279 an NFS share, rather than getting a handle to the target of the
2280 symlink (which would spoil the task of this method quite a bit).
2281 Fortunately it's ignored on most other file systems so we don't have
2282 to special case NFS too much. */
2283 status = NtCreateFile (&h,
2284 READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA,
2285 &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS,
2287 FILE_OPEN_REPARSE_POINT
2288 | FILE_OPEN_FOR_BACKUP_INTENT,
2290 debug_printf ("%p = NtCreateFile (%S)", status, &upath);
2291 /* No right to access EAs or EAs not supported? */
2292 if (!NT_SUCCESS (status)
2293 && (status == STATUS_ACCESS_DENIED
2294 || status == STATUS_EAS_NOT_SUPPORTED
2295 || status == STATUS_NOT_SUPPORTED
2296 || status == STATUS_INVALID_NETWORK_RESPONSE
2297 /* Or a bug in Samba 3.2.x (x <= 7) when accessing a share's
2298 root dir which has EAs enabled? */
2299 || status == STATUS_INVALID_PARAMETER))
2302 /* If EAs are not supported, there's no sense to check them again
2303 with suffixes attached. So we set eabuf/easize to 0 here once. */
2304 if (status == STATUS_EAS_NOT_SUPPORTED
2305 || status == STATUS_NOT_SUPPORTED)
2310 status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2311 &attr, &io, FILE_SHARE_VALID_FLAGS,
2312 FILE_OPEN_REPARSE_POINT
2313 | FILE_OPEN_FOR_BACKUP_INTENT);
2314 debug_printf ("%p = NtOpenFile (no-EAs %S)", status, &upath);
2316 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
2318 if (ci_flag == 0 && wincap.has_broken_udf ()
2319 && (!fs.inited () || fs.is_udf ()))
2321 /* On NT 5.x UDF is broken (at least) in terms of case
2322 sensitivity. When trying to open a file case sensitive,
2323 the file appears to be non-existant. Another bug is
2324 described in fs_info::update. */
2325 attr.Attributes = OBJ_CASE_INSENSITIVE;
2326 status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2327 &attr, &io, FILE_SHARE_VALID_FLAGS,
2328 FILE_OPEN_REPARSE_POINT
2329 | FILE_OPEN_FOR_BACKUP_INTENT);
2330 debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath);
2331 attr.Attributes = 0;
2332 if (NT_SUCCESS (status))
2335 fs.update (&upath, h);
2340 status = STATUS_OBJECT_NAME_NOT_FOUND;
2344 /* There are filesystems out in the wild (Netapp, NWFS, and others)
2345 which are uncapable of generating pathnames outside the Win32
2346 rules. That means, filenames on these FSes must not have a
2347 leading space or trailing dots and spaces. This code snippet
2348 manages them. I really hope it's streamlined enough not to
2349 slow down normal operation. This extra check only kicks in if
2350 we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't
2351 already attach a suffix *and* the above special case for UDF
2352 on XP didn't succeeed. */
2353 if (!restarted && !*ext_here && !(pflags & PATH_DOS) && !fs.inited ())
2355 /* Check for trailing dot or space or leading space in
2357 char *p = ext_here - 1;
2358 if (*p != '.' && *p != ' ')
2360 while (*--p != '\\')
2367 /* If so, check if file resides on one of the known broken
2368 FSes only supporting filenames following DOS rules. */
2370 fs.update (&upath, NULL);
2371 if (fs.has_dos_filenames_only ())
2373 /* If so, try again. Since we now know the FS, the
2374 filenames will be tweaked to follow DOS rules via the
2375 third parameter in the call to get_nt_native_path. */
2384 if (NT_SUCCESS (status)
2385 /* Check file system while we're having the file open anyway.
2386 This speeds up path_conv noticably (~10%). */
2387 && (fs.inited () || fs.update (&upath, h)))
2391 status = nfs_fetch_fattr3 (h, conv_hdl.nfsattr ());
2392 if (NT_SUCCESS (status))
2393 fileattr = ((conv_hdl.nfsattr ()->type & 7) == NF3DIR)
2394 ? FILE_ATTRIBUTE_DIRECTORY : 0;
2398 PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2400 /* Netapps don't implement FileNetworkOpenInformation. */
2401 status = fs.is_netapp ()
2402 ? STATUS_INVALID_PARAMETER
2403 : NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi,
2404 FileNetworkOpenInformation);
2405 if (status == STATUS_INVALID_PARAMETER
2406 || status == STATUS_NOT_IMPLEMENTED)
2408 /* Apart from accessing Netapps, this also occurs when
2409 accessing SMB share root dirs hosted on NT4
2410 (STATUS_INVALID_PARAMETER), or when trying to access
2411 SMB share root dirs from NT4 (STATUS_NOT_IMPLEMENTED). */
2412 FILE_BASIC_INFORMATION fbi;
2413 FILE_STANDARD_INFORMATION fsi;
2415 status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
2416 FileBasicInformation);
2417 if (NT_SUCCESS (status))
2419 memcpy (pfnoi, &fbi, 4 * sizeof (LARGE_INTEGER));
2420 if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fsi,
2422 FileStandardInformation)))
2424 pfnoi->EndOfFile.QuadPart = fsi.EndOfFile.QuadPart;
2425 pfnoi->AllocationSize.QuadPart
2426 = fsi.AllocationSize.QuadPart;
2429 pfnoi->EndOfFile.QuadPart
2430 = pfnoi->AllocationSize.QuadPart = 0;
2431 pfnoi->FileAttributes = fbi.FileAttributes;
2434 if (NT_SUCCESS (status))
2435 fileattr = pfnoi->FileAttributes;
2438 if (!NT_SUCCESS (status))
2440 debug_printf ("%p = NtQueryInformationFile (%S)", status, &upath);
2441 fileattr = INVALID_FILE_ATTRIBUTES;
2443 /* One of the inner path components is invalid, or the path contains
2444 invalid characters. Bail out with ENOENT.
2446 Note that additional STATUS_OBJECT_PATH_INVALID and
2447 STATUS_OBJECT_PATH_SYNTAX_BAD status codes exist. The first one
2448 is seemingly not generated by NtQueryInformationFile, the latter
2449 is only generated if the path is no absolute path within the
2450 NT name space, which should not happen and would point to an
2451 error in get_nt_native_path. Both status codes are deliberately
2452 not tested here unless proved necessary. */
2453 if (status == STATUS_OBJECT_PATH_NOT_FOUND
2454 || status == STATUS_OBJECT_NAME_INVALID
2455 || status == STATUS_BAD_NETWORK_PATH
2456 || status == STATUS_BAD_NETWORK_NAME
2457 || status == STATUS_NO_MEDIA_IN_DEVICE)
2460 goto file_not_symlink;
2462 if (status != STATUS_OBJECT_NAME_NOT_FOUND
2463 && status != STATUS_NO_SUCH_FILE) /* ENOENT on NFS or 9x share */
2465 /* The file exists, but the user can't access it for one reason
2466 or the other. To get the file attributes we try to access the
2467 information by opening the parent directory and getting the
2468 file attributes using a matching NtQueryDirectoryFile call. */
2469 UNICODE_STRING dirname, basename;
2470 OBJECT_ATTRIBUTES dattr;
2473 FILE_BOTH_DIRECTORY_INFORMATION fdi;
2474 WCHAR dummy_buf[NAME_MAX + 1];
2477 RtlSplitUnicodePath (&upath, &dirname, &basename);
2478 InitializeObjectAttributes (&dattr, &dirname, ci_flag,
2480 status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
2481 &dattr, &io, FILE_SHARE_VALID_FLAGS,
2482 FILE_SYNCHRONOUS_IO_NONALERT
2483 | FILE_OPEN_FOR_BACKUP_INTENT
2484 | FILE_DIRECTORY_FILE);
2485 if (!NT_SUCCESS (status))
2487 debug_printf ("%p = NtOpenFile(%S)", status, &dirname);
2488 /* There's a special case if the file is itself the root
2489 of a drive which is not accessible by the current user.
2490 This case is only recognized by the length of the
2491 basename part. If it's 0, the incoming file is the
2492 root of a drive. So we at least know it's a directory. */
2493 fileattr = basename.Length ? 0 : FILE_ATTRIBUTE_DIRECTORY;
2497 status = NtQueryDirectoryFile (dir, NULL, NULL, NULL, &io,
2498 &fdi_buf, sizeof fdi_buf,
2499 FileBothDirectoryInformation,
2500 TRUE, &basename, TRUE);
2501 /* Take the opportunity to check file system while we're
2502 having the handle to the parent dir. */
2503 fs.update (&upath, dir);
2505 if (!NT_SUCCESS (status))
2507 debug_printf ("%p = NtQueryDirectoryFile(%S)",
2509 if (status == STATUS_NO_SUCH_FILE)
2511 /* This can happen when trying to access files
2512 which match DOS device names on SMB shares.
2513 NtOpenFile failed with STATUS_ACCESS_DENIED,
2514 but the NtQueryDirectoryFile tells us the
2515 file doesn't exist. We're suspicious in this
2516 case and retry with the next suffix instead of
2525 PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2527 fileattr = fdi_buf.fdi.FileAttributes;
2528 memcpy (pfnoi, &fdi_buf.fdi.CreationTime, sizeof *pfnoi);
2529 /* Amazing, but true: The FILE_NETWORK_OPEN_INFORMATION
2530 structure has the AllocationSize and EndOfFile members
2531 interchanged relative to the directory information
2533 pfnoi->AllocationSize.QuadPart
2534 = fdi_buf.fdi.AllocationSize.QuadPart;
2535 pfnoi->EndOfFile.QuadPart
2536 = fdi_buf.fdi.EndOfFile.QuadPart;
2539 ext_tacked_on = !!*ext_here;
2540 goto file_not_symlink;
2546 ext_tacked_on = !!*ext_here;
2547 /* Don't allow to returns directories with appended suffix. If we found
2548 a directory with a suffix which has been appended here, then this
2549 directory doesn't match the request. So, just do as usual if file
2550 hasn't been found. */
2551 if (ext_tacked_on && !had_ext && (fileattr & FILE_ATTRIBUTE_DIRECTORY))
2559 /* Reparse points are potentially symlinks. This check must be
2560 performed before checking the SYSTEM attribute for sysfile
2561 symlinks, since reparse points can have this flag set, too.
2562 For instance, Vista starts to create a couple of reparse points
2563 with SYSTEM and HIDDEN flags set. */
2564 if ((fileattr & FILE_ATTRIBUTE_REPARSE_POINT))
2566 /* Don't check reparse points on remote filesystems. A reparse point
2567 pointing to another file on the remote system will be mistreated
2568 as pointing to a local file on the local system. This breaks the
2569 way reparse points are transparently handled on remote systems. */
2570 if (fs.is_remote_drive())
2573 res = check_reparse_point (h);
2576 /* Volume mount point. The filesystem information for the top
2577 level directory should be for the volume top level directory,
2578 rather than for the reparse point itself. So we fetch the
2579 filesystem information again, but with a NULL handle.
2580 This does what we want because fs_info::update opens the
2581 handle without FILE_OPEN_REPARSE_POINT. */
2582 fs.update (&upath, NULL);
2583 /* Make sure the open handle is not used in later stat calls.
2584 The handle has been opened with the FILE_OPEN_REPARSE_POINT
2585 flag, so it's a handle to the reparse point, not a handle
2586 to the volumes root dir. */
2587 pflags &= ~PC_KEEP_HANDLE;
2591 /* A symlink is never a directory. */
2592 conv_hdl.fnoi ()->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
2597 /* Windows shortcuts are potentially treated as symlinks. Valid Cygwin
2598 & U/WIN shortcuts are R/O, but definitely not directories. */
2599 else if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
2600 == FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
2604 status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2605 FILE_SHARE_VALID_FLAGS,
2606 FILE_OPEN_FOR_BACKUP_INTENT
2607 | FILE_SYNCHRONOUS_IO_NONALERT);
2608 if (!NT_SUCCESS (status))
2612 res = check_shortcut (sym_h);
2617 /* If searching for `foo' and then finding a `foo.lnk' which
2618 is no shortcut, return the same as if file not found. */
2621 fileattr = INVALID_FILE_ATTRIBUTES;
2626 else if (contents[0] != ':' || contents[1] != '\\'
2627 || !parse_device (contents))
2631 /* If searching for `foo' and then finding a `foo.lnk' which is
2632 no shortcut, return the same as if file not found. */
2633 else if (suffix.lnk_match () && ext_tacked_on)
2635 fileattr = INVALID_FILE_ATTRIBUTES;
2640 /* This is the old Cygwin method creating symlinks. A symlink will
2641 have the `system' file attribute. Only files can be symlinks
2642 (which can be symlinks to directories). */
2643 else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))
2644 == FILE_ATTRIBUTE_SYSTEM)
2648 status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2649 FILE_SHARE_VALID_FLAGS,
2650 FILE_OPEN_FOR_BACKUP_INTENT
2651 | FILE_SYNCHRONOUS_IO_NONALERT);
2653 if (!NT_SUCCESS (status))
2657 res = check_sysfile (sym_h);
2664 /* If the file is on an NFS share and could be opened with extended
2665 attributes, check if it's a symlink. Only files can be symlinks
2666 (which can be symlinks to directories). */
2667 else if (fs.is_nfs () && (conv_hdl.nfsattr ()->type & 7) == NF3LNK)
2669 res = check_nfs_symlink (h);
2677 syscall_printf ("%s", isdevice ? "is a device" : "not a symlink");
2684 if (pflags & PC_KEEP_HANDLE)
2690 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2691 res, suffix.path, contents, pflags);
2695 /* "path" is the path in a virtual symlink. Set a symlink_info struct from
2696 that and proceed with further path checking afterwards. */
2698 symlink_info::set (char *path)
2700 strcpy (contents, path);
2701 pflags = PATH_SYMLINK;
2702 fileattr = FILE_ATTRIBUTE_NORMAL;
2706 ext_tacked_on = false;
2708 extn = major = minor = mode = 0;
2709 return strlen (path);
2712 /* readlink system call */
2715 readlink (const char *path, char *buf, size_t buflen)
2719 set_errno (ENAMETOOLONG);
2723 path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2727 set_errno (pathbuf.error);
2728 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2732 if (!pathbuf.exists ())
2738 if (!pathbuf.issymlink ())
2740 if (pathbuf.exists ())
2745 ssize_t len = min (buflen, strlen (pathbuf.get_win32 ()));
2746 memcpy (buf, pathbuf.get_win32 (), len);
2748 /* errno set by symlink.check if error */
2752 /* Some programs rely on st_dev/st_ino being unique for each file.
2753 Hash the path name and hope for the best. The hash arg is not
2754 always initialized to zero since readdir needs to compute the
2755 dirent ino_t based on a combination of the hash of the directory
2756 done during the opendir call and the hash or the filename within
2757 the directory. FIXME: Not bullet-proof. */
2758 /* Cygwin internal */
2760 hash_path_name (__ino64_t hash, PUNICODE_STRING name)
2762 if (name->Length == 0)
2765 /* Build up hash. Name is already normalized */
2766 USHORT len = name->Length / sizeof (WCHAR);
2767 for (USHORT idx = 0; idx < len; ++idx)
2768 hash = RtlUpcaseUnicodeChar (name->Buffer[idx])
2769 + (hash << 6) + (hash << 16) - hash;
2774 hash_path_name (__ino64_t hash, PCWSTR name)
2776 UNICODE_STRING uname;
2777 RtlInitUnicodeString (&uname, name);
2778 return hash_path_name (hash, &uname);
2782 hash_path_name (__ino64_t hash, const char *name)
2784 UNICODE_STRING uname;
2785 RtlCreateUnicodeStringFromAsciiz (&uname, name);
2786 __ino64_t ret = hash_path_name (hash, &uname);
2787 RtlFreeUnicodeString (&uname);
2792 getcwd (char *buf, size_t ulen)
2796 if (efault.faulted (EFAULT))
2798 else if (ulen == 0 && buf)
2801 res = cygheap->cwd.get (buf, 1, 1, ulen);
2805 /* getwd: Legacy. */
2809 return getcwd (buf, PATH_MAX + 1); /*Per SuSv3!*/
2812 /* chdir: POSIX 5.2.1.1 */
2814 chdir (const char *in_dir)
2817 if (efault.faulted (EFAULT))
2825 syscall_printf ("dir '%s'", in_dir);
2827 /* Convert path. First argument ensures that we don't check for NULL/empty/invalid
2829 path_conv path (PC_NONULLEMPTY, in_dir, PC_SYM_FOLLOW | PC_POSIX);
2832 set_errno (path.error);
2833 syscall_printf ("-1 = chdir (%s)", in_dir);
2838 const char *posix_cwd = NULL;
2839 int devn = path.get_devn ();
2840 if (!path.exists ())
2842 else if (!path.isdir ())
2843 set_errno (ENOTDIR);
2844 else if (!isvirtual_dev (devn))
2846 /* The sequence chdir("xx"); chdir(".."); must be a noop if xx
2847 is not a symlink. This is exploited by find.exe.
2848 The posix_cwd is just path.normalized_path.
2849 In other cases we let cwd.set obtain the Posix path through
2851 if (!isdrive(path.normalized_path))
2852 posix_cwd = path.normalized_path;
2857 posix_cwd = path.normalized_path;
2862 res = cygheap->cwd.set (&path, posix_cwd);
2864 /* Note that we're accessing cwd.posix without a lock here. I didn't think
2865 it was worth locking just for strace. */
2866 syscall_printf ("%d = chdir() cygheap->cwd.posix '%s' native '%S'", res,
2867 cygheap->cwd.get_posix (), path.get_nt_native_path ());
2876 cygheap_fdget cfd (fd);
2878 res = chdir (cfd->get_name ());
2882 syscall_printf ("%d = fchdir (%d)", res, fd);
2886 /******************** Exported Path Routines *********************/
2888 /* Cover functions to the path conversion routines.
2889 These are exported to the world as cygwin_foo by cygwin.din. */
2891 #define return_with_errno(x) \
2901 cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to,
2906 if (efault.faulted (EFAULT))
2914 bool relative = !!(what & CCP_RELATIVE);
2915 what &= ~CCP_RELATIVE;
2919 case CCP_POSIX_TO_WIN_A:
2921 p.check ((const char *) from,
2922 PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2923 | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2925 return_with_errno (p.error);
2926 PUNICODE_STRING up = p.get_nt_native_path ();
2928 sys_wcstombs (buf, NT_MAX_PATH, up->Buffer, up->Length / sizeof (WCHAR));
2929 /* Convert native path to standard DOS path. */
2930 if (!strncmp (buf, "\\??\\", 4))
2933 if (buf[1] != ':') /* native UNC path */
2936 else if (*buf == '\\')
2938 /* Device name points to somewhere else in the NT namespace.
2939 Use GLOBALROOT prefix to convert to Win32 path. */
2940 char *p = stpcpy (buf, "\\\\.\\GLOBALROOT");
2941 sys_wcstombs (p, NT_MAX_PATH - (p - buf),
2942 up->Buffer, up->Length / sizeof (WCHAR));
2944 lsiz = strlen (buf) + 1;
2945 /* TODO: Incoming "." is a special case which leads to a trailing
2946 backslash ".\\" in the Win32 path. That's a result of the
2947 conversion in normalize_posix_path. This should not occur
2948 so the below code is just a band-aid. */
2949 if (relative && !strcmp ((const char *) from, ".")
2950 && !strcmp (buf, ".\\"))
2957 case CCP_POSIX_TO_WIN_W:
2958 p.check ((const char *) from,
2959 PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2960 | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2962 return_with_errno (p.error);
2963 /* Relative Windows paths are always restricted to MAX_PATH chars. */
2964 if (relative && !isabspath (p.get_win32 ())
2965 && sys_mbstowcs (NULL, 0, p.get_win32 ()) > MAX_PATH)
2967 /* Recreate as absolute path. */
2968 p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW
2969 | PC_NO_ACCESS_CHECK | PC_NOWARN);
2971 return_with_errno (p.error);
2973 lsiz = p.get_wide_win32_path_len () + 1;
2974 path = p.get_nt_native_path ()->Buffer;
2976 /* Convert native path to standard DOS path. */
2977 if (!wcsncmp (path, L"\\??\\", 4))
2981 /* Drop long path prefix for short pathnames. Unfortunately there's
2982 quite a bunch of Win32 functions, especially in user32.dll,
2983 apparently, which don't grok long path names at all, not even
2984 in the UNICODE API. */
2985 if ((path[5] == L':' && lsiz <= MAX_PATH + 4)
2986 || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6))
2990 if (path[1] != L':')
2992 *(path += 2) = '\\';
2997 else if (*path == L'\\')
2999 /* Device name points to somewhere else in the NT namespace.
3000 Use GLOBALROOT prefix to convert to Win32 path. */
3001 to = (void *) wcpcpy ((wchar_t *) to, L"\\\\.\\GLOBALROOT");
3002 lsiz += sizeof ("\\\\.\\GLOBALROOT") - 1;
3004 /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */
3005 if (relative && !strcmp ((const char *) from, ".")
3006 && !wcscmp (path, L".\\"))
3011 lsiz *= sizeof (WCHAR);
3013 case CCP_WIN_A_TO_POSIX:
3015 error = mount_table->conv_to_posix_path ((const char *) from, buf,
3018 return_with_errno (error);
3019 lsiz = strlen (buf) + 1;
3021 case CCP_WIN_W_TO_POSIX:
3023 error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf,
3026 return_with_errno (error);
3027 lsiz = strlen (buf) + 1;
3042 case CCP_POSIX_TO_WIN_A:
3043 case CCP_WIN_A_TO_POSIX:
3044 case CCP_WIN_W_TO_POSIX:
3045 stpcpy ((char *) to, buf);
3047 case CCP_POSIX_TO_WIN_W:
3048 wcpcpy ((PWCHAR) to, path);
3055 cygwin_create_path (cygwin_conv_path_t what, const void *from)
3058 ssize_t size = cygwin_conv_path (what, from, NULL, 0);
3061 else if (!(to = malloc (size)))
3063 if (cygwin_conv_path (what, from, to, size) == -1)
3073 cygwin_conv_to_win32_path (const char *path, char *win32_path)
3075 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, path, win32_path,
3080 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
3082 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path, win32_path,
3086 /* This is exported to the world as cygwin_foo by cygwin.din. */
3089 cygwin_conv_to_posix_path (const char *path, char *posix_path)
3091 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, path, posix_path,
3096 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
3098 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, path, posix_path,
3102 /* The realpath function is required by POSIX:2008. */
3105 realpath (const char *path, char *resolved)
3107 /* Make sure the right errno is returned if path is NULL. */
3114 /* Guard reading from a potentially invalid path and writing to a
3115 potentially invalid resolved. */
3118 if (efault.faulted (EFAULT))
3124 tpath = tp.c_get ();
3125 mount_table->cygdrive_posix_path (path, tpath, 0);
3128 tpath = (char *) path;
3130 path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
3133 /* POSIX 2008 requires malloc'ing if resolved is NULL, and states
3134 that using non-NULL resolved is asking for portability
3137 if (!real_path.error && real_path.exists ())
3141 resolved = (char *) malloc (strlen (real_path.normalized_path) + 1);
3145 strcpy (resolved, real_path.normalized_path);
3149 /* FIXME: on error, Linux puts the name of the path
3150 component which could not be resolved into RESOLVED, but POSIX
3151 does not require this. */
3154 set_errno (real_path.error ?: ENOENT);
3158 /* Linux provides this extension. Since the only portable use of
3159 realpath requires a NULL second argument, we might as well have a
3160 one-argument wrapper. */
3162 canonicalize_file_name (const char *path)
3164 return realpath (path, NULL);
3167 /* Return non-zero if path is a POSIX path list.
3168 This is exported to the world as cygwin_foo by cygwin.din.
3171 <sect1 id="add-func-cygwin-posix-path-list-p">
3172 <para>Rather than use a mode to say what the "proper" path list
3173 format is, we allow any, and give apps the tools they need to
3174 convert between the two. If a ';' is present in the path list it's
3175 a Win32 path list. Otherwise, if the first path begins with
3176 [letter]: (in which case it can be the only element since if it
3177 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
3178 it's a POSIX path list.</para>
3184 cygwin_posix_path_list_p (const char *path)
3186 int posix_p = !(strchr (path, ';') || isdrive (path));
3190 /* These are used for apps that need to convert env vars like PATH back and
3191 forth. The conversion is a two step process. First, an upper bound on the
3192 size of the buffer needed is computed. Then the conversion is done. This
3193 allows the caller to use alloca if it wants. */
3196 conv_path_list_buf_size (const char *path_list, bool to_posix)
3198 int i, num_elms, max_mount_path_len, size;
3201 path_conv pc(".", PC_POSIX);
3202 /* The theory is that an upper bound is
3203 current_size + (num_elms * max_mount_path_len) */
3204 /* FIXME: This method is questionable in the long run. */
3207 char delim = to_posix ? ';' : ':';
3208 for (p = path_list, num_elms = nrel = 0; p; num_elms++)
3212 p = strchr (++p, delim);
3215 /* 7: strlen ("//c") + slop, a conservative initial value */
3216 for (max_mount_path_len = sizeof ("/cygdrive/X"), i = 0;
3217 i < mount_table->nmounts; i++)
3219 int mount_len = (to_posix
3220 ? mount_table->mount[i].posix_pathlen
3221 : mount_table->mount[i].native_pathlen);
3222 if (max_mount_path_len < mount_len)
3223 max_mount_path_len = mount_len;
3227 size = strlen (path_list)
3228 + (num_elms * max_mount_path_len)
3229 + (nrel * strlen (to_posix ? pc.normalized_path : pc.get_win32 ()))
3237 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
3239 return conv_path_list_buf_size (path_list, true);
3243 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
3245 return conv_path_list_buf_size (path_list, false);
3249 env_PATH_to_posix (const void *win32, void *posix, size_t size)
3251 return_with_errno (conv_path_list ((const char *) win32, (char *) posix,
3256 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
3258 return_with_errno (conv_path_list (win32, posix, MAX_PATH, 1));
3262 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
3264 return_with_errno (conv_path_list (posix, win32, MAX_PATH, 0));
3268 cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
3271 /* FIXME: Path lists are (so far) always retaining relative paths. */
3272 what &= ~CCP_RELATIVE;
3275 case CCP_WIN_W_TO_POSIX:
3276 case CCP_POSIX_TO_WIN_W:
3278 api_fatal ("wide char path lists not yet supported");
3280 case CCP_WIN_A_TO_POSIX:
3281 case CCP_POSIX_TO_WIN_A:
3283 return conv_path_list_buf_size ((const char *) from,
3284 what == CCP_WIN_A_TO_POSIX);
3285 return_with_errno (conv_path_list ((const char *) from, (char *) to,
3286 size, what == CCP_WIN_A_TO_POSIX));
3295 /* cygwin_split_path: Split a path into directory and file name parts.
3296 Buffers DIR and FILE are assumed to be big enough.
3298 Examples (path -> `dir' / `file'):
3301 . -> `.' / `.' (FIXME: should this be `.' / `'?)
3302 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
3304 foo/bar -> `foo' / `bar'
3305 foo/bar/ -> `foo' / `bar'
3307 /foo/bar -> `/foo' / `bar'
3310 c:foo -> `c:/' / `foo'
3311 c:/foo -> `c:/' / `foo'
3315 cygwin_split_path (const char *path, char *dir, char *file)
3317 int dir_started_p = 0;
3319 /* Deal with drives.
3320 Remember that c:foo <==> c:/foo. */
3332 if (isdirsep (*path))
3337 /* Determine if there are trailing slashes and "delete" them if present.
3338 We pretend as if they don't exist. */
3339 const char *end = path + strlen (path);
3340 /* path + 1: keep leading slash. */
3341 while (end > path + 1 && isdirsep (end[-1]))
3344 /* At this point, END points to one beyond the last character
3345 (with trailing slashes "deleted"). */
3347 /* Point LAST_SLASH at the last slash (duh...). */
3348 const char *last_slash;
3349 for (last_slash = end - 1; last_slash >= path; --last_slash)
3350 if (isdirsep (*last_slash))
3353 if (last_slash == path)
3358 else if (last_slash > path)
3360 memcpy (dir, path, last_slash - path);
3361 dir[last_slash - path] = 0;
3366 ; /* nothing to do */
3372 memcpy (file, last_slash + 1, end - last_slash - 1);
3373 file[end - last_slash - 1] = 0;
3376 /*****************************************************************************/
3378 /* The find_fast_cwd_pointers function and parts of the
3379 cwdstuff::override_win32_cwd method are based on code using the
3382 Copyright 2010 John Carey. All rights reserved.
3384 Redistribution and use in source and binary forms, with or without
3385 modification, are permitted provided that the following conditions
3388 1. Redistributions of source code must retain the above
3389 copyright notice, this list of conditions and the following
3392 2. Redistributions in binary form must reproduce the above
3393 copyright notice, this list of conditions and the following
3394 disclaimer in the documentation and/or other materials provided
3395 with the distribution.
3397 THIS SOFTWARE IS PROVIDED BY JOHN CAREY ``AS IS'' AND ANY EXPRESS
3398 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3399 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3400 ARE DISCLAIMED. IN NO EVENT SHALL JOHN CAREY OR CONTRIBUTORS BE
3401 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3402 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
3403 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
3404 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3405 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3406 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3407 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3410 /* This structure is used to store the CWD starting with Windows Vista.
3411 The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only
3412 an afterthought now. The actual CWD storage is a FAST_CWD structure
3413 which is allocated on the process heap. The new method only requires
3414 minimal locking and it's much more multi-thread friendly. Presumably
3415 it minimizes contention when accessing the CWD. */
3416 typedef struct _FAST_CWD {
3417 LONG ReferenceCount; /* Only release when this is 0. */
3418 HANDLE DirectoryHandle;
3419 ULONG OldDismountCount; /* Reflects the system DismountCount
3420 at the time the CWD has been set. */
3421 UNICODE_STRING Path; /* Path's Buffer member always refers
3422 to the following Buffer array. */
3423 WCHAR Buffer[MAX_PATH];
3424 } FAST_CWD, *PFAST_CWD;
3426 /* fast_cwd_ptr is a pointer to the global pointer in ntdll.dll pointing
3427 to the FAST_CWD structure which constitutes the CWD.
3429 We put the pointer into the common shared DLL segment. This allows to
3430 restrict the call to find_fast_cwd_pointers() to once per Cygwin session
3431 per user session. This works, because ASLR randomizes the load address
3432 of DLLs only once at boot time. */
3433 static PFAST_CWD *fast_cwd_ptr
3434 __attribute__((section (".cygwin_dll_common"), shared)) = (PFAST_CWD *) -1;
3436 /* This is the mapping of the KUSER_SHARED_DATA structure into the 32 bit
3437 user address space. We need it here to access the current DismountCount. */
3438 static KUSER_SHARED_DATA &SharedUserData
3439 = *(volatile PKUSER_SHARED_DATA) 0x7ffe0000;
3441 #define peek32(x) (*(uint32_t *)(x))
3443 /* This function scans the code in ntdll.dll to find the address of the
3444 global variable used to access the CWD starting with Vista. While the
3445 pointer is global, it's not exported from the DLL, unfortunately.
3446 Therefore we have to use some knowledge to figure out the address.
3448 This code has been tested on Vista 32/64 bit, Server 2008 32/64 bit,
3449 Windows 7 32/64 bit, and Server 2008 R2 (which is only 64 bit anyway).
3450 There's some hope that this will still work for Windows 8... */
3452 find_fast_cwd_pointers ()
3454 /* Note that we have been called. */
3455 fast_cwd_ptr = NULL;
3456 /* Fetch entry points of relevant functions in ntdll.dll. */
3457 HMODULE ntdll = GetModuleHandle ("ntdll.dll");
3460 const uint8_t *get_dir = (const uint8_t *)
3461 GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
3462 const uint8_t *ent_crit = (const uint8_t *)
3463 GetProcAddress (ntdll, "RtlEnterCriticalSection");
3464 if (!get_dir || !ent_crit)
3466 /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
3467 const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 32);
3470 /* Fetch offset from instruction and compute address of called function.
3471 This function actually fetches the current FAST_CWD instance and
3472 performs some other actions, not important to us. */
3473 ptrdiff_t offset = (ptrdiff_t) peek32 (rcall + 1);
3474 const uint8_t *use_cwd = rcall + 5 + offset;
3475 /* Find first "push edi" instruction. */
3476 const uint8_t *pushedi = (const uint8_t *) memchr (use_cwd, 0x57, 32);
3477 /* ...which should be followed by "mov edi, crit-sect-addr" then
3479 const uint8_t *movedi = pushedi + 1;
3480 if (movedi[0] != 0xbf || movedi[5] != 0x57)
3482 /* Compare the address used for the critical section with the known
3483 PEB lock as stored in the PEB. */
3484 if ((PRTL_CRITICAL_SECTION) peek32 (movedi + 1)
3485 != NtCurrentTeb ()->Peb->FastPebLock)
3487 /* To check we are seeing the right code, we check our expectation that
3488 the next instruction is a relative call into RtlEnterCriticalSection. */
3490 if (rcall[0] != 0xe8)
3492 /* Check that this is a relative call to RtlEnterCriticalSection. */
3493 offset = (ptrdiff_t) peek32 (rcall + 1);
3494 if (rcall + 5 + offset != ent_crit)
3496 /* After locking the critical section, the code should read the global
3497 PFAST_CWD * pointer that is guarded by that critical section. */
3498 const uint8_t *movesi = rcall + 5;
3499 if (movesi[0] != 0x8b)
3501 fast_cwd_ptr = (PFAST_CWD *) peek32 (movesi + 2);
3505 copy_cwd_str (PUNICODE_STRING tgt, PUNICODE_STRING src)
3507 RtlCopyUnicodeString (tgt, src);
3508 if (tgt->Buffer[tgt->Length / sizeof (WCHAR) - 1] != L'\\')
3510 tgt->Buffer[tgt->Length / sizeof (WCHAR)] = L'\\';
3511 tgt->Length += sizeof (WCHAR);
3516 cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
3521 PEB &peb = *NtCurrentTeb ()->Peb;
3522 UNICODE_STRING &upp_cwd_str = peb.ProcessParameters->CurrentDirectoryName;
3523 HANDLE &upp_cwd_hdl = peb.ProcessParameters->CurrentDirectoryHandle;
3525 if (wincap.has_fast_cwd ())
3527 if (fast_cwd_ptr == (PFAST_CWD *) -1)
3529 find_fast_cwd_pointers ();
3531 system_printf ("WARNING: Couldn't compute FAST_CWD pointer. "
3532 "Please report this problem to\nthe public mailing "
3533 "list cygwin@cygwin.com");
3537 /* Default method starting with Vista. If we got a valid value for
3538 fast_cwd_ptr, we can simply replace the RtlSetCurrentDirectory_U
3539 function entirely, just as on pre-Vista. */
3540 PVOID heap = peb.ProcessHeap;
3541 /* First allocate a new FAST_CWD strcuture on the heap. */
3542 PFAST_CWD f_cwd = (PFAST_CWD)
3543 RtlAllocateHeap (heap, 0, sizeof (FAST_CWD));
3546 debug_printf ("RtlAllocateHeap failed");
3549 /* Fill in the values. */
3550 f_cwd->ReferenceCount = 1;
3551 f_cwd->DirectoryHandle = dir;
3552 f_cwd->OldDismountCount = old_dismount_count;
3553 RtlInitEmptyUnicodeString (&f_cwd->Path, f_cwd->Buffer,
3554 MAX_PATH * sizeof (WCHAR));
3555 copy_cwd_str (&f_cwd->Path, error ? &ro_u_pipedir : &win32);
3556 /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
3557 structure and writing the CWD to the user process parameter
3558 block. This is equivalent to calling RtlAcquirePebLock/
3559 RtlReleasePebLock, but without having to go through the FS
3561 RtlEnterCriticalSection (peb.FastPebLock);
3562 PFAST_CWD old_cwd = *fast_cwd_ptr;
3563 *fast_cwd_ptr = f_cwd;
3564 upp_cwd_str = f_cwd->Path;
3566 RtlLeaveCriticalSection (peb.FastPebLock);
3567 /* Decrement the reference count. If it's down to 0, free structure
3569 if (old_cwd && InterlockedDecrement (&old_cwd->ReferenceCount) == 0)
3571 /* In contrast to pre-Vista, the handle on init is always a fresh
3572 one and not the handle inherited from the parent process. So
3573 we always have to close it here. However, the handle could
3574 be NULL, if we cd'ed into a virtual dir. */
3575 if (old_cwd->DirectoryHandle)
3576 NtClose (old_cwd->DirectoryHandle);
3577 RtlFreeHeap (heap, 0, old_cwd);
3582 /* This is more a hack, and it's only used on Vista and later if we
3583 failed to find the fast_cwd_ptr value. What we do here is to call
3584 RtlSetCurrentDirectory_U and let it set up a new FAST_CWD
3585 structure. Afterwards, compute the address of that structure
3586 utilizing the fact that the buffer address in the user process
3587 parameter block is actually pointing to the buffer in that
3588 FAST_CWD structure. Then replace the directory handle in that
3589 structure with our own handle and close the original one.
3591 Note that the call to RtlSetCurrentDirectory_U also closes our
3592 old dir handle, so there won't be any handle left open.
3594 This method is prone to two race conditions:
3596 - Due to the way RtlSetCurrentDirectory_U opens the directory
3597 handle, the directory is locked against deletion or renaming
3598 between the RtlSetCurrentDirectory_U and the subsequent NtClose
3601 - When another thread calls SetCurrentDirectory at exactly the
3602 same time, a crash might occur, or worse, unrelated data could
3603 be overwritten or NtClose could be called on an unrelated handle.
3605 Therefore, use this *only* as a fallback. */
3608 status = RtlSetCurrentDirectory_U (error ? &ro_u_pipedir
3610 if (!NT_SUCCESS (status))
3612 debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %p",
3613 error ? &ro_u_pipedir : &win32, status);
3617 RtlEnterCriticalSection (peb.FastPebLock);
3618 PFAST_CWD f_cwd = (PFAST_CWD)
3619 ((PBYTE) upp_cwd_str.Buffer
3620 - __builtin_offsetof (struct _FAST_CWD, Buffer));
3622 f_cwd->DirectoryHandle = upp_cwd_hdl = dir;
3623 RtlLeaveCriticalSection (peb.FastPebLock);
3624 /* In contrast to pre-Vista, the handle on init is always a fresh one
3625 and not the handle inherited from the parent process. So we always
3626 have to close it here. */
3632 /* This method is used for all pre-Vista OSes. We simply set the values
3633 for the CWD in the user process parameter block entirely by ourselves
3634 under PEB lock condition. This is how RtlSetCurrentDirectory_U worked
3635 in these older OSes, so we're safe.
3637 Note that we can't just RtlEnterCriticalSection (peb.FastPebLock)
3638 on pre-Vista. RtlAcquirePebLock was way more complicated back then. */
3639 RtlAcquirePebLock ();
3641 copy_cwd_str (&upp_cwd_str, error ? &ro_u_pipedir : &win32);
3644 RtlReleasePebLock ();
3645 /* Only on init, the handle is potentially a native handle. However,
3646 if it's identical to dir, it's the inherited handle from a Cygwin
3647 parent process and must not be closed. */
3653 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
3657 cwd_lock.init ("cwd_lock");
3659 /* Cygwin processes inherit the cwd from their parent. If the win32 path
3660 buffer is not NULL, the cwd struct is already set up, and we only
3661 have to override the Win32 CWD with ours. */
3663 override_win32_cwd (true, SharedUserData.DismountCount);
3665 /* Initially re-open the cwd to allow POSIX semantics. */
3669 /* Chdir and fill out the elements of a cwdstuff struct. */
3671 cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
3674 UNICODE_STRING upath;
3675 PEB &peb = *NtCurrentTeb ()->Peb;
3676 bool virtual_path = false;
3677 bool unc_path = false;
3678 bool inaccessible_path = false;
3680 /* Here are the problems with using SetCurrentDirectory. Just skip this
3681 comment if you don't like whining.
3683 - SetCurrentDirectory only supports paths of up to MAX_PATH - 1 chars,
3684 including a trailing backslash. That's an absolute restriction, even
3687 - SetCurrentDirectory fails for directories with strict permissions even
3688 for processes with the SE_BACKUP_NAME privilege enabled. The reason
3689 is apparently that SetCurrentDirectory calls NtOpenFile without the
3690 FILE_OPEN_FOR_BACKUP_INTENT flag set.
3692 - SetCurrentDirectory does not support case-sensitivity.
3694 - Unlinking a cwd fails because SetCurrentDirectory seems to open
3695 directories so that deleting the directory is disallowed.
3697 - SetCurrentDirectory can naturally not work on virtual Cygwin paths
3698 like /proc or /cygdrive.
3700 Unfortunately, even though we have access to the Win32 process parameter
3701 block, we can't just replace the directory handle. Starting with Vista,
3702 the handle is used elsewhere, and just replacing the handle in the process
3703 parameter block shows quite surprising results.
3704 FIXME: If we ever find a *safe* way to replace the directory handle in
3705 the process parameter block, we're back in business.
3707 Nevertheless, doing entirely without SetCurrentDirectory is not really
3708 feasible, because it breaks too many mixed applications using the Win32
3711 Therefore we handle the CWD all by ourselves and just keep the Win32
3712 CWD in sync. However, to avoid surprising behaviour in the Win32 API
3713 when we are in a CWD which is inaccessible as Win32 CWD, we set the
3714 Win32 CWD to a "weird" directory in which all relative filesystem-related
3717 cwd_lock.acquire ();
3721 upath = *nat_cwd->get_nt_native_path ();
3722 if (nat_cwd->isspecial ())
3723 virtual_path = true;
3726 /* Memorize old DismountCount before opening the dir. This value is
3727 stored in the FAST_CWD structure on Vista and later. It would be
3728 simpler to fetch the old DismountCount in override_win32_cwd, but
3729 Windows also fetches it before opening the directory handle. It's
3730 not quite clear if that's really required, but since we don't know
3731 the side effects of this action, we better follow Windows' lead. */
3732 ULONG old_dismount_count = SharedUserData.DismountCount;
3733 /* Open a directory handle with FILE_OPEN_FOR_BACKUP_INTENT and with all
3734 sharing flags set. The handle is right now used in exceptions.cc only,
3735 but that might change in future. */
3740 OBJECT_ATTRIBUTES attr;
3744 /* On init, just reopen Win32 CWD with desired access flags.
3745 We can access the PEB without lock, because no other thread
3746 can change the CWD. */
3747 RtlInitUnicodeString (&upath, L"");
3748 InitializeObjectAttributes (&attr, &upath,
3749 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
3750 peb.ProcessParameters->CurrentDirectoryHandle, NULL);
3753 InitializeObjectAttributes (&attr, &upath,
3754 nat_cwd->objcaseinsensitive () | OBJ_INHERIT,
3756 /* First try without FILE_OPEN_FOR_BACKUP_INTENT, to find out if the
3757 directory is valid for Win32 apps. And, no, we can't just call
3758 SetCurrentDirectory here, since that would potentially break
3759 case-sensitivity. */
3760 status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
3761 FILE_SHARE_VALID_FLAGS,
3763 | FILE_SYNCHRONOUS_IO_NONALERT);
3764 if (status == STATUS_ACCESS_DENIED)
3766 status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
3767 FILE_SHARE_VALID_FLAGS,
3769 | FILE_SYNCHRONOUS_IO_NONALERT
3770 | FILE_OPEN_FOR_BACKUP_INTENT);
3771 inaccessible_path = true;
3773 if (!NT_SUCCESS (status))
3775 cwd_lock.release ();
3776 __seterrno_from_nt_status (status);
3780 /* Set new handle. Note that we simply overwrite the old handle here
3781 without closing it. The handle is also used as Win32 CWD handle in
3782 the user parameter block, and it will be closed in override_win32_cwd,
3788 /* On init, just fetch the Win32 dir from the PEB. We can access
3789 the PEB without lock, because no other thread can change the CWD
3791 PUNICODE_STRING pdir = &peb.ProcessParameters->CurrentDirectoryName;
3792 RtlInitEmptyUnicodeString (&win32,
3793 (PWCHAR) crealloc_abort (win32.Buffer,
3796 pdir->Length + sizeof (WCHAR));
3797 RtlCopyUnicodeString (&win32, pdir);
3799 PWSTR eoBuffer = win32.Buffer + (win32.Length / sizeof (WCHAR));
3800 /* Remove trailing slash if one exists. */
3801 if ((eoBuffer - win32.Buffer) > 3 && eoBuffer[-1] == L'\\')
3802 win32.Length -= sizeof (WCHAR);
3803 if (eoBuffer[0] == L'\\')
3810 if (virtual_path) /* don't mangle virtual path. */
3814 /* Compute length on Win32 path. */
3815 size_t len = upath.Length / sizeof (WCHAR) - 4;
3816 if (RtlEqualUnicodePathPrefix (&upath, &ro_u_uncp, TRUE))
3821 /* Convert to a Win32 path. */
3822 upath.Buffer += upath.Length / sizeof (WCHAR) - len;
3823 upath.Length = len * sizeof (WCHAR);
3825 PWSTR eoBuffer = upath.Buffer + (upath.Length / sizeof (WCHAR));
3826 /* Remove trailing slash if one exists. */
3827 if ((eoBuffer - upath.Buffer) > 3 && eoBuffer[-1] == L'\\')
3828 upath.Length -= sizeof (WCHAR);
3830 RtlInitEmptyUnicodeString (&win32,
3831 (PWCHAR) crealloc_abort (win32.Buffer,
3834 upath.Length + sizeof (WCHAR));
3835 RtlCopyUnicodeString (&win32, &upath);
3837 win32.Buffer[0] = L'\\';
3839 /* Make sure it's NUL-terminated. */
3840 win32.Buffer[win32.Length / sizeof (WCHAR)] = L'\0';
3842 /* Set drive_length, used in path conversion, and error code, used in
3843 spawn_guts to decide whether a native Win32 app can be started or not. */
3855 PWCHAR ptr = wcschr (win32.Buffer + 2, L'\\');
3857 ptr = wcschr (ptr + 1, L'\\');
3859 drive_length = ptr - win32.Buffer;
3861 drive_length = win32.Length / sizeof (WCHAR);
3863 if (inaccessible_path)
3865 else if (win32.Length > (MAX_PATH - 2) * sizeof (WCHAR))
3866 error = ENAMETOOLONG;
3870 /* Keep the Win32 CWD in sync. Don't check for error, other than for
3871 strace output. Try to keep overhead low. */
3872 override_win32_cwd (!nat_cwd, old_dismount_count);
3874 /* Eventually, create POSIX path if it's not set on entry. */
3878 posix_cwd = (const char *) tp.c_get ();
3879 mount_table->conv_to_posix_path (win32.Buffer, (char *) posix_cwd, 0);
3881 posix = (char *) crealloc_abort (posix, strlen (posix_cwd) + 1);
3882 stpcpy (posix, posix_cwd);
3884 cwd_lock.release ();
3889 cwdstuff::get_error_desc () const
3891 switch (cygheap->cwd.get_error ())
3894 return "has restricted permissions which render it\n"
3895 "inaccessible as Win32 working directory";
3897 return "is a virtual Cygwin directory which does\n"
3898 "not exist for a native Windows application";
3900 return "has a path longer than allowed for a\n"
3901 "Win32 working directory";
3905 /* That shouldn't occur, unless we defined a new error code
3906 in cwdstuff::set. */
3907 return "is not accessible for some unknown reason";
3910 /* Store incoming wchar_t path as current posix cwd. This is called from
3911 setlocale so that the cwd is always stored in the right charset. */
3913 cwdstuff::reset_posix (wchar_t *w_cwd)
3915 size_t len = sys_wcstombs (NULL, (size_t) -1, w_cwd);
3916 posix = (char *) crealloc_abort (posix, len + 1);
3917 sys_wcstombs (posix, len + 1, w_cwd);
3921 cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
3928 else if (buf == NULL)
3929 ulen = (unsigned) -1;
3936 cwd_lock.acquire ();
3941 tocopy = tp.c_get ();
3942 sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer,
3943 win32.Length / sizeof (WCHAR));
3948 debug_printf ("posix %s", posix);
3949 if (strlen (tocopy) >= ulen)
3957 buf = (char *) malloc (strlen (tocopy) + 1);
3958 strcpy (buf, tocopy);
3959 if (!buf[0]) /* Should only happen when chroot */
3963 cwd_lock.release ();
3966 syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
3967 buf, buf, ulen, need_posix, with_chroot, errno);
3972 int etc::curr_ix = 0;
3973 /* Note that the first elements of the below arrays are unused */
3974 bool etc::change_possible[MAX_ETC_FILES + 1];
3975 OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1];
3976 LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1];
3979 etc::init (int n, POBJECT_ATTRIBUTES attr)
3983 else if (++curr_ix <= MAX_ETC_FILES)
3986 api_fatal ("internal error");
3989 change_possible[n] = false;
3990 test_file_change (n);
3991 paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix);
3996 etc::test_file_change (int n)
3999 FILE_NETWORK_OPEN_INFORMATION fnoi;
4002 status = NtQueryFullAttributesFile (&fn[n], &fnoi);
4003 if (!NT_SUCCESS (status))
4006 memset (last_modified + n, 0, sizeof (last_modified[n]));
4007 debug_printf ("NtQueryFullAttributesFile (%S) failed, %p",
4008 fn[n].ObjectName, status);
4012 res = CompareFileTime ((FILETIME *) &fnoi.LastWriteTime,
4013 (FILETIME *) last_modified + n) > 0;
4014 last_modified[n].QuadPart = fnoi.LastWriteTime.QuadPart;
4017 paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4022 etc::dir_changed (int n)
4024 if (!change_possible[n])
4026 static HANDLE changed_h NO_COPY;
4032 OBJECT_ATTRIBUTES attr;
4034 path_conv dir ("/etc");
4035 status = NtOpenFile (&changed_h, SYNCHRONIZE | FILE_LIST_DIRECTORY,
4036 dir.get_object_attr (attr, sec_none_nih), &io,
4037 FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE);
4038 if (!NT_SUCCESS (status))
4041 system_printf ("NtOpenFile (%S) failed, %p",
4042 dir.get_nt_native_path (), status);
4044 changed_h = INVALID_HANDLE_VALUE;
4048 status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4050 FILE_NOTIFY_CHANGE_LAST_WRITE
4051 | FILE_NOTIFY_CHANGE_FILE_NAME,
4053 if (!NT_SUCCESS (status))
4056 system_printf ("NtNotifyChangeDirectoryFile (1) failed, %p",
4059 NtClose (changed_h);
4060 changed_h = INVALID_HANDLE_VALUE;
4063 memset (change_possible, true, sizeof (change_possible));
4066 if (changed_h == INVALID_HANDLE_VALUE)
4067 change_possible[n] = true;
4068 else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
4070 status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4072 FILE_NOTIFY_CHANGE_LAST_WRITE
4073 | FILE_NOTIFY_CHANGE_FILE_NAME,
4075 if (!NT_SUCCESS (status))
4078 system_printf ("NtNotifyChangeDirectoryFile (2) failed, %p",
4081 NtClose (changed_h);
4082 changed_h = INVALID_HANDLE_VALUE;
4084 memset (change_possible, true, sizeof change_possible);
4088 paranoid_printf ("fn[%d] %S change_possible %d",
4089 n, fn[n].ObjectName, change_possible[n]);
4090 return change_possible[n];
4094 etc::file_changed (int n)
4097 if (dir_changed (n) && test_file_change (n))
4099 change_possible[n] = false; /* Change is no longer possible */
4100 paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4104 /* No need to be reentrant or thread-safe according to SUSv3.
4105 / and \\ are treated equally. Leading drive specifiers are
4106 kept intact as far as it makes sense. Everything else is
4107 POSIX compatible. */
4109 basename (char *path)
4112 char *c, *d, *bs = path;
4114 if (!path || !*path)
4115 return strcpy (buf, ".");
4116 if (isalpha (path[0]) && path[1] == ':')
4118 else if (strspn (path, "/\\") > 1)
4120 c = strrchr (bs, '/');
4121 if ((d = strrchr (c ?: bs, '\\')) > c)
4125 /* Trailing (back)slashes are eliminated. */
4126 while (c && c > bs && c[1] == '\0')
4129 c = strrchr (bs, '/');
4130 if ((d = strrchr (c ?: bs, '\\')) > c)
4133 if (c && (c > bs || c[1]))
4138 stpncpy (buf, path, bs - path);
4139 stpcpy (buf + (bs - path), ".");
4145 /* No need to be reentrant or thread-safe according to SUSv3.
4146 / and \\ are treated equally. Leading drive specifiers and
4147 leading double (back)slashes are kept intact as far as it
4148 makes sense. Everything else is POSIX compatible. */
4150 dirname (char *path)
4153 char *c, *d, *bs = path;
4155 if (!path || !*path)
4156 return strcpy (buf, ".");
4157 if (isalpha (path[0]) && path[1] == ':')
4159 else if (strspn (path, "/\\") > 1)
4161 c = strrchr (bs, '/');
4162 if ((d = strrchr (c ?: bs, '\\')) > c)
4166 /* Trailing (back)slashes are eliminated. */
4167 while (c && c > bs && c[1] == '\0')
4170 c = strrchr (bs, '/');
4171 if ((d = strrchr (c ?: bs, '\\')) > c)
4178 /* More trailing (back)slashes are eliminated. */
4179 while (c > bs && (*c == '/' || *c == '\\'))
4187 stpncpy (buf, path, bs - path);
4188 stpcpy (buf + (bs - path), ".");