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"
60 #include <sys/cygwin.h>
67 #include "shared_info.h"
76 bool dos_file_warning = true;
78 suffix_info stat_suffixes[] =
81 suffix_info (".exe", 1),
87 char contents[SYMLINK_MAX + 1];
99 int check (char *path, const suffix_info *suffixes, fs_info &fs,
100 path_conv_handle &conv_hdl);
101 int set (char *path);
102 bool parse_device (const char *);
103 int check_sysfile (HANDLE h);
104 int check_shortcut (HANDLE h);
105 int check_reparse_point (HANDLE h);
106 int check_nfs_symlink (HANDLE h);
107 int posixify (char *srcbuf);
108 bool set_error (int);
111 muto NO_COPY cwdstuff::cwd_lock;
113 static const GUID GUID_shortcut
114 = { 0x00021401L, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
117 WSH_FLAG_IDLIST = 0x01, /* Contains an ITEMIDLIST. */
118 WSH_FLAG_FILE = 0x02, /* Contains a file locator element. */
119 WSH_FLAG_DESC = 0x04, /* Contains a description. */
120 WSH_FLAG_RELPATH = 0x08, /* Contains a relative path. */
121 WSH_FLAG_WD = 0x10, /* Contains a working dir. */
122 WSH_FLAG_CMDLINE = 0x20, /* Contains command line args. */
123 WSH_FLAG_ICON = 0x40 /* Contains a custom icon. */
126 struct win_shortcut_hdr
128 DWORD size; /* Header size in bytes. Must contain 0x4c. */
129 GUID magic; /* GUID of shortcut files. */
130 DWORD flags; /* Content flags. See above. */
132 /* The next fields from attr to icon_no are always set to 0 in Cygwin
133 and U/Win shortcuts. */
134 DWORD attr; /* Target file attributes. */
135 FILETIME ctime; /* These filetime items are never touched by the */
136 FILETIME mtime; /* system, apparently. Values don't matter. */
138 DWORD filesize; /* Target filesize. */
139 DWORD icon_no; /* Icon number. */
141 DWORD run; /* Values defined in winuser.h. Use SW_NORMAL. */
142 DWORD hotkey; /* Hotkey value. Set to 0. */
143 DWORD dummy[2]; /* Future extension probably. Always 0. */
146 /* Return non-zero if PATH1 is a prefix of PATH2.
147 Both are assumed to be of the same path style and / vs \ usage.
149 LEN1 = strlen (PATH1). It's passed because often it's already known.
152 /foo/ is a prefix of /foo <-- may seem odd, but desired
153 /foo is a prefix of /foo/
154 / is a prefix of /foo/bar
155 / is not a prefix of foo/bar
156 foo/ is a prefix foo/bar
157 /foo is not a prefix of /foobar
161 path_prefix_p (const char *path1, const char *path2, int len1,
162 bool caseinsensitive)
164 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
165 if (len1 > 0 && isdirsep (path1[len1 - 1]))
169 return isdirsep (path2[0]) && !isdirsep (path2[1]);
171 if (isdirsep (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':')
172 return caseinsensitive ? strncasematch (path1, path2, len1)
173 : !strncmp (path1, path2, len1);
178 /* Return non-zero if paths match in first len chars.
179 Check is dependent of the case sensitivity setting. */
181 pathnmatch (const char *path1, const char *path2, int len, bool caseinsensitive)
183 return caseinsensitive
184 ? strncasematch (path1, path2, len) : !strncmp (path1, path2, len);
187 /* Return non-zero if paths match. Check is dependent of the case
188 sensitivity setting. */
190 pathmatch (const char *path1, const char *path2, bool caseinsensitive)
192 return caseinsensitive
193 ? strcasematch (path1, path2) : !strcmp (path1, path2);
196 /* TODO: This function is used in mkdir and rmdir to generate correct
197 error messages in case of paths ending in /. or /.. components.
198 Right now, normalize_posix_path will just normalize
199 those components away, which changes the semantics. */
201 has_dot_last_component (const char *dir, bool test_dot_dot)
203 /* SUSv3: . and .. are not allowed as last components in various system
204 calls. Don't test for backslash path separator since that's a Win32
205 path following Win32 rules. */
206 const char *last_comp = strchr (dir, '\0');
208 if (last_comp == dir)
209 return false; /* Empty string. Probably shouldn't happen here? */
211 /* Detect run of trailing slashes */
212 while (last_comp > dir && *--last_comp == '/')
215 /* Detect just a run of slashes or a path that does not end with a slash. */
216 if (*last_comp != '.')
219 /* We know we have a trailing dot here. Check that it really is a standalone "."
220 path component by checking that it is at the beginning of the string or is
222 if (last_comp == dir || *--last_comp == '/')
225 /* If we're not checking for '..' we're done. Ditto if we're now pointing to
227 if (!test_dot_dot || *last_comp != '.')
228 return false; /* either not testing for .. or this was not '..' */
230 /* Repeat previous test for standalone or path component. */
231 return last_comp == dir || last_comp[-1] == '/';
234 /* Normalize a POSIX path.
235 All duplicate /'s, except for 2 leading /'s, are deleted.
236 The result is 0 for success, or an errno error value. */
239 normalize_posix_path (const char *src, char *dst, char *&tail)
241 const char *in_src = src;
242 char *dst_start = dst;
243 syscall_printf ("src %s", src);
245 if ((isdrive (src) && isdirsep (src[2])) || *src == '\\')
249 if (!isslash (src[0]))
251 if (!cygheap->cwd.get (dst))
253 tail = strchr (tail, '\0');
254 if (isslash (dst[0]) && isslash (dst[1]))
258 if (tail == dst_start + 1 && *dst_start == '/')
262 if (tail > dst && !isslash (tail[-1]))
265 /* Two leading /'s? If so, preserve them. */
266 else if (isslash (src[1]) && !isslash (src[2]))
276 /* Strip runs of /'s. */
297 if (!isslash (src[1]))
300 else if (src[2] && !isslash (src[2]))
304 while (tail > dst_start && !isslash (*--tail))
312 if ((tail - dst) >= NT_MAX_PATH)
314 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
322 debug_printf ("%s = normalize_posix_path (%s)", dst, in_src);
326 int err = normalize_win32_path (in_src, dst, tail);
328 for (char *p = dst; (p = strchr (p, '\\')); p++)
334 path_conv::add_ext_from_sym (symlink_info &sym)
336 if (sym.ext_here && *sym.ext_here)
338 known_suffix = path + sym.extn;
339 if (sym.ext_tacked_on)
340 strcpy ((char *) known_suffix, sym.ext_here);
344 static void __stdcall mkrelpath (char *dst, bool caseinsensitive)
345 __attribute__ ((regparm (2)));
347 static void __stdcall
348 mkrelpath (char *path, bool caseinsensitive)
351 char *cwd_win32 = tp.c_get ();
352 if (!cygheap->cwd.get (cwd_win32, 0))
355 unsigned cwdlen = strlen (cwd_win32);
356 if (!path_prefix_p (cwd_win32, path, cwdlen, caseinsensitive))
359 size_t n = strlen (path);
367 tail += isdirsep (cwd_win32[cwdlen - 1]) ? cwdlen : cwdlen + 1;
369 memmove (path, tail, strlen (tail) + 1);
375 path_conv::set_normalized_path (const char *path_copy)
379 size_t n = strlen (path_copy) + 1;
380 char *p = (char *) crealloc_abort ((void *) normalized_path, n);
381 normalized_path = (const char *) memcpy (p, path_copy, n);
386 str2uni_cat (UNICODE_STRING &tgt, const char *srcstr)
388 int len = sys_mbstowcs (tgt.Buffer + tgt.Length / sizeof (WCHAR),
389 (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR),
392 tgt.Length += (len - 1) * sizeof (WCHAR);
396 get_nt_native_path (const char *path, UNICODE_STRING& upath, bool dos)
399 if (path[0] == '/') /* special path w/o NT path representation. */
400 str2uni_cat (upath, path);
401 else if (path[0] != '\\') /* X:\... or relative path. */
403 if (path[1] == ':') /* X:\... */
405 RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
406 str2uni_cat (upath, path);
407 /* The drive letter must be upper case. */
408 upath.Buffer[4] = towupper (upath.Buffer[4]);
411 str2uni_cat (upath, path);
412 transform_chars (&upath, 7);
414 else if (path[1] != '\\') /* \Device\... */
415 str2uni_cat (upath, path);
416 else if ((path[2] != '.' && path[2] != '?')
417 || path[3] != '\\') /* \\server\share\... */
419 RtlAppendUnicodeStringToString (&upath, &ro_u_uncp);
420 str2uni_cat (upath, path + 2);
421 transform_chars (&upath, 8);
423 else /* \\.\device or \\?\foo */
425 RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
426 str2uni_cat (upath, path + 4);
430 /* Unfortunately we can't just use transform_chars with the tfx_rev_chars
431 table since only leading and trailing spaces and dots are affected.
432 So we step to every backslash and fix surrounding dots and spaces.
433 That makes these broken filesystems a bit slower, but, hey. */
434 PWCHAR cp = upath.Buffer + 7;
435 PWCHAR cend = upath.Buffer + upath.Length / sizeof (WCHAR);
440 while (*ccp == L'.' || *ccp == L' ')
442 while (cp[1] == L' ')
445 while (*--cp == L'.' || *cp == L' ')
452 path_conv::get_nt_native_path ()
462 uni_path.MaximumLength = (strlen (path) + 10) * sizeof (WCHAR);
463 wide_path = (PWCHAR) cmalloc_abort (HEAP_STR, uni_path.MaximumLength);
464 uni_path.Buffer = wide_path;
465 ::get_nt_native_path (path, uni_path, has_dos_filenames_only ());
472 path_conv::get_wide_win32_path (PWCHAR wc)
474 get_nt_native_path ();
477 wcpcpy (wc, wide_path);
484 warn_msdos (const char *src)
486 if (user_shared->warned_msdos || !dos_file_warning || !cygwin_finished_initializing)
489 char *posix_path = tp.c_get ();
490 small_printf ("cygwin warning:\n");
491 if (cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, src,
492 posix_path, NT_MAX_PATH))
493 small_printf (" MS-DOS style path detected: %ls\n POSIX equivalent preferred.\n",
496 small_printf (" MS-DOS style path detected: %ls\n Preferred POSIX equivalent is: %ls\n",
498 small_printf (" CYGWIN environment variable option \"nodosfilewarning\" turns off this warning.\n"
499 " Consult the user's guide for more details about POSIX paths:\n"
500 " http://cygwin.com/cygwin-ug-net/using.html#using-pathnames\n");
501 user_shared->warned_msdos = true;
505 getfileattr (const char *path, bool caseinsensitive) /* path has to be always absolute. */
508 UNICODE_STRING upath;
509 OBJECT_ATTRIBUTES attr;
510 FILE_BASIC_INFORMATION fbi;
515 InitializeObjectAttributes (&attr, &upath,
516 caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
518 get_nt_native_path (path, upath, false);
520 status = NtQueryAttributesFile (&attr, &fbi);
521 if (NT_SUCCESS (status))
522 return fbi.FileAttributes;
524 if (status != STATUS_OBJECT_NAME_NOT_FOUND
525 && status != STATUS_NO_SUCH_FILE) /* File not found on 9x share */
527 /* File exists but access denied. Try to get attribute through
529 UNICODE_STRING dirname, basename;
531 FILE_BOTH_DIRECTORY_INFORMATION fdi;
533 RtlSplitUnicodePath (&upath, &dirname, &basename);
534 InitializeObjectAttributes (&attr, &dirname,
535 caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
537 status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
538 &attr, &io, FILE_SHARE_VALID_FLAGS,
539 FILE_SYNCHRONOUS_IO_NONALERT
540 | FILE_OPEN_FOR_BACKUP_INTENT
541 | FILE_DIRECTORY_FILE);
542 if (NT_SUCCESS (status))
544 status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io,
546 FileBothDirectoryInformation,
547 TRUE, &basename, TRUE);
549 if (NT_SUCCESS (status) || status == STATUS_BUFFER_OVERFLOW)
550 return fdi.FileAttributes;
553 SetLastError (RtlNtStatusToDosError (status));
554 return INVALID_FILE_ATTRIBUTES;
557 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
558 passing to Win32 API routines.
560 If an error occurs, `error' is set to the errno value.
561 Otherwise it is set to 0.
564 SYMLINK_FOLLOW - convert to PATH symlink points to
565 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
566 SYMLINK_IGNORE - do not check PATH for symlinks
567 SYMLINK_CONTENTS - just return symlink contents
570 /* TODO: This implementation is only preliminary. For internal
571 purposes it's necessary to have a path_conv::check function which
572 takes a UNICODE_STRING src path, otherwise we waste a lot of time
573 for converting back and forth. The below implementation does
574 realy nothing but converting to char *, until path_conv handles
575 wide-char paths directly. */
577 path_conv::check (const UNICODE_STRING *src, unsigned opt,
578 const suffix_info *suffixes)
581 char *path = tp.c_get ();
583 user_shared->warned_msdos = true;
584 sys_wcstombs (path, NT_MAX_PATH, src->Buffer, src->Length / sizeof (WCHAR));
585 path_conv::check (path, opt, suffixes);
589 path_conv::check (const char *src, unsigned opt,
590 const suffix_info *suffixes)
592 /* The tmp_buf array is used when expanding symlinks. It is NT_MAX_PATH * 2
593 in length so that we can hold the expanded symlink plus a trailer. */
595 char *path_copy = tp.c_get ();
596 char *pathbuf = tp.c_get ();
597 char *tmp_buf = tp.t_get ();
598 char *THIS_path = tp.c_get ();
600 bool need_directory = 0;
601 bool saw_symlinks = 0;
602 bool add_ext = false;
604 char *tail, *path_end;
607 static path_conv last_path_conv;
608 static char last_src[CYG_MAX_PATH];
610 if (*last_src && strcmp (last_src, src) == 0)
612 *this = last_path_conv;
618 if (efault.faulted ())
626 fileattr = INVALID_FILE_ATTRIBUTES;
627 caseinsensitive = OBJ_CASE_INSENSITIVE;
633 cfree (modifiable_path ());
636 close_conv_handle ();
637 memset (&dev, 0, sizeof (dev));
641 cfree ((void *) normalized_path);
642 normalized_path = NULL;
644 int component = 0; // Number of translated components
646 if (!(opt & PC_NULLEMPTY))
654 bool is_msdos = false;
655 /* This loop handles symlink expansion. */
661 is_relpath = !isabspath (src);
662 error = normalize_posix_path (src, path_copy, tail);
672 /* Detect if the user was looking for a directory. We have to strip the
673 trailing slash initially while trying to add extensions but take it
674 into account during processing */
675 if (tail > path_copy + 2 && isslash (tail[-1]))
682 /* Scan path_copy from right to left looking either for a symlink
683 or an actual existing file. If an existing file is found, just
684 return. If a symlink is found, exit the for loop.
685 Also: be careful to preserve the errno returned from
686 symlink.check as the caller may need it. */
687 /* FIXME: Do we have to worry about multiple \'s here? */
688 component = 0; // Number of translated components
689 sym.contents[0] = '\0';
693 for (unsigned pflags_or = opt & (PC_NO_ACCESS_CHECK | PC_KEEP_HANDLE);
697 const suffix_info *suff;
700 /* Don't allow symlink.check to set anything in the path_conv
701 class if we're working on an inner component of the path */
710 full_path = THIS_path;
713 /* Convert to native path spec sans symbolic link info. */
714 error = mount_table->conv_to_win32_path (path_copy, full_path, dev,
720 sym.pflags |= pflags_or;
722 if (dev.get_major () == DEV_CYGDRIVE_MAJOR)
725 fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY;
728 fileattr = getfileattr (THIS_path,
729 sym.pflags & MOUNT_NOPOSIX);
734 else if (dev == FH_DEV)
738 fileattr = getfileattr (THIS_path, sym.pflags & MOUNT_NOPOSIX);
739 if (!component && fileattr == INVALID_FILE_ATTRIBUTES)
741 fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY;
746 else if (isvirtual_dev (dev))
748 /* FIXME: Calling build_fhandler here is not the right way to handle this. */
749 fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy);
750 virtual_ftype_t file_type = fh->exists ();
751 if (file_type == virt_symlink)
754 symlen = sym.set (fh->get_filebuf ());
762 fileattr = FILE_ATTRIBUTE_DIRECTORY;
769 goto is_virtual_symlink;
786 /* Access to real file or directory via block device
787 entry in /proc/sys. Convert to real file and go with
790 goto is_fs_via_procsys;
792 /* Block special device. If the trailing slash has been
793 requested, the target is the root directory of the
794 filesystem on this block device. So we convert this to
795 a real file and attach the backslash. */
796 if (component == 0 && need_directory)
799 strcat (full_path, "\\");
800 fileattr = FILE_ATTRIBUTE_DIRECTORY
801 | FILE_ATTRIBUTE_DEVICE;
807 fileattr = FILE_ATTRIBUTE_DEVICE;
811 fileattr = INVALID_FILE_ATTRIBUTES;
812 goto virtual_component_retry;
814 if (component == 0 || dev != FH_NETDRIVE)
815 path_flags |= PATH_RO;
818 /* devn should not be a device. If it is, then stop parsing now. */
819 else if (dev != FH_FS)
822 path_flags = sym.pflags;
828 goto out; /* Found a device. Stop parsing. */
831 /* If path is only a drivename, Windows interprets it as the
832 current working directory on this drive instead of the root
833 dir which is what we want. So we need the trailing backslash
835 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
841 /* If the incoming path was given in DOS notation, always treat
842 it as caseinsensitive,noacl path. This must be set before
843 calling sym.check, otherwise the path is potentially treated
846 sym.pflags |= PATH_NOPOSIX | PATH_NOACL;
850 symlen = sym.check (full_path, suff, fs, conv_handle);
861 dev.parse (sym.major, sym.minor);
864 fileattr = sym.fileattr;
868 if (sym.pflags & PATH_SOCKET)
875 fileattr = sym.fileattr;
883 fileattr = sym.fileattr;
884 path_flags = sym.pflags;
887 /* If symlink.check found an existing non-symlink file, then
888 it sets the appropriate flag. It also sets any suffix found
890 if (!sym.issymlink && sym.fileattr != INVALID_FILE_ATTRIBUTES)
895 else if (!(sym.fileattr & FILE_ATTRIBUTE_DIRECTORY))
900 goto out; // file found
902 /* Found a symlink if symlen > 0. If component == 0, then the
903 src path itself was a symlink. If !follow_mode then
904 we're done. Otherwise we have to insert the path found
905 into the full path that we are building and perform all of
906 these operations again on the newly derived path. */
910 if (component == 0 && !need_directory
911 && (!(opt & PC_SYM_FOLLOW)
912 || (is_rep_symlink () && (opt & PC_SYM_NOFOLLOW_REP))))
914 set_symlink (symlen); // last component of path is a symlink.
915 if (opt & PC_SYM_CONTENTS)
917 strcpy (THIS_path, sym.contents);
923 /* Following a symlink we can't trust the collected filesystem
924 information any longer. */
926 /* Close handle, if we have any. Otherwise we're collecting
927 handles while following symlinks. */
928 conv_handle.close ();
931 else if (sym.error && sym.error != ENOENT)
936 /* No existing file found. */
938 virtual_component_retry:
939 /* Find the new "tail" of the path, e.g. in '/for/bar/baz',
941 if (tail != path_end)
943 while (--tail > path_copy + 1 && *tail != '/') {}
944 /* Exit loop if there is no tail or we are at the
945 beginning of a UNC path */
946 if (tail <= path_copy + 1)
947 goto out; // all done
949 /* Haven't found an existing pathname component yet.
950 Pinch off the tail and try again. */
955 /* Arrive here if above loop detected a symlink. */
956 if (++loop > SYMLOOP_MAX)
958 error = ELOOP; // Eep.
965 /* Place the link content, possibly with head and/or tail, in tmp_buf */
968 if (isabspath (sym.contents))
969 headptr = tmp_buf; /* absolute path */
972 /* Copy the first part of the path (with ending /) and point to the end. */
973 char *prevtail = tail;
974 while (--prevtail > path_copy && *prevtail != '/') {}
975 int headlen = prevtail - path_copy + 1;;
976 memcpy (tmp_buf, path_copy, headlen);
977 headptr = &tmp_buf[headlen];
980 /* Make sure there is enough space */
981 if (headptr + symlen >= tmp_buf + (2 * NT_MAX_PATH))
984 error = ENAMETOOLONG;
985 set_path ("::ENAMETOOLONG::");
989 /* Copy the symlink contents to the end of tmp_buf.
991 for (char *p = sym.contents; *p; p++)
992 *headptr++ = *p == '\\' ? '/' : *p;
995 /* Copy any tail component (with the 0) */
996 if (tail++ < path_end)
998 /* Add a slash if needed. There is space. */
999 if (*(headptr - 1) != '/')
1001 int taillen = path_end - tail + 1;
1002 if (headptr + taillen > tmp_buf + (2 * NT_MAX_PATH))
1004 memcpy (headptr, tail, taillen);
1007 /* Evaluate everything all over again. */
1011 if (!(opt & PC_SYM_CONTENTS))
1015 set_path (THIS_path);
1017 add_ext_from_sym (sym);
1018 if (dev == FH_NETDRIVE && component)
1020 /* This case indicates a non-existant resp. a non-retrievable
1021 share. This happens for instance if the share is a printer.
1022 In this case the path must not be treated like a FH_NETDRIVE,
1023 but like a FH_FS instead, so the usual open call for files
1027 else if (isproc_dev (dev) && fileattr == INVALID_FILE_ATTRIBUTES)
1029 /* FIXME: Usually we don't set error to ENOENT if a file doesn't
1030 exist. This is typically indicated by the fileattr content.
1031 So, why here? The downside is that cygwin_conv_path just gets
1032 an error for these paths so it reports the error back to the
1033 application. Unlike in all other cases of non-existant files,
1034 for which check doesn't set error, so cygwin_conv_path just
1035 returns the path, as intended. */
1039 else if (!need_directory || error)
1040 /* nothing to do */;
1041 else if (fileattr == INVALID_FILE_ATTRIBUTES)
1042 strcat (modifiable_path (), "\\"); /* Reattach trailing dirsep in native path. */
1043 else if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
1044 path_flags &= ~PATH_SYMLINK;
1047 debug_printf ("%s is a non-directory", path);
1054 if (strncmp (path, "\\\\.\\", 4))
1056 if (!tail || tail == path)
1058 else if (tail[-1] != '\\')
1067 /* If FS hasn't been checked already in symlink_info::check, do so now. */
1068 if (fs.inited ()|| fs.update (get_nt_native_path (), NULL))
1070 /* Incoming DOS paths are treated like DOS paths in native
1071 Windows applications. No ACLs, just default settings. */
1073 fs.has_acls (false);
1074 debug_printf ("this->path(%s), has_acls(%d)", path, fs.has_acls ());
1075 /* CV: We could use this->has_acls() but I want to make sure that
1076 we don't forget that the PATH_NOACL flag must be taken into
1078 if (!(path_flags & PATH_NOACL) && fs.has_acls ())
1079 set_exec (0); /* We really don't know if this is executable or not here
1080 but set it to not executable since it will be figured out
1081 later by anything which cares about this. */
1083 /* If the FS has been found to have unrelibale inodes, note
1084 that in path_flags. */
1085 if (!fs.hasgood_inode ())
1086 path_flags |= PATH_IHASH;
1087 /* If the OS is caseinsensitive or the FS is caseinsensitive,
1088 don't handle path casesensitive. */
1089 if (cygwin_shared->obcaseinsensitive || fs.caseinsensitive ())
1090 path_flags |= PATH_NOPOSIX;
1091 caseinsensitive = (path_flags & PATH_NOPOSIX)
1092 ? OBJ_CASE_INSENSITIVE : 0;
1093 if (exec_state () != dont_know_if_executable)
1097 else if (issymlink () || issocket ())
1101 if (opt & PC_NOFULL)
1105 mkrelpath (this->modifiable_path (), !!caseinsensitive);
1106 /* Invalidate wide_path so that wide relpath can be created
1107 in later calls to get_nt_native_path or get_wide_win32_path. */
1114 size_t n = strlen (this->path);
1115 /* Do not add trailing \ to UNC device names like \\.\a: */
1116 if (this->path[n - 1] != '\\' &&
1117 (strncmp (this->path, "\\\\.\\", 4) != 0))
1119 this->modifiable_path ()[n] = '\\';
1120 this->modifiable_path ()[n + 1] = '\0';
1126 set_has_symlinks ();
1129 path_flags |= PATH_OPEN;
1132 path_flags |= PATH_CTTY;
1134 if ((opt & PC_POSIX))
1136 if (tail < path_end && tail > path_copy + 1)
1138 set_normalized_path (path_copy);
1139 if (is_msdos && !(opt & PC_NOWARN))
1146 last_path_conv = *this;
1147 strcpy (last_src, src);
1152 path_conv::~path_conv ()
1154 if (normalized_path)
1156 cfree ((void *) normalized_path);
1157 normalized_path = NULL;
1161 cfree (modifiable_path ());
1169 close_conv_handle ();
1173 path_conv::is_binary ()
1176 PWCHAR bintest = tp.w_get ();
1179 return GetBinaryTypeW (get_wide_win32_path (bintest), &bin)
1180 && (bin == SCS_32BIT_BINARY || bin == SCS_64BIT_BINARY);
1183 /* Normalize a Win32 path.
1184 /'s are converted to \'s in the process.
1185 All duplicate \'s, except for 2 leading \'s, are deleted.
1187 The result is 0 for success, or an errno error value.
1188 FIXME: A lot of this should be mergeable with the POSIX critter. */
1190 normalize_win32_path (const char *src, char *dst, char *&tail)
1192 const char *src_start = src;
1193 bool beg_src_slash = isdirsep (src[0]);
1196 /* Skip long path name prefixes in Win32 or NT syntax. */
1197 if (beg_src_slash && (src[1] == '?' || isdirsep (src[1]))
1198 && src[2] == '?' && isdirsep (src[3]))
1201 if (src[1] != ':') /* native UNC path */
1202 src += 2; /* Fortunately the first char is not copied... */
1204 beg_src_slash = false;
1206 if (beg_src_slash && isdirsep (src[1]))
1208 if (isdirsep (src[2]))
1210 /* More than two slashes are just folded into one. */
1212 while (isdirsep (src[1]))
1217 /* Two slashes start a network or device path. */
1220 if (src[1] == '.' && isdirsep (src[2]))
1231 /* Always convert drive letter to uppercase for case sensitivity. */
1232 *tail++ = cyg_toupper (*src++);
1233 else if (*src != '/')
1236 tail += cygheap->cwd.get_drive (dst);
1237 else if (!cygheap->cwd.get (dst, 0))
1238 return get_errno ();
1241 tail = strchr (tail, '\0');
1242 if (tail[-1] != '\\')
1250 /* Strip duplicate /'s. */
1251 if (isdirsep (src[0]) && isdirsep (src[1]))
1254 else if (src[0] == '.' && isdirsep (src[1])
1255 && (src == src_start || isdirsep (src[-1])))
1258 /* Backup if "..". */
1259 else if (src[0] == '.' && src[1] == '.'
1260 /* dst must be greater than dst_start */
1261 && tail[-1] == '\\')
1263 if (!isdirsep (src[2]) && src[2] != '\0')
1267 /* Back up over /, but not if it's the first one. */
1270 /* Now back up to the next /. */
1271 while (tail > dst + 1 && tail[-1] != '\\' && tail[-2] != ':')
1274 /* Skip /'s to the next path component. */
1275 while (isdirsep (*src))
1279 /* Otherwise, add char to result. */
1288 if ((tail - dst) >= NT_MAX_PATH)
1289 return ENAMETOOLONG;
1291 if (tail > dst + 1 && tail[-1] == '.' && tail[-2] == '\\')
1294 debug_printf ("%s = normalize_win32_path (%s)", dst, src_start);
1298 /* Various utilities. */
1300 /* nofinalslash: Remove trailing / and \ from SRC (except for the
1301 first one). It is ok for src == dst. */
1304 nofinalslash (const char *src, char *dst)
1306 int len = strlen (src);
1308 memcpy (dst, src, len + 1);
1309 while (len > 1 && isdirsep (dst[--len]))
1313 /* conv_path_list: Convert a list of path names to/from Win32/POSIX. */
1316 conv_path_list (const char *src, char *dst, size_t size,
1317 cygwin_conv_path_t what)
1320 char src_delim, dst_delim;
1322 bool env_cvt = false;
1324 if (what == (cygwin_conv_path_t) ENV_CVT)
1326 what = CCP_WIN_A_TO_POSIX | CCP_RELATIVE;
1329 if (what & CCP_WIN_A_TO_POSIX)
1341 len = strlen (src) + 1;
1342 if (len <= NT_MAX_PATH * sizeof (WCHAR))
1343 srcbuf = (char *) tp.w_get ();
1345 srcbuf = (char *) alloca (len);
1349 bool saw_empty = false;
1352 char *srcpath = srcbuf;
1353 char *s = strccpy (srcpath, &src, src_delim);
1354 size_t len = s - srcpath;
1355 if (len >= NT_MAX_PATH)
1360 /* Paths in Win32 path lists in the environment (%Path%), are often
1361 enclosed in quotes (usually paths with spaces). Trailing backslashes
1362 are common, too. Remove them. */
1365 if (*srcpath == '"')
1371 while (len && s[-1] == '\\')
1380 err = cygwin_conv_path (what, srcpath, d, size - (d - dst));
1382 else if ((what & CCP_CONVTYPE_MASK) == CCP_POSIX_TO_WIN_A)
1385 err = cygwin_conv_path (what, ".", d, size - (d - dst));
1395 d = strchr (d, '\0');
1409 /********************** Symbolic Link Support **************************/
1411 /* Create a symlink from FROMPATH to TOPATH. */
1413 /* If TRUE create symlinks as Windows shortcuts, if false create symlinks
1414 as normal files with magic number and system bit set. */
1415 bool allow_winsymlinks = false;
1418 symlink (const char *oldpath, const char *newpath)
1420 return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
1424 symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
1429 path_conv win32_newpath, win32_oldpath;
1431 SECURITY_ATTRIBUTES sa = sec_none_nih;
1432 OBJECT_ATTRIBUTES attr;
1436 ULONG access = DELETE | FILE_GENERIC_WRITE;
1439 bool mk_winsym = use_winsym;
1440 bool has_trailing_dirsep = false;
1442 /* POSIX says that empty 'newpath' is invalid input while empty
1443 'oldpath' is valid -- it's symlink resolver job to verify if
1444 symlink contents point to existing filesystem object */
1446 if (efault.faulted (EFAULT))
1448 if (!*oldpath || !*newpath)
1454 if (strlen (oldpath) > SYMLINK_MAX)
1456 set_errno (ENAMETOOLONG);
1460 /* Trailing dirsep is a no-no. */
1461 len = strlen (newpath);
1462 has_trailing_dirsep = isdirsep (newpath[len - 1]);
1463 if (has_trailing_dirsep)
1465 newpath = strdup (newpath);
1466 ((char *) newpath)[len - 1] = '\0';
1469 check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0);
1470 /* We need the normalized full path below. */
1471 win32_newpath.check (newpath, check_opt, stat_suffixes);
1472 /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O
1473 attribute. Therefore we create symlinks on MVFS always as shortcuts. */
1474 mk_winsym |= win32_newpath.fs_is_mvfs ();
1476 if (mk_winsym && !win32_newpath.exists ()
1477 && (isdevice || !win32_newpath.fs_is_nfs ()))
1479 char *newplnk = tp.c_get ();
1480 stpcpy (stpcpy (newplnk, newpath), ".lnk");
1481 win32_newpath.check (newplnk, check_opt);
1484 if (win32_newpath.error)
1486 set_errno (win32_newpath.error);
1490 syscall_printf ("symlink (%s, %S)", oldpath,
1491 win32_newpath.get_nt_native_path ());
1493 if ((!isdevice && win32_newpath.exists ())
1494 || win32_newpath.is_auto_device ())
1499 if (has_trailing_dirsep && !win32_newpath.exists ())
1505 if (!isdevice && win32_newpath.fs_is_nfs ())
1507 /* On NFS, create symlinks by calling NtCreateFile with an EA of type
1508 NfsSymlinkTargetName containing ... the symlink target name. */
1509 PFILE_FULL_EA_INFORMATION pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1510 pffei->NextEntryOffset = 0;
1512 pffei->EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1513 char *EaValue = stpcpy (pffei->EaName, NFS_SYML_TARGET) + 1;
1514 pffei->EaValueLength = sizeof (WCHAR) *
1515 (sys_mbstowcs ((PWCHAR) EaValue, NT_MAX_PATH, oldpath) - 1);
1516 status = NtCreateFile (&fh, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE,
1517 win32_newpath.get_object_attr (attr, sa),
1518 &io, NULL, FILE_ATTRIBUTE_SYSTEM,
1519 FILE_SHARE_VALID_FLAGS, FILE_CREATE,
1520 FILE_SYNCHRONOUS_IO_NONALERT
1521 | FILE_OPEN_FOR_BACKUP_INTENT,
1522 pffei, NT_MAX_PATH * sizeof (WCHAR));
1523 if (!NT_SUCCESS (status))
1525 __seterrno_from_nt_status (status);
1535 ITEMIDLIST *pidl = NULL;
1536 size_t full_len = 0;
1537 unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
1538 char desc[MAX_PATH + 1], *relpath;
1542 /* First create an IDLIST to learn how big our shortcut is
1546 /* The symlink target is relative to the directory in which
1547 the symlink gets created, not relative to the cwd. Therefore
1548 we have to mangle the path quite a bit before calling path_conv. */
1549 if (isabspath (oldpath))
1550 win32_oldpath.check (oldpath,
1555 len = strrchr (win32_newpath.normalized_path, '/')
1556 - win32_newpath.normalized_path + 1;
1557 char *absoldpath = tp.t_get ();
1558 stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
1560 win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1562 if (SUCCEEDED (SHGetDesktopFolder (&psl)))
1564 WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
1565 win32_oldpath.get_wide_win32_path (wc_path);
1566 /* Amazing but true: Even though the ParseDisplayName method
1567 takes a wide char path name, it does not understand the
1568 Win32 prefix for long pathnames! So we have to tack off
1569 the prefix and convert the path to the "normal" syntax
1570 for ParseDisplayName. */
1571 WCHAR *wc = wc_path + 4;
1572 if (wc[1] != L':') /* native UNC path */
1575 if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
1580 for (p = pidl; p->mkid.cb > 0;
1581 p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
1583 pidl_len = (char *) p - (char *) pidl + 2;
1588 /* Compute size of shortcut file. */
1589 full_len = sizeof (win_shortcut_hdr);
1591 full_len += sizeof (unsigned short) + pidl_len;
1592 oldpath_len = strlen (oldpath);
1593 /* Unfortunately the length of the description is restricted to a
1594 length of MAX_PATH up to NT4, and to a length of 2000 bytes
1595 since W2K. We don't want to add considerations for the different
1596 lengths and even 2000 bytes is not enough for long path names.
1597 So what we do here is to set the description to the POSIX path
1598 only if the path is not longer than MAX_PATH characters. We
1599 append the full path name after the regular shortcut data
1600 (see below), which works fine with Windows Explorer as well
1601 as older Cygwin versions (as long as the whole file isn't bigger
1602 than 8K). The description field is only used for backward
1603 compatibility to older Cygwin versions and those versions are
1604 not capable of handling long path names anyway. */
1605 desc_len = stpcpy (desc, oldpath_len > MAX_PATH
1606 ? "[path too long]" : oldpath) - desc;
1607 full_len += sizeof (unsigned short) + desc_len;
1608 /* Devices get the oldpath string unchanged as relative path. */
1611 relpath_len = oldpath_len;
1612 stpcpy (relpath = tp.c_get (), oldpath);
1616 relpath_len = strlen (win32_oldpath.get_win32 ());
1617 stpcpy (relpath = tp.c_get (), win32_oldpath.get_win32 ());
1619 full_len += sizeof (unsigned short) + relpath_len;
1620 full_len += sizeof (unsigned short) + oldpath_len;
1621 /* 1 byte more for trailing 0 written by stpcpy. */
1622 if (full_len < NT_MAX_PATH * sizeof (WCHAR))
1623 buf = (char *) tp.w_get ();
1625 buf = (char *) alloca (full_len + 1);
1627 /* Create shortcut header */
1628 win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf;
1629 memset (shortcut_header, 0, sizeof *shortcut_header);
1630 shortcut_header->size = sizeof *shortcut_header;
1631 shortcut_header->magic = GUID_shortcut;
1632 shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH);
1634 shortcut_header->flags |= WSH_FLAG_IDLIST;
1635 shortcut_header->run = SW_NORMAL;
1636 cp = buf + sizeof (win_shortcut_hdr);
1641 *(unsigned short *)cp = pidl_len;
1642 memcpy (cp += 2, pidl, pidl_len);
1644 CoTaskMemFree (pidl);
1647 /* Create description */
1648 *(unsigned short *)cp = desc_len;
1649 cp = stpcpy (cp += 2, desc);
1651 /* Create relpath */
1652 *(unsigned short *)cp = relpath_len;
1653 cp = stpcpy (cp += 2, relpath);
1655 /* Append the POSIX path after the regular shortcut data for
1656 the long path support. */
1657 unsigned short *plen = (unsigned short *) cp;
1659 *(PWCHAR) cp = 0xfeff; /* BOM */
1661 *plen = sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1666 /* Default technique creating a symlink. */
1667 buf = (char *) tp.w_get ();
1668 cp = stpcpy (buf, SYMLINK_COOKIE);
1669 *(PWCHAR) cp = 0xfeff; /* BOM */
1671 /* Note that the terminating nul is written. */
1672 cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1675 if (isdevice && win32_newpath.exists ())
1677 status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
1678 win32_newpath.get_object_attr (attr, sa),
1679 &io, 0, FILE_OPEN_FOR_BACKUP_INTENT);
1680 if (!NT_SUCCESS (status))
1682 __seterrno_from_nt_status (status);
1685 status = NtSetAttributesFile (fh, FILE_ATTRIBUTE_NORMAL);
1687 if (!NT_SUCCESS (status))
1689 __seterrno_from_nt_status (status);
1693 else if (!isdevice && win32_newpath.has_acls () && !win32_newpath.isremote ())
1694 /* If the filesystem supports ACLs, we will overwrite the DACL after the
1695 call to NtCreateFile. This requires a handle with READ_CONTROL and
1696 WRITE_DAC access, otherwise get_file_sd and set_file_sd both have to
1697 open the file again.
1698 FIXME: On remote NTFS shares open sometimes fails because even the
1699 creator of the file doesn't have the right to change the DACL.
1700 I don't know what setting that is or how to recognize such a share,
1701 so for now we don't request WRITE_DAC on remote drives. */
1702 access |= READ_CONTROL | WRITE_DAC;
1704 status = NtCreateFile (&fh, access, win32_newpath.get_object_attr (attr, sa),
1705 &io, NULL, FILE_ATTRIBUTE_NORMAL,
1706 FILE_SHARE_VALID_FLAGS,
1707 isdevice ? FILE_OVERWRITE_IF : FILE_CREATE,
1708 FILE_SYNCHRONOUS_IO_NONALERT
1709 | FILE_NON_DIRECTORY_FILE
1710 | FILE_OPEN_FOR_BACKUP_INTENT,
1712 if (!NT_SUCCESS (status))
1714 __seterrno_from_nt_status (status);
1717 if (win32_newpath.has_acls ())
1718 set_file_attribute (fh, win32_newpath, ILLEGAL_UID, ILLEGAL_GID,
1719 (io.Information == FILE_CREATED ? S_JUSTCREATED : 0)
1720 | S_IFLNK | STD_RBITS | STD_WBITS);
1721 status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL);
1722 if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf))
1724 status = NtSetAttributesFile (fh, mk_winsym ? FILE_ATTRIBUTE_READONLY
1725 : FILE_ATTRIBUTE_SYSTEM);
1726 if (!NT_SUCCESS (status))
1727 debug_printf ("Setting attributes failed, status = %p", status);
1732 __seterrno_from_nt_status (status);
1733 FILE_DISPOSITION_INFORMATION fdi = { TRUE };
1734 status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
1735 FileDispositionInformation);
1736 if (!NT_SUCCESS (status))
1737 debug_printf ("Setting delete dispostion failed, status = %p", status);
1742 syscall_printf ("%d = symlink_worker(%s, %s, %d, %d)", res, oldpath,
1743 newpath, mk_winsym, isdevice);
1744 if (has_trailing_dirsep)
1745 free ((void *) newpath);
1750 cmp_shortcut_header (win_shortcut_hdr *file_header)
1752 /* A Cygwin or U/Win shortcut only contains a description and a relpath.
1753 Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
1754 always set to SW_NORMAL. */
1755 return file_header->size == sizeof (win_shortcut_hdr)
1756 && !memcmp (&file_header->magic, &GUID_shortcut, sizeof GUID_shortcut)
1757 && (file_header->flags & ~WSH_FLAG_IDLIST)
1758 == (WSH_FLAG_DESC | WSH_FLAG_RELPATH)
1759 && file_header->run == SW_NORMAL;
1763 symlink_info::check_shortcut (HANDLE h)
1766 win_shortcut_hdr *file_header;
1772 FILE_STANDARD_INFORMATION fsi;
1773 LARGE_INTEGER off = { QuadPart:0LL };
1775 status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
1776 FileStandardInformation);
1777 if (!NT_SUCCESS (status))
1782 if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
1783 || fsi.EndOfFile.QuadPart > 4 * 65536)
1785 if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
1786 buf = (char *) tp.w_get ();
1788 buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
1789 status = NtReadFile (h, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart,
1791 if (!NT_SUCCESS (status))
1793 if (status != STATUS_END_OF_FILE)
1797 file_header = (win_shortcut_hdr *) buf;
1798 if (io.Information != fsi.EndOfFile.LowPart
1799 || !cmp_shortcut_header (file_header))
1801 cp = buf + sizeof (win_shortcut_hdr);
1802 if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
1803 cp += *(unsigned short *) cp + 2;
1804 if (!(len = *(unsigned short *) cp))
1807 /* Check if this is a device file - these start with the sequence :\\ */
1808 if (strncmp (cp, ":\\", 2) == 0)
1809 res = strlen (strcpy (contents, cp)); /* Don't mess with device files */
1812 /* Has appended full path? If so, use it instead of description. */
1813 unsigned short relpath_len = *(unsigned short *) (cp + len);
1814 if (cp + len + 2 + relpath_len < buf + fsi.EndOfFile.LowPart)
1816 cp += len + 2 + relpath_len;
1817 len = *(unsigned short *) cp;
1820 if (*(PWCHAR) cp == 0xfeff) /* BOM */
1822 char *tmpbuf = tp.c_get ();
1823 if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2))
1826 res = posixify (tmpbuf);
1828 else if (len > SYMLINK_MAX)
1833 res = posixify (cp);
1836 if (res) /* It's a symlink. */
1837 pflags |= PATH_SYMLINK | PATH_LNK;
1842 symlink_info::check_sysfile (HANDLE h)
1845 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
1846 char *srcbuf = tp.c_get ();
1850 bool interix_symlink = false;
1851 LARGE_INTEGER off = { QuadPart:0LL };
1853 status = NtReadFile (h, NULL, NULL, NULL, &io, cookie_buf,
1854 sizeof (cookie_buf), &off, NULL);
1855 if (!NT_SUCCESS (status))
1857 debug_printf ("ReadFile1 failed %p", status);
1858 if (status != STATUS_END_OF_FILE)
1862 off.QuadPart = io.Information;
1863 if (io.Information == sizeof (cookie_buf)
1864 && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
1866 /* It's a symlink. */
1867 pflags |= PATH_SYMLINK;
1869 else if (io.Information == sizeof (cookie_buf)
1870 && memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
1871 pflags |= PATH_SOCKET;
1872 else if (io.Information >= sizeof (INTERIX_SYMLINK_COOKIE)
1873 && memcmp (cookie_buf, INTERIX_SYMLINK_COOKIE,
1874 sizeof (INTERIX_SYMLINK_COOKIE) - 1) == 0)
1876 /* It's an Interix symlink. */
1877 pflags |= PATH_SYMLINK;
1878 interix_symlink = true;
1879 /* Interix symlink cookies are shorter than Cygwin symlink cookies, so
1880 in case of an Interix symlink cooky we have read too far into the
1881 file. Set file pointer back to the position right after the cookie. */
1882 off.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1;
1884 if (pflags & PATH_SYMLINK)
1886 status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
1887 NT_MAX_PATH, &off, NULL);
1888 if (!NT_SUCCESS (status))
1890 debug_printf ("ReadFile2 failed");
1891 if (status != STATUS_END_OF_FILE)
1894 else if (*(PWCHAR) srcbuf == 0xfeff /* BOM */
1897 /* Add trailing 0 to Interix symlink target. Skip BOM in Cygwin
1899 if (interix_symlink)
1900 ((PWCHAR) srcbuf)[io.Information / sizeof (WCHAR)] = L'\0';
1903 char *tmpbuf = tp.c_get ();
1904 if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) srcbuf)
1906 debug_printf ("symlink string too long");
1908 res = posixify (tmpbuf);
1910 else if (io.Information > SYMLINK_MAX + 1)
1911 debug_printf ("symlink string too long");
1913 res = posixify (srcbuf);
1919 symlink_info::check_reparse_point (HANDLE h)
1924 PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) tp.c_get ();
1925 UNICODE_STRING subst;
1926 char srcbuf[SYMLINK_MAX + 7];
1928 status = NtFsControlFile (h, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT,
1929 NULL, 0, (LPVOID) rp,
1930 MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1931 if (!NT_SUCCESS (status))
1933 debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %p",
1938 if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
1939 RtlInitCountedUnicodeString (&subst,
1940 (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
1941 + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset),
1942 rp->SymbolicLinkReparseBuffer.SubstituteNameLength);
1943 else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
1945 RtlInitCountedUnicodeString (&subst,
1946 (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
1947 + rp->MountPointReparseBuffer.SubstituteNameOffset),
1948 rp->MountPointReparseBuffer.SubstituteNameLength);
1949 if (RtlEqualUnicodePathPrefix (&subst, &ro_u_volume, TRUE))
1951 /* Volume mount point. Not treated as symlink. The return
1952 value of -1 is a hint for the caller to treat this as a
1953 volume mount point. */
1959 /* Maybe it's a reparse point, but it's certainly not one we
1960 recognize. Drop the REPARSE file attribute so we don't even
1961 try to use the flag for some special handling. It's just some
1962 arbitrary file or directory for us. */
1963 fileattr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1966 sys_wcstombs (srcbuf, SYMLINK_MAX + 7, subst.Buffer,
1967 subst.Length / sizeof (WCHAR));
1968 pflags |= PATH_SYMLINK | PATH_REP;
1969 /* A symlink is never a directory. */
1970 fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
1971 return posixify (srcbuf);
1975 symlink_info::check_nfs_symlink (HANDLE h)
1981 FILE_GET_EA_INFORMATION fgei;
1982 char buf[sizeof (NFS_SYML_TARGET)];
1984 PFILE_FULL_EA_INFORMATION pffei;
1987 /* To find out if the file is a symlink and to get the symlink target,
1988 try to fetch the NfsSymlinkTargetName EA. */
1989 fgei_buf.fgei.NextEntryOffset = 0;
1990 fgei_buf.fgei.EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1991 stpcpy (fgei_buf.fgei.EaName, NFS_SYML_TARGET);
1992 pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1993 status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE,
1994 &fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
1995 if (NT_SUCCESS (status) && pffei->EaValueLength > 0)
1997 PWCHAR spath = (PWCHAR)
1998 (pffei->EaName + pffei->EaNameLength + 1);
1999 res = sys_wcstombs (contents, SYMLINK_MAX + 1,
2000 spath, pffei->EaValueLength) - 1;
2001 pflags |= PATH_SYMLINK;
2007 symlink_info::posixify (char *srcbuf)
2009 /* The definition for a path in a native symlink is a bit weird. The Flags
2010 value seem to contain 0 for absolute paths (stored as NT native path)
2011 and 1 for relative paths. Relative paths are paths not starting with a
2012 drive letter. These are not converted to NT native, but stored as
2013 given. A path starting with a single backslash is relative to the
2014 current drive thus a "relative" value (Flags == 1).
2015 Funny enough it's possible to store paths with slashes instead of
2016 backslashes, but they are evaluated incorrectly by subsequent Windows
2017 calls like CreateFile (ERROR_INVALID_NAME). So, what we do here is to
2018 take paths starting with slashes at face value, evaluating them as
2019 Cygwin specific POSIX paths.
2020 A path starting with two slashes(!) or backslashes is converted into an
2021 NT UNC path. Unfortunately, in contrast to POSIX rules, paths starting
2022 with three or more (back)slashes are also converted into UNC paths,
2023 just incorrectly sticking to one redundant leading backslash. We go
2024 along with this behaviour to avoid scenarios in which native tools access
2025 other files than Cygwin.
2026 The above rules are used exactly the same way on Cygwin specific symlinks
2027 (sysfiles and shortcuts) to eliminate non-POSIX paths in the output. */
2029 /* Eliminate native NT prefixes. */
2030 if (srcbuf[0] == '\\' && !strncmp (srcbuf + 1, "??\\", 3))
2033 if (srcbuf[1] != ':') /* native UNC path */
2034 *(srcbuf += 2) = '\\';
2036 if (isdrive (srcbuf))
2037 mount_table->conv_to_posix_path (srcbuf, contents, 0);
2038 else if (srcbuf[0] == '\\')
2040 if (srcbuf[1] == '\\') /* UNC path */
2041 slashify (srcbuf, contents, 0);
2042 else /* Paths starting with \ are current drive relative. */
2044 char cvtbuf[SYMLINK_MAX + 1];
2046 stpcpy (cvtbuf + cygheap->cwd.get_drive (cvtbuf), srcbuf);
2047 mount_table->conv_to_posix_path (cvtbuf, contents, 0);
2050 else /* Everything else is taken as is. */
2051 slashify (srcbuf, contents, 0);
2052 return strlen (contents);
2061 SCAN_JUSTCHECKTHIS, /* Never try to append a suffix. */
2069 const suffix_info *suffixes, *suffixes_start;
2074 char *has (const char *, const suffix_info *);
2076 int lnk_match () {return nextstate >= SCAN_APPENDLNK;}
2080 suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
2082 nextstate = SCAN_BEG;
2083 suffixes = suffixes_start = in_suffixes;
2085 const char *fname = strrchr (in_path, '\\');
2086 fname = fname ? fname + 1 : in_path;
2087 char *ext_here = strrchr (fname, '.');
2089 eopath = strchr (path, '\0');
2096 /* Check if the extension matches a known extension */
2097 for (const suffix_info *ex = in_suffixes; ex->name != NULL; ex++)
2098 if (ascii_strcasematch (ext_here, ex->name))
2100 nextstate = SCAN_JUSTCHECK;
2101 suffixes = NULL; /* Has an extension so don't scan for one. */
2106 /* Didn't match. Use last resort -- .lnk. */
2107 if (ascii_strcasematch (ext_here, ".lnk"))
2109 nextstate = SCAN_HASLNK;
2117 /* Avoid attaching suffixes if the resulting filename would be invalid. */
2118 if (eopath - fname > NAME_MAX - 4)
2120 nextstate = SCAN_JUSTCHECKTHIS;
2127 suffix_scan::next ()
2135 suffixes = suffixes_start;
2138 nextstate = SCAN_LNK;
2141 nextstate = SCAN_EXTRALNK;
2142 /* fall through to suffix checking below */
2145 nextstate = SCAN_APPENDLNK; /* Skip SCAN_BEG */
2148 nextstate = SCAN_DONE;
2151 case SCAN_JUSTCHECK:
2152 nextstate = SCAN_LNK;
2154 case SCAN_JUSTCHECKTHIS:
2155 nextstate = SCAN_DONE;
2158 case SCAN_APPENDLNK:
2159 strcat (eopath, ".lnk");
2160 nextstate = SCAN_DONE;
2167 while (suffixes && suffixes->name)
2168 if (nextstate == SCAN_EXTRALNK && !suffixes->addon)
2172 strcpy (eopath, suffixes->name);
2173 if (nextstate == SCAN_EXTRALNK)
2174 strcat (eopath, ".lnk");
2183 symlink_info::set_error (int in_errno)
2186 if (!(pflags & PATH_NO_ACCESS_CHECK) || in_errno == ENAMETOOLONG || in_errno == EIO)
2191 else if (in_errno == ENOENT)
2195 fileattr = FILE_ATTRIBUTE_NORMAL;
2202 symlink_info::parse_device (const char *contents)
2209 mymajor = strtol (contents += 2, &endptr, 16);
2210 if (endptr == contents)
2211 return isdevice = false;
2214 myminor = strtol (++contents, &endptr, 16);
2215 if (endptr == contents)
2216 return isdevice = false;
2219 mymode = strtol (++contents, &endptr, 16);
2220 if (endptr == contents)
2221 return isdevice = false;
2223 if ((mymode & S_IFMT) == S_IFIFO)
2225 mymajor = _major (FH_FIFO);
2226 myminor = _minor (FH_FIFO);
2232 return isdevice = true;
2235 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2237 If PATH is a symlink, put the value of the symlink--the file to
2238 which it points--into BUF. The value stored in BUF is not
2239 necessarily null terminated. BUFLEN is the length of BUF; only up
2240 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2241 which case nothing will be stored.
2243 Set *SYML if PATH is a symlink.
2245 Set *EXEC if PATH appears to be executable. This is an efficiency
2246 hack because we sometimes have to open the file anyhow. *EXEC will
2247 not be set for every executable file.
2249 Return -1 on error, 0 if PATH is not a symlink, or the length
2250 stored into BUF if PATH is a symlink. */
2253 symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs,
2254 path_conv_handle &conv_hdl)
2259 UNICODE_STRING upath;
2260 OBJECT_ATTRIBUTES attr;
2264 const ULONG ci_flag = cygwin_shared->obcaseinsensitive
2265 || (pflags & PATH_NOPOSIX) ? OBJ_CASE_INSENSITIVE : 0;
2266 /* TODO: Temporarily do all char->UNICODE conversion here. This should
2267 already be slightly faster than using Ascii functions. */
2270 InitializeObjectAttributes (&attr, &upath, ci_flag, NULL, NULL);
2272 /* This label is used in case we encounter a FS which only handles
2273 DOS paths. See below. */
2274 bool restarted = false;
2285 pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
2287 ext_here = suffix.has (path, suffixes);
2288 extn = ext_here - path;
2290 PVOID eabuf = &nfs_aol_ffei;
2291 ULONG easize = sizeof nfs_aol_ffei;
2293 bool had_ext = !!*ext_here;
2294 while (suffix.next ())
2299 get_nt_native_path (suffix.path, upath, pflags & PATH_DOS);
2305 /* The EA given to NtCreateFile allows to get a handle to a symlink on
2306 an NFS share, rather than getting a handle to the target of the
2307 symlink (which would spoil the task of this method quite a bit).
2308 Fortunately it's ignored on most other file systems so we don't have
2309 to special case NFS too much. */
2310 status = NtCreateFile (&h,
2311 READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA,
2312 &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS,
2314 FILE_OPEN_REPARSE_POINT
2315 | FILE_OPEN_FOR_BACKUP_INTENT,
2317 debug_printf ("%p = NtCreateFile (%S)", status, &upath);
2318 /* No right to access EAs or EAs not supported? */
2319 if (!NT_SUCCESS (status)
2320 && (status == STATUS_ACCESS_DENIED
2321 || status == STATUS_EAS_NOT_SUPPORTED
2322 || status == STATUS_NOT_SUPPORTED
2323 || status == STATUS_INVALID_NETWORK_RESPONSE
2324 /* Or a bug in Samba 3.2.x (x <= 7) when accessing a share's
2325 root dir which has EAs enabled? */
2326 || status == STATUS_INVALID_PARAMETER))
2329 /* If EAs are not supported, there's no sense to check them again
2330 with suffixes attached. So we set eabuf/easize to 0 here once. */
2331 if (status == STATUS_EAS_NOT_SUPPORTED
2332 || status == STATUS_NOT_SUPPORTED)
2337 status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2338 &attr, &io, FILE_SHARE_VALID_FLAGS,
2339 FILE_OPEN_REPARSE_POINT
2340 | FILE_OPEN_FOR_BACKUP_INTENT);
2341 debug_printf ("%p = NtOpenFile (no-EAs %S)", status, &upath);
2343 if (status == STATUS_OBJECT_NAME_NOT_FOUND)
2345 if (ci_flag == 0 && wincap.has_broken_udf ()
2346 && (!fs.inited () || fs.is_udf ()))
2348 /* On NT 5.x UDF is broken (at least) in terms of case
2349 sensitivity. When trying to open a file case sensitive,
2350 the file appears to be non-existant. Another bug is
2351 described in fs_info::update. */
2352 attr.Attributes = OBJ_CASE_INSENSITIVE;
2353 status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2354 &attr, &io, FILE_SHARE_VALID_FLAGS,
2355 FILE_OPEN_REPARSE_POINT
2356 | FILE_OPEN_FOR_BACKUP_INTENT);
2357 debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath);
2358 attr.Attributes = 0;
2359 if (NT_SUCCESS (status))
2362 fs.update (&upath, h);
2367 status = STATUS_OBJECT_NAME_NOT_FOUND;
2371 /* There are filesystems out in the wild (Netapp, NWFS, and others)
2372 which are uncapable of generating pathnames outside the Win32
2373 rules. That means, filenames on these FSes must not have a
2374 leading space or trailing dots and spaces. This code snippet
2375 manages them. I really hope it's streamlined enough not to
2376 slow down normal operation. This extra check only kicks in if
2377 we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't
2378 already attach a suffix *and* the above special case for UDF
2379 on XP didn't succeeed. */
2380 if (!restarted && !*ext_here && !(pflags & PATH_DOS) && !fs.inited ())
2382 /* Check for trailing dot or space or leading space in
2384 char *p = ext_here - 1;
2385 if (*p != '.' && *p != ' ')
2387 while (*--p != '\\')
2394 /* If so, check if file resides on one of the known broken
2395 FSes only supporting filenames following DOS rules. */
2397 fs.update (&upath, NULL);
2398 if (fs.has_dos_filenames_only ())
2400 /* If so, try again. Since we now know the FS, the
2401 filenames will be tweaked to follow DOS rules via the
2402 third parameter in the call to get_nt_native_path. */
2411 if (NT_SUCCESS (status)
2412 /* Check file system while we're having the file open anyway.
2413 This speeds up path_conv noticably (~10%). */
2414 && (fs.inited () || fs.update (&upath, h)))
2418 status = nfs_fetch_fattr3 (h, conv_hdl.nfsattr ());
2419 if (NT_SUCCESS (status))
2420 fileattr = ((conv_hdl.nfsattr ()->type & 7) == NF3DIR)
2421 ? FILE_ATTRIBUTE_DIRECTORY : 0;
2425 PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2427 /* Netapps don't implement FileNetworkOpenInformation. */
2428 status = fs.is_netapp ()
2429 ? STATUS_INVALID_PARAMETER
2430 : NtQueryInformationFile (h, &io, pfnoi, sizeof *pfnoi,
2431 FileNetworkOpenInformation);
2432 if (status == STATUS_INVALID_PARAMETER
2433 || status == STATUS_NOT_IMPLEMENTED)
2435 /* Apart from accessing Netapps, this also occurs when
2436 accessing SMB share root dirs hosted on NT4
2437 (STATUS_INVALID_PARAMETER), or when trying to access
2438 SMB share root dirs from NT4 (STATUS_NOT_IMPLEMENTED). */
2439 FILE_BASIC_INFORMATION fbi;
2440 FILE_STANDARD_INFORMATION fsi;
2442 status = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
2443 FileBasicInformation);
2444 if (NT_SUCCESS (status))
2446 memcpy (pfnoi, &fbi, 4 * sizeof (LARGE_INTEGER));
2447 if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fsi,
2449 FileStandardInformation)))
2451 pfnoi->EndOfFile.QuadPart = fsi.EndOfFile.QuadPart;
2452 pfnoi->AllocationSize.QuadPart
2453 = fsi.AllocationSize.QuadPart;
2456 pfnoi->EndOfFile.QuadPart
2457 = pfnoi->AllocationSize.QuadPart = 0;
2458 pfnoi->FileAttributes = fbi.FileAttributes;
2461 if (NT_SUCCESS (status))
2462 fileattr = pfnoi->FileAttributes;
2465 if (!NT_SUCCESS (status))
2467 debug_printf ("%p = NtQueryInformationFile (%S)", status, &upath);
2468 fileattr = INVALID_FILE_ATTRIBUTES;
2470 /* One of the inner path components is invalid, or the path contains
2471 invalid characters. Bail out with ENOENT.
2473 Note that additional STATUS_OBJECT_PATH_INVALID and
2474 STATUS_OBJECT_PATH_SYNTAX_BAD status codes exist. The first one
2475 is seemingly not generated by NtQueryInformationFile, the latter
2476 is only generated if the path is no absolute path within the
2477 NT name space, which should not happen and would point to an
2478 error in get_nt_native_path. Both status codes are deliberately
2479 not tested here unless proved necessary. */
2480 if (status == STATUS_OBJECT_PATH_NOT_FOUND
2481 || status == STATUS_OBJECT_NAME_INVALID
2482 || status == STATUS_BAD_NETWORK_PATH
2483 || status == STATUS_BAD_NETWORK_NAME
2484 || status == STATUS_NO_MEDIA_IN_DEVICE)
2487 goto file_not_symlink;
2489 if (status != STATUS_OBJECT_NAME_NOT_FOUND
2490 && status != STATUS_NO_SUCH_FILE) /* ENOENT on NFS or 9x share */
2492 /* The file exists, but the user can't access it for one reason
2493 or the other. To get the file attributes we try to access the
2494 information by opening the parent directory and getting the
2495 file attributes using a matching NtQueryDirectoryFile call. */
2496 UNICODE_STRING dirname, basename;
2497 OBJECT_ATTRIBUTES dattr;
2500 FILE_BOTH_DIRECTORY_INFORMATION fdi;
2501 WCHAR dummy_buf[NAME_MAX + 1];
2504 RtlSplitUnicodePath (&upath, &dirname, &basename);
2505 InitializeObjectAttributes (&dattr, &dirname, ci_flag,
2507 status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
2508 &dattr, &io, FILE_SHARE_VALID_FLAGS,
2509 FILE_SYNCHRONOUS_IO_NONALERT
2510 | FILE_OPEN_FOR_BACKUP_INTENT
2511 | FILE_DIRECTORY_FILE);
2512 if (!NT_SUCCESS (status))
2514 debug_printf ("%p = NtOpenFile(%S)", status, &dirname);
2515 /* There's a special case if the file is itself the root
2516 of a drive which is not accessible by the current user.
2517 This case is only recognized by the length of the
2518 basename part. If it's 0, the incoming file is the
2519 root of a drive. So we at least know it's a directory. */
2520 fileattr = basename.Length ? 0 : FILE_ATTRIBUTE_DIRECTORY;
2524 status = NtQueryDirectoryFile (dir, NULL, NULL, NULL, &io,
2525 &fdi_buf, sizeof fdi_buf,
2526 FileBothDirectoryInformation,
2527 TRUE, &basename, TRUE);
2528 /* Take the opportunity to check file system while we're
2529 having the handle to the parent dir. */
2530 fs.update (&upath, dir);
2532 if (!NT_SUCCESS (status))
2534 debug_printf ("%p = NtQueryDirectoryFile(%S)",
2536 if (status == STATUS_NO_SUCH_FILE)
2538 /* This can happen when trying to access files
2539 which match DOS device names on SMB shares.
2540 NtOpenFile failed with STATUS_ACCESS_DENIED,
2541 but the NtQueryDirectoryFile tells us the
2542 file doesn't exist. We're suspicious in this
2543 case and retry with the next suffix instead of
2552 PFILE_NETWORK_OPEN_INFORMATION pfnoi = conv_hdl.fnoi ();
2554 fileattr = fdi_buf.fdi.FileAttributes;
2555 memcpy (pfnoi, &fdi_buf.fdi.CreationTime, sizeof *pfnoi);
2556 /* Amazing, but true: The FILE_NETWORK_OPEN_INFORMATION
2557 structure has the AllocationSize and EndOfFile members
2558 interchanged relative to the directory information
2560 pfnoi->AllocationSize.QuadPart
2561 = fdi_buf.fdi.AllocationSize.QuadPart;
2562 pfnoi->EndOfFile.QuadPart
2563 = fdi_buf.fdi.EndOfFile.QuadPart;
2566 ext_tacked_on = !!*ext_here;
2567 goto file_not_symlink;
2573 ext_tacked_on = !!*ext_here;
2574 /* Don't allow to returns directories with appended suffix. If we found
2575 a directory with a suffix which has been appended here, then this
2576 directory doesn't match the request. So, just do as usual if file
2577 hasn't been found. */
2578 if (ext_tacked_on && !had_ext && (fileattr & FILE_ATTRIBUTE_DIRECTORY))
2586 /* Reparse points are potentially symlinks. This check must be
2587 performed before checking the SYSTEM attribute for sysfile
2588 symlinks, since reparse points can have this flag set, too.
2589 For instance, Vista starts to create a couple of reparse points
2590 with SYSTEM and HIDDEN flags set. */
2591 if ((fileattr & FILE_ATTRIBUTE_REPARSE_POINT))
2593 /* Don't check reparse points on remote filesystems. A reparse point
2594 pointing to another file on the remote system will be mistreated
2595 as pointing to a local file on the local system. This breaks the
2596 way reparse points are transparently handled on remote systems. */
2597 if (fs.is_remote_drive())
2600 res = check_reparse_point (h);
2603 /* Volume mount point. The filesystem information for the top
2604 level directory should be for the volume top level directory,
2605 rather than for the reparse point itself. So we fetch the
2606 filesystem information again, but with a NULL handle.
2607 This does what we want because fs_info::update opens the
2608 handle without FILE_OPEN_REPARSE_POINT. */
2609 fs.update (&upath, NULL);
2610 /* Make sure the open handle is not used in later stat calls.
2611 The handle has been opened with the FILE_OPEN_REPARSE_POINT
2612 flag, so it's a handle to the reparse point, not a handle
2613 to the volumes root dir. */
2614 pflags &= ~PC_KEEP_HANDLE;
2618 /* A symlink is never a directory. */
2619 conv_hdl.fnoi ()->FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
2624 /* Windows shortcuts are potentially treated as symlinks. Valid Cygwin
2625 & U/WIN shortcuts are R/O, but definitely not directories. */
2626 else if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
2627 == FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
2631 status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2632 FILE_SHARE_VALID_FLAGS,
2633 FILE_OPEN_FOR_BACKUP_INTENT
2634 | FILE_SYNCHRONOUS_IO_NONALERT);
2635 if (!NT_SUCCESS (status))
2639 res = check_shortcut (sym_h);
2644 /* If searching for `foo' and then finding a `foo.lnk' which
2645 is no shortcut, return the same as if file not found. */
2648 fileattr = INVALID_FILE_ATTRIBUTES;
2653 else if (contents[0] != ':' || contents[1] != '\\'
2654 || !parse_device (contents))
2658 /* If searching for `foo' and then finding a `foo.lnk' which is
2659 no shortcut, return the same as if file not found. */
2660 else if (suffix.lnk_match () && ext_tacked_on)
2662 fileattr = INVALID_FILE_ATTRIBUTES;
2667 /* This is the old Cygwin method creating symlinks. A symlink will
2668 have the `system' file attribute. Only files can be symlinks
2669 (which can be symlinks to directories). */
2670 else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))
2671 == FILE_ATTRIBUTE_SYSTEM)
2675 status = NtOpenFile (&sym_h, SYNCHRONIZE | GENERIC_READ, &attr, &io,
2676 FILE_SHARE_VALID_FLAGS,
2677 FILE_OPEN_FOR_BACKUP_INTENT
2678 | FILE_SYNCHRONOUS_IO_NONALERT);
2680 if (!NT_SUCCESS (status))
2684 res = check_sysfile (sym_h);
2691 /* If the file is on an NFS share and could be opened with extended
2692 attributes, check if it's a symlink. Only files can be symlinks
2693 (which can be symlinks to directories). */
2694 else if (fs.is_nfs () && (conv_hdl.nfsattr ()->type & 7) == NF3LNK)
2696 res = check_nfs_symlink (h);
2704 syscall_printf ("%s", isdevice ? "is a device" : "not a symlink");
2711 if (pflags & PC_KEEP_HANDLE)
2717 syscall_printf ("%d = symlink.check(%s, %p) (%p)",
2718 res, suffix.path, contents, pflags);
2722 /* "path" is the path in a virtual symlink. Set a symlink_info struct from
2723 that and proceed with further path checking afterwards. */
2725 symlink_info::set (char *path)
2727 strcpy (contents, path);
2728 pflags = PATH_SYMLINK;
2729 fileattr = FILE_ATTRIBUTE_NORMAL;
2733 ext_tacked_on = false;
2735 extn = major = minor = mode = 0;
2736 return strlen (path);
2739 /* readlink system call */
2742 readlink (const char *path, char *buf, size_t buflen)
2746 set_errno (ENAMETOOLONG);
2750 path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2754 set_errno (pathbuf.error);
2755 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2759 if (!pathbuf.exists ())
2765 if (!pathbuf.issymlink ())
2767 if (pathbuf.exists ())
2772 ssize_t len = min (buflen, strlen (pathbuf.get_win32 ()));
2773 memcpy (buf, pathbuf.get_win32 (), len);
2775 /* errno set by symlink.check if error */
2779 /* Some programs rely on st_dev/st_ino being unique for each file.
2780 Hash the path name and hope for the best. The hash arg is not
2781 always initialized to zero since readdir needs to compute the
2782 dirent ino_t based on a combination of the hash of the directory
2783 done during the opendir call and the hash or the filename within
2784 the directory. FIXME: Not bullet-proof. */
2785 /* Cygwin internal */
2787 hash_path_name (__ino64_t hash, PUNICODE_STRING name)
2789 if (name->Length == 0)
2792 /* Build up hash. Name is already normalized */
2793 USHORT len = name->Length / sizeof (WCHAR);
2794 for (USHORT idx = 0; idx < len; ++idx)
2795 hash = RtlUpcaseUnicodeChar (name->Buffer[idx])
2796 + (hash << 6) + (hash << 16) - hash;
2801 hash_path_name (__ino64_t hash, PCWSTR name)
2803 UNICODE_STRING uname;
2804 RtlInitUnicodeString (&uname, name);
2805 return hash_path_name (hash, &uname);
2809 hash_path_name (__ino64_t hash, const char *name)
2811 UNICODE_STRING uname;
2812 RtlCreateUnicodeStringFromAsciiz (&uname, name);
2813 __ino64_t ret = hash_path_name (hash, &uname);
2814 RtlFreeUnicodeString (&uname);
2819 getcwd (char *buf, size_t ulen)
2823 if (efault.faulted (EFAULT))
2825 else if (ulen == 0 && buf)
2828 res = cygheap->cwd.get (buf, 1, 1, ulen);
2832 /* getwd: Legacy. */
2836 return getcwd (buf, PATH_MAX + 1); /*Per SuSv3!*/
2839 /* chdir: POSIX 5.2.1.1 */
2841 chdir (const char *in_dir)
2844 if (efault.faulted (EFAULT))
2852 syscall_printf ("dir '%s'", in_dir);
2854 /* Convert path. First argument ensures that we don't check for NULL/empty/invalid
2856 path_conv path (PC_NONULLEMPTY, in_dir, PC_SYM_FOLLOW | PC_POSIX);
2859 set_errno (path.error);
2860 syscall_printf ("-1 = chdir (%s)", in_dir);
2865 const char *posix_cwd = NULL;
2866 int devn = path.get_devn ();
2867 if (!path.exists ())
2869 else if (!path.isdir ())
2870 set_errno (ENOTDIR);
2871 else if (!isvirtual_dev (devn))
2873 /* The sequence chdir("xx"); chdir(".."); must be a noop if xx
2874 is not a symlink. This is exploited by find.exe.
2875 The posix_cwd is just path.normalized_path.
2876 In other cases we let cwd.set obtain the Posix path through
2878 if (!isdrive(path.normalized_path))
2879 posix_cwd = path.normalized_path;
2884 posix_cwd = path.normalized_path;
2889 res = cygheap->cwd.set (&path, posix_cwd);
2891 /* Note that we're accessing cwd.posix without a lock here. I didn't think
2892 it was worth locking just for strace. */
2893 syscall_printf ("%R = chdir() cygheap->cwd.posix '%s' native '%S'", res,
2894 cygheap->cwd.get_posix (), path.get_nt_native_path ());
2903 cygheap_fdget cfd (fd);
2905 res = chdir (cfd->get_name ());
2909 syscall_printf ("%R = fchdir(%d)", res, fd);
2913 /******************** Exported Path Routines *********************/
2915 /* Cover functions to the path conversion routines.
2916 These are exported to the world as cygwin_foo by cygwin.din. */
2918 #define return_with_errno(x) \
2928 cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to,
2933 if (efault.faulted (EFAULT))
2941 bool relative = !!(what & CCP_RELATIVE);
2942 what &= ~CCP_RELATIVE;
2946 case CCP_POSIX_TO_WIN_A:
2948 p.check ((const char *) from,
2949 PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2950 | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2952 return_with_errno (p.error);
2953 PUNICODE_STRING up = p.get_nt_native_path ();
2955 UINT cp = AreFileApisANSI () ? CP_ACP : CP_OEMCP;
2956 int len = WideCharToMultiByte (cp, WC_NO_BEST_FIT_CHARS,
2957 up->Buffer, up->Length / sizeof (WCHAR),
2958 buf, NT_MAX_PATH, NULL, NULL);
2960 /* Convert native path to standard DOS path. */
2961 if (!strncmp (buf, "\\??\\", 4))
2964 if (buf[1] != ':') /* native UNC path */
2967 else if (*buf == '\\')
2969 /* Device name points to somewhere else in the NT namespace.
2970 Use GLOBALROOT prefix to convert to Win32 path. */
2971 char *p = buf + WideCharToMultiByte (cp, WC_NO_BEST_FIT_CHARS,
2972 ro_u_globalroot.Buffer,
2973 ro_u_globalroot.Length / sizeof (WCHAR),
2974 buf, NT_MAX_PATH, NULL, NULL);
2975 len = WideCharToMultiByte (cp, WC_NO_BEST_FIT_CHARS,
2976 up->Buffer, up->Length / sizeof (WCHAR),
2977 p, NT_MAX_PATH - (p - buf), NULL, NULL);
2980 lsiz = strlen (buf) + 1;
2981 /* TODO: Incoming "." is a special case which leads to a trailing
2982 backslash ".\\" in the Win32 path. That's a result of the
2983 conversion in normalize_posix_path. This should not occur
2984 so the below code is just a band-aid. */
2985 if (relative && !strcmp ((const char *) from, ".")
2986 && !strcmp (buf, ".\\"))
2993 case CCP_POSIX_TO_WIN_W:
2994 p.check ((const char *) from,
2995 PC_POSIX | PC_SYM_FOLLOW | PC_SYM_NOFOLLOW_REP
2996 | PC_NO_ACCESS_CHECK | PC_NOWARN | (relative ? PC_NOFULL : 0));
2998 return_with_errno (p.error);
2999 /* Relative Windows paths are always restricted to MAX_PATH chars. */
3000 if (relative && !isabspath (p.get_win32 ())
3001 && sys_mbstowcs (NULL, 0, p.get_win32 ()) > MAX_PATH)
3003 /* Recreate as absolute path. */
3004 p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW
3005 | PC_NO_ACCESS_CHECK | PC_NOWARN);
3007 return_with_errno (p.error);
3009 lsiz = p.get_wide_win32_path_len () + 1;
3010 path = p.get_nt_native_path ()->Buffer;
3012 /* Convert native path to standard DOS path. */
3013 if (!wcsncmp (path, L"\\??\\", 4))
3017 /* Drop long path prefix for short pathnames. Unfortunately there's
3018 quite a bunch of Win32 functions, especially in user32.dll,
3019 apparently, which don't grok long path names at all, not even
3020 in the UNICODE API. */
3021 if ((path[5] == L':' && lsiz <= MAX_PATH + 4)
3022 || (!wcsncmp (path + 4, L"UNC\\", 4) && lsiz <= MAX_PATH + 6))
3026 if (path[1] != L':')
3028 *(path += 2) = '\\';
3033 else if (*path == L'\\')
3035 /* Device name points to somewhere else in the NT namespace.
3036 Use GLOBALROOT prefix to convert to Win32 path. */
3037 to = (void *) wcpcpy ((wchar_t *) to, ro_u_globalroot.Buffer);
3038 lsiz += ro_u_globalroot.Length / sizeof (WCHAR);
3040 /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */
3041 if (relative && !strcmp ((const char *) from, ".")
3042 && !wcscmp (path, L".\\"))
3047 lsiz *= sizeof (WCHAR);
3049 case CCP_WIN_A_TO_POSIX:
3051 UINT cp = AreFileApisANSI () ? CP_ACP : CP_OEMCP;
3052 PWCHAR wbuf = tp.w_get ();
3053 MultiByteToWideChar (cp, 0, (const char *) from, -1, wbuf, NT_MAX_PATH);
3055 error = mount_table->conv_to_posix_path (wbuf, buf, relative);
3057 return_with_errno (error);
3058 lsiz = strlen (buf) + 1;
3061 case CCP_WIN_W_TO_POSIX:
3063 error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf,
3066 return_with_errno (error);
3067 lsiz = strlen (buf) + 1;
3082 case CCP_POSIX_TO_WIN_A:
3083 case CCP_WIN_A_TO_POSIX:
3084 case CCP_WIN_W_TO_POSIX:
3085 stpcpy ((char *) to, buf);
3087 case CCP_POSIX_TO_WIN_W:
3088 wcpcpy ((PWCHAR) to, path);
3095 cygwin_create_path (cygwin_conv_path_t what, const void *from)
3098 ssize_t size = cygwin_conv_path (what, from, NULL, 0);
3101 else if (!(to = malloc (size)))
3103 if (cygwin_conv_path (what, from, to, size) == -1)
3113 cygwin_conv_to_win32_path (const char *path, char *win32_path)
3115 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, path, win32_path,
3120 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
3122 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path, win32_path,
3126 /* This is exported to the world as cygwin_foo by cygwin.din. */
3129 cygwin_conv_to_posix_path (const char *path, char *posix_path)
3131 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, path, posix_path,
3136 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
3138 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, path, posix_path,
3142 /* The realpath function is required by POSIX:2008. */
3145 realpath (const char *path, char *resolved)
3147 /* Make sure the right errno is returned if path is NULL. */
3154 /* Guard reading from a potentially invalid path and writing to a
3155 potentially invalid resolved. */
3158 if (efault.faulted (EFAULT))
3164 tpath = tp.c_get ();
3165 mount_table->cygdrive_posix_path (path, tpath, 0);
3168 tpath = (char *) path;
3170 path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
3173 /* POSIX 2008 requires malloc'ing if resolved is NULL, and states
3174 that using non-NULL resolved is asking for portability
3177 if (!real_path.error && real_path.exists ())
3181 resolved = (char *) malloc (strlen (real_path.normalized_path) + 1);
3185 strcpy (resolved, real_path.normalized_path);
3189 /* FIXME: on error, Linux puts the name of the path
3190 component which could not be resolved into RESOLVED, but POSIX
3191 does not require this. */
3194 set_errno (real_path.error ?: ENOENT);
3198 /* Linux provides this extension. Since the only portable use of
3199 realpath requires a NULL second argument, we might as well have a
3200 one-argument wrapper. */
3202 canonicalize_file_name (const char *path)
3204 return realpath (path, NULL);
3207 /* Return non-zero if path is a POSIX path list.
3208 This is exported to the world as cygwin_foo by cygwin.din.
3211 <sect1 id="add-func-cygwin-posix-path-list-p">
3212 <para>Rather than use a mode to say what the "proper" path list
3213 format is, we allow any, and give apps the tools they need to
3214 convert between the two. If a ';' is present in the path list it's
3215 a Win32 path list. Otherwise, if the first path begins with
3216 [letter]: (in which case it can be the only element since if it
3217 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
3218 it's a POSIX path list.</para>
3224 cygwin_posix_path_list_p (const char *path)
3226 int posix_p = !(strchr (path, ';') || isdrive (path));
3230 /* These are used for apps that need to convert env vars like PATH back and
3231 forth. The conversion is a two step process. First, an upper bound on the
3232 size of the buffer needed is computed. Then the conversion is done. This
3233 allows the caller to use alloca if it wants. */
3236 conv_path_list_buf_size (const char *path_list, bool to_posix)
3238 int i, num_elms, max_mount_path_len, size;
3241 path_conv pc(".", PC_POSIX);
3242 /* The theory is that an upper bound is
3243 current_size + (num_elms * max_mount_path_len) */
3244 /* FIXME: This method is questionable in the long run. */
3247 char delim = to_posix ? ';' : ':';
3248 for (p = path_list, num_elms = nrel = 0; p; num_elms++)
3252 p = strchr (++p, delim);
3255 /* 7: strlen ("//c") + slop, a conservative initial value */
3256 for (max_mount_path_len = sizeof ("/cygdrive/X"), i = 0;
3257 i < mount_table->nmounts; i++)
3259 int mount_len = (to_posix
3260 ? mount_table->mount[i].posix_pathlen
3261 : mount_table->mount[i].native_pathlen);
3262 if (max_mount_path_len < mount_len)
3263 max_mount_path_len = mount_len;
3267 size = strlen (path_list)
3268 + (num_elms * max_mount_path_len)
3269 + (nrel * strlen (to_posix ? pc.normalized_path : pc.get_win32 ()))
3277 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
3279 return conv_path_list_buf_size (path_list, true);
3283 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
3285 return conv_path_list_buf_size (path_list, false);
3289 env_PATH_to_posix (const void *win32, void *posix, size_t size)
3291 return_with_errno (conv_path_list ((const char *) win32, (char *) posix,
3296 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
3298 return_with_errno (conv_path_list (win32, posix, MAX_PATH,
3299 CCP_WIN_A_TO_POSIX | CCP_RELATIVE));
3303 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
3305 return_with_errno (conv_path_list (posix, win32, MAX_PATH,
3306 CCP_POSIX_TO_WIN_A | CCP_RELATIVE));
3310 cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
3315 void *orig_to = NULL;
3316 size_t orig_size = (size_t) -1;
3319 switch (what & CCP_CONVTYPE_MASK)
3321 case CCP_WIN_W_TO_POSIX:
3322 if (!sys_wcstombs_alloc (&winp, HEAP_NOTHEAP, (const wchar_t *) from,
3325 what = (what & ~CCP_CONVTYPE_MASK) | CCP_WIN_A_TO_POSIX;
3326 from = (const void *) winp;
3328 case CCP_POSIX_TO_WIN_W:
3330 return conv_path_list_buf_size ((const char *) from, 0)
3332 what = (what & ~CCP_CONVTYPE_MASK) | CCP_POSIX_TO_WIN_A;
3335 to = (void *) tp.w_get ();
3339 switch (what & CCP_CONVTYPE_MASK)
3341 case CCP_WIN_A_TO_POSIX:
3342 case CCP_POSIX_TO_WIN_A:
3344 return conv_path_list_buf_size ((const char *) from,
3345 what == CCP_WIN_A_TO_POSIX);
3346 ret = conv_path_list ((const char *) from, (char *) to, size, what);
3347 /* Free winp buffer in case of CCP_WIN_W_TO_POSIX. */
3350 /* Convert to WCHAR in case of CCP_POSIX_TO_WIN_W. */
3352 sys_mbstowcs ((wchar_t *) orig_to, size / sizeof (WCHAR),
3353 (const char *) to, (size_t) -1);
3354 return_with_errno (ret);
3363 /* cygwin_split_path: Split a path into directory and file name parts.
3364 Buffers DIR and FILE are assumed to be big enough.
3366 Examples (path -> `dir' / `file'):
3369 . -> `.' / `.' (FIXME: should this be `.' / `'?)
3370 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
3372 foo/bar -> `foo' / `bar'
3373 foo/bar/ -> `foo' / `bar'
3375 /foo/bar -> `/foo' / `bar'
3378 c:foo -> `c:/' / `foo'
3379 c:/foo -> `c:/' / `foo'
3383 cygwin_split_path (const char *path, char *dir, char *file)
3385 int dir_started_p = 0;
3387 /* Deal with drives.
3388 Remember that c:foo <==> c:/foo. */
3400 if (isdirsep (*path))
3405 /* Determine if there are trailing slashes and "delete" them if present.
3406 We pretend as if they don't exist. */
3407 const char *end = path + strlen (path);
3408 /* path + 1: keep leading slash. */
3409 while (end > path + 1 && isdirsep (end[-1]))
3412 /* At this point, END points to one beyond the last character
3413 (with trailing slashes "deleted"). */
3415 /* Point LAST_SLASH at the last slash (duh...). */
3416 const char *last_slash;
3417 for (last_slash = end - 1; last_slash >= path; --last_slash)
3418 if (isdirsep (*last_slash))
3421 if (last_slash == path)
3426 else if (last_slash > path)
3428 memcpy (dir, path, last_slash - path);
3429 dir[last_slash - path] = 0;
3434 ; /* nothing to do */
3440 memcpy (file, last_slash + 1, end - last_slash - 1);
3441 file[end - last_slash - 1] = 0;
3445 copy_cwd_str (PUNICODE_STRING tgt, PUNICODE_STRING src)
3447 RtlCopyUnicodeString (tgt, src);
3448 if (tgt->Buffer[tgt->Length / sizeof (WCHAR) - 1] != L'\\')
3450 tgt->Buffer[tgt->Length / sizeof (WCHAR)] = L'\\';
3451 tgt->Length += sizeof (WCHAR);
3455 /*****************************************************************************/
3457 /* The find_fast_cwd_pointer function and parts of the
3458 cwdstuff::override_win32_cwd method are based on code using the
3461 Copyright 2010 John Carey. All rights reserved.
3463 Redistribution and use in source and binary forms, with or without
3464 modification, are permitted provided that the following conditions
3467 1. Redistributions of source code must retain the above
3468 copyright notice, this list of conditions and the following
3471 2. Redistributions in binary form must reproduce the above
3472 copyright notice, this list of conditions and the following
3473 disclaimer in the documentation and/or other materials provided
3474 with the distribution.
3476 THIS SOFTWARE IS PROVIDED BY JOHN CAREY ``AS IS'' AND ANY EXPRESS
3477 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3478 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3479 ARE DISCLAIMED. IN NO EVENT SHALL JOHN CAREY OR CONTRIBUTORS BE
3480 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3481 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
3482 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
3483 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3484 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3485 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
3486 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
3489 /* This class is used to store the CWD starting with Windows Vista.
3490 The CWD storage in the RTL_USER_PROCESS_PARAMETERS block is only
3491 an afterthought now. The actual CWD storage is a FAST_CWD structure
3492 which is allocated on the process heap. The new method only requires
3493 minimal locking and it's much more multi-thread friendly. Presumably
3494 it minimizes contention when accessing the CWD.
3495 The class fcwd_access_t is supposed to encapsulate the gory implementation
3496 details depending on OS version from the calling functions. */
3497 class fcwd_access_t {
3498 /* This is the layout used in Windows 8 developer preview. */
3500 LONG ReferenceCount; /* Only release when this is 0. */
3501 HANDLE DirectoryHandle;
3502 ULONG OldDismountCount; /* Reflects the system DismountCount
3503 at the time the CWD has been set. */
3504 UNICODE_STRING Path; /* Path's Buffer member always refers
3505 to the following Buffer array. */
3506 LONG FSCharacteristics; /* Taken from FileFsDeviceInformation */
3507 WCHAR Buffer[MAX_PATH];
3509 /* This is the layout used in Windows 7 and Vista. */
3511 UNICODE_STRING Path; /* Path's Buffer member always refers
3512 to the following Buffer array. */
3513 HANDLE DirectoryHandle;
3514 LONG FSCharacteristics; /* Taken from FileFsDeviceInformation */
3515 LONG ReferenceCount; /* Only release when this is 0. */
3516 ULONG OldDismountCount; /* Reflects the system DismountCount
3517 at the time the CWD has been set. */
3518 WCHAR Buffer[MAX_PATH];
3520 /* This is the old FAST_CWD structure up to the patch from KB 2393802,
3521 release in February 2011. */
3522 struct FAST_CWD_OLD {
3523 LONG ReferenceCount; /* Only release when this is 0. */
3524 HANDLE DirectoryHandle;
3525 ULONG OldDismountCount; /* Reflects the system DismountCount
3526 at the time the CWD has been set. */
3527 UNICODE_STRING Path; /* Path's Buffer member always refers
3528 to the following Buffer array. */
3529 WCHAR Buffer[MAX_PATH];
3537 /* Type of FAST_CWD used on this system. Keeping this information available
3538 in shared memory avoids to test for the version every time around.
3539 Default to new version. */
3540 enum fcwd_version_t {
3545 static fcwd_version_t fast_cwd_version;
3547 #define IMPLEMENT(type, name) \
3549 switch (fast_cwd_version) { \
3559 IMPLEMENT (LONG &, ReferenceCount)
3560 IMPLEMENT (HANDLE &, DirectoryHandle)
3561 IMPLEMENT (ULONG &, OldDismountCount)
3562 IMPLEMENT (UNICODE_STRING &, Path)
3563 IMPLEMENT (WCHAR *, Buffer)
3564 /* Special case FSCharacteristics. Didn't exist originally. */
3565 void SetFSCharacteristics (LONG val)
3567 switch (fast_cwd_version)
3572 f7.FSCharacteristics = val;
3575 f8.FSCharacteristics = val;
3580 void CopyPath (UNICODE_STRING &target)
3582 /* Copy the Path contents over into the UNICODE_STRING referenced by
3583 target. This is used to set the CurrentDirectoryName in the
3584 user parameter block. */
3587 void Free (PVOID heap)
3589 /* Decrement the reference count. If it's down to 0, free
3590 structure from heap. */
3591 if (this && InterlockedDecrement (&ReferenceCount ()) == 0)
3593 /* In contrast to pre-Vista, the handle on init is always a
3594 fresh one and not the handle inherited from the parent
3595 process. So we always have to close it here. However, the
3596 handle could be NULL, if we cd'ed into a virtual dir. */
3597 HANDLE h = DirectoryHandle ();
3600 RtlFreeHeap (heap, 0, this);
3603 void FillIn (HANDLE dir, PUNICODE_STRING name, ULONG old_dismount_count)
3605 /* Fill in all values into this FAST_CWD structure. */
3606 DirectoryHandle () = dir;
3607 ReferenceCount () = 1;
3608 OldDismountCount () = old_dismount_count;
3609 /* The new structure stores the device characteristics of the
3610 volume holding the dir. RtlGetCurrentDirectory_U checks
3611 if the FILE_REMOVABLE_MEDIA flag is set and, if so, checks if
3612 the volume is still the same as the one used when opening
3613 the directory handle.
3614 We don't call NtQueryVolumeInformationFile for the \\?\PIPE,
3615 though. It just returns STATUS_INVALID_HANDLE anyway. */
3616 if (fast_cwd_version != FCWD_OLD)
3618 SetFSCharacteristics (0);
3619 if (name != &ro_u_pipedir)
3622 FILE_FS_DEVICE_INFORMATION ffdi;
3623 if (NT_SUCCESS (NtQueryVolumeInformationFile (dir, &io, &ffdi,
3624 sizeof ffdi, FileFsDeviceInformation)))
3625 SetFSCharacteristics (ffdi.Characteristics);
3628 RtlInitEmptyUnicodeString (&Path (), Buffer (),
3629 MAX_PATH * sizeof (WCHAR));
3630 copy_cwd_str (&Path (), name);
3633 static void SetDirHandleFromBufferPointer (PWCHAR buf_p, HANDLE dir)
3635 /* Input: The buffer pointer as it's stored in the user parameter block
3636 and a directory handle.
3637 This function computes the address to the FAST_CWD structure based
3638 on the version and overwrites the directory handle. It is only
3639 used if we couldn't figure out the address of fast_cwd_ptr. */
3640 fcwd_access_t *f_cwd;
3641 switch (fast_cwd_version)
3645 f_cwd = (fcwd_access_t *)
3646 ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_OLD, Buffer));
3648 f_cwd = (fcwd_access_t *)
3649 ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_7, Buffer));
3651 f_cwd = (fcwd_access_t *)
3652 ((PBYTE) buf_p - __builtin_offsetof (FAST_CWD_8, Buffer));
3654 f_cwd->DirectoryHandle () = dir;
3656 static void SetVersionFromPointer (PBYTE buf_p, bool is_buffer)
3658 /* Given a pointer to the FAST_CWD structure (is_buffer == false) or a
3659 pointer to the Buffer within (is_buffer == true), this function
3660 computes the FAST_CWD version by checking that Path.MaximumLength
3661 equals MAX_PATH, and that Path.Buffer == Buffer. */
3663 buf_p -= __builtin_offsetof (FAST_CWD_8, Buffer);
3664 fcwd_access_t *f_cwd = (fcwd_access_t *) buf_p;
3665 if (f_cwd->f8.Path.MaximumLength == MAX_PATH * sizeof (WCHAR)
3666 && f_cwd->f8.Path.Buffer == f_cwd->f8.Buffer)
3667 fast_cwd_version = FCWD_W8;
3668 else if (f_cwd->f7.Path.MaximumLength == MAX_PATH * sizeof (WCHAR)
3669 && f_cwd->f7.Path.Buffer == f_cwd->f7.Buffer)
3670 fast_cwd_version = FCWD_W7;
3672 fast_cwd_version = FCWD_OLD;
3675 fcwd_access_t::fcwd_version_t fcwd_access_t::fast_cwd_version
3676 __attribute__((section (".cygwin_dll_common"), shared))
3677 = fcwd_access_t::FCWD_W7;
3678 /* fast_cwd_ptr is a pointer to the global RtlpCurDirRef pointer in
3679 ntdll.dll pointing to the FAST_CWD structure which constitutes the CWD.
3680 Unfortunately RtlpCurDirRef is not exported from ntdll.dll.
3681 We put the pointer into the common shared DLL segment. This allows to
3682 restrict the call to find_fast_cwd_pointer() to once per Cygwin session
3683 per user session. This works, because ASLR randomizes the load address
3684 of DLLs only once at boot time. */
3685 static fcwd_access_t **fast_cwd_ptr
3686 __attribute__((section (".cygwin_dll_common"), shared))
3687 = (fcwd_access_t **) -1;
3689 #define peek32(x) (*(uint32_t *)(x))
3691 /* This function scans the code in ntdll.dll to find the address of the
3692 global variable used to access the CWD starting with Vista. While the
3693 pointer is global, it's not exported from the DLL, unfortunately.
3694 Therefore we have to use some knowledge to figure out the address.
3696 This code has been tested on Vista 32/64 bit, Server 2008 32/64 bit,
3697 Windows 7 32/64 bit, and Server 2008 R2 (which is only 64 bit anyway).
3698 There's some hope that this will still work for Windows 8... */
3699 static fcwd_access_t **
3700 find_fast_cwd_pointer ()
3702 /* Fetch entry points of relevant functions in ntdll.dll. */
3703 HMODULE ntdll = GetModuleHandle ("ntdll.dll");
3706 const uint8_t *get_dir = (const uint8_t *)
3707 GetProcAddress (ntdll, "RtlGetCurrentDirectory_U");
3708 const uint8_t *ent_crit = (const uint8_t *)
3709 GetProcAddress (ntdll, "RtlEnterCriticalSection");
3710 if (!get_dir || !ent_crit)
3712 /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
3713 const uint8_t *rcall = (const uint8_t *) memchr (get_dir, 0xe8, 32);
3716 /* Fetch offset from instruction and compute address of called function.
3717 This function actually fetches the current FAST_CWD instance and
3718 performs some other actions, not important to us. */
3719 ptrdiff_t offset = (ptrdiff_t) peek32 (rcall + 1);
3720 const uint8_t *use_cwd = rcall + 5 + offset;
3721 /* Find first "push edi" instruction. */
3722 const uint8_t *pushedi = (const uint8_t *) memchr (use_cwd, 0x57, 32);
3723 /* ...which should be followed by "mov edi, crit-sect-addr" then
3724 "push edi", or by just a single "push crit-sect-addr". */
3725 const uint8_t *movedi = pushedi + 1;
3726 if (movedi[0] == 0xbf && movedi[5] == 0x57)
3728 else if (movedi[0] == 0x68)
3732 /* Compare the address used for the critical section with the known
3733 PEB lock as stored in the PEB. */
3734 if ((PRTL_CRITICAL_SECTION) peek32 (movedi + 1)
3735 != NtCurrentTeb ()->Peb->FastPebLock)
3737 /* To check we are seeing the right code, we check our expectation that
3738 the next instruction is a relative call into RtlEnterCriticalSection. */
3739 if (rcall[0] != 0xe8)
3741 /* Check that this is a relative call to RtlEnterCriticalSection. */
3742 offset = (ptrdiff_t) peek32 (rcall + 1);
3743 if (rcall + 5 + offset != ent_crit)
3745 /* After locking the critical section, the code should read the global
3746 PFAST_CWD * pointer that is guarded by that critical section. */
3747 const uint8_t *movesi = rcall + 5;
3748 if (movesi[0] != 0x8b)
3750 return (fcwd_access_t **) peek32 (movesi + 2);
3753 static fcwd_access_t **
3756 /* Fetch the pointer but don't set the global fast_cwd_ptr yet. First
3757 we have to make sure we know the version of the FAST_CWD structure
3758 used on the system. */
3759 fcwd_access_t **f_cwd_ptr = find_fast_cwd_pointer ();
3761 system_printf ("WARNING: Couldn't compute FAST_CWD pointer. "
3762 "Please report this problem to\nthe public mailing "
3763 "list cygwin@cygwin.com");
3764 if (f_cwd_ptr && *f_cwd_ptr)
3766 /* Just evaluate structure version. */
3767 fcwd_access_t::SetVersionFromPointer ((PBYTE) *f_cwd_ptr, false);
3771 /* If we couldn't fetch fast_cwd_ptr, or if fast_cwd_ptr is NULL(*)
3772 we have to figure out the version from the Buffer pointer in the
3775 (*) This is very unlikely to happen when starting the first
3776 Cygwin process, since it only happens when starting the
3777 process in a directory which can't be used as CWD by Win32, or
3778 if the directory doesn't exist. But *if* it happens, we have
3779 no valid FAST_CWD structure, even though upp_cwd_str.Buffer is
3780 not NULL in that case. So we let the OS create a valid
3781 FAST_CWD structure temporarily to have something to work with.
3782 We know the pipe FS works. */
3783 PEB &peb = *NtCurrentTeb ()->Peb;
3785 if (f_cwd_ptr /* so *f_cwd_ptr == NULL */
3786 && !NT_SUCCESS (RtlSetCurrentDirectory_U (&ro_u_pipedir)))
3787 api_fatal ("Couldn't set directory to %S temporarily.\n"
3788 "Cannot continue.", &ro_u_pipedir);
3789 RtlEnterCriticalSection (peb.FastPebLock);
3790 fcwd_access_t::SetVersionFromPointer
3791 ((PBYTE) peb.ProcessParameters->CurrentDirectoryName.Buffer, true);
3792 RtlLeaveCriticalSection (peb.FastPebLock);
3794 /* Eventually, after we set the version as well, set fast_cwd_ptr. */
3799 cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
3803 PEB &peb = *NtCurrentTeb ()->Peb;
3804 UNICODE_STRING &upp_cwd_str = peb.ProcessParameters->CurrentDirectoryName;
3805 HANDLE &upp_cwd_hdl = peb.ProcessParameters->CurrentDirectoryHandle;
3807 if (wincap.has_fast_cwd ())
3809 if (fast_cwd_ptr == (fcwd_access_t **) -1)
3810 fast_cwd_ptr = find_fast_cwd ();
3813 /* Default method starting with Vista. If we got a valid value for
3814 fast_cwd_ptr, we can simply replace the RtlSetCurrentDirectory_U
3815 function entirely, just as on pre-Vista. */
3816 PVOID heap = peb.ProcessHeap;
3817 /* First allocate a new fcwd_access_t structure on the heap.
3818 The new fcwd_access_t structure is 4 byte bigger than the old one,
3819 but we simply don't care, so we allocate always room for the
3821 fcwd_access_t *f_cwd = (fcwd_access_t *)
3822 RtlAllocateHeap (heap, 0, sizeof (fcwd_access_t));
3825 debug_printf ("RtlAllocateHeap failed");
3828 /* Fill in the values. */
3829 f_cwd->FillIn (dir, error ? &ro_u_pipedir : &win32,
3830 old_dismount_count);
3831 /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
3832 structure and writing the CWD to the user process parameter
3833 block. This is equivalent to calling RtlAcquirePebLock/
3834 RtlReleasePebLock, but without having to go through the FS
3836 RtlEnterCriticalSection (peb.FastPebLock);
3837 fcwd_access_t *old_cwd = *fast_cwd_ptr;
3838 *fast_cwd_ptr = f_cwd;
3839 f_cwd->CopyPath (upp_cwd_str);
3841 RtlLeaveCriticalSection (peb.FastPebLock);
3842 old_cwd->Free (heap);
3846 /* This is more a hack, and it's only used on Vista and later if we
3847 failed to find the fast_cwd_ptr value. What we do here is to call
3848 RtlSetCurrentDirectory_U and let it set up a new FAST_CWD
3849 structure. Afterwards, compute the address of that structure
3850 utilizing the fact that the buffer address in the user process
3851 parameter block is actually pointing to the buffer in that
3852 FAST_CWD structure. Then replace the directory handle in that
3853 structure with our own handle and close the original one.
3855 Note that the call to RtlSetCurrentDirectory_U also closes our
3856 old dir handle, so there won't be any handle left open.
3858 This method is prone to two race conditions:
3860 - Due to the way RtlSetCurrentDirectory_U opens the directory
3861 handle, the directory is locked against deletion or renaming
3862 between the RtlSetCurrentDirectory_U and the subsequent NtClose
3865 - When another thread calls SetCurrentDirectory at exactly the
3866 same time, a crash might occur, or worse, unrelated data could
3867 be overwritten or NtClose could be called on an unrelated handle.
3869 Therefore, use this *only* as a fallback. */
3873 RtlSetCurrentDirectory_U (error ? &ro_u_pipedir : &win32);
3874 if (!NT_SUCCESS (status))
3876 debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %p",
3877 error ? &ro_u_pipedir : &win32, status);
3881 else if (upp_cwd_hdl == NULL)
3883 RtlEnterCriticalSection (peb.FastPebLock);
3884 fcwd_access_t::SetDirHandleFromBufferPointer(upp_cwd_str.Buffer, dir);
3887 RtlLeaveCriticalSection (peb.FastPebLock);
3888 /* In contrast to pre-Vista, the handle on init is always a fresh one
3889 and not the handle inherited from the parent process. So we always
3890 have to close it here. */
3896 /* This method is used for all pre-Vista OSes. We simply set the values
3897 for the CWD in the user process parameter block entirely by ourselves
3898 under PEB lock condition. This is how RtlSetCurrentDirectory_U worked
3899 in these older OSes, so we're safe.
3901 Note that we can't just RtlEnterCriticalSection (peb.FastPebLock)
3902 on pre-Vista. RtlAcquirePebLock was way more complicated back then. */
3903 RtlAcquirePebLock ();
3905 copy_cwd_str (&upp_cwd_str, error ? &ro_u_pipedir : &win32);
3908 RtlReleasePebLock ();
3909 /* Only on init, the handle is potentially a native handle. However,
3910 if it's identical to dir, it's the inherited handle from a Cygwin
3911 parent process and must not be closed. */
3917 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
3921 cwd_lock.init ("cwd_lock");
3923 /* Cygwin processes inherit the cwd from their parent. If the win32 path
3924 buffer is not NULL, the cwd struct is already set up, and we only
3925 have to override the Win32 CWD with ours. */
3927 override_win32_cwd (true, SharedUserData.DismountCount);
3929 /* Initially re-open the cwd to allow POSIX semantics. */
3933 /* Chdir and fill out the elements of a cwdstuff struct. */
3935 cwdstuff::set (path_conv *nat_cwd, const char *posix_cwd)
3938 UNICODE_STRING upath;
3939 PEB &peb = *NtCurrentTeb ()->Peb;
3940 bool virtual_path = false;
3941 bool unc_path = false;
3942 bool inaccessible_path = false;
3944 /* Here are the problems with using SetCurrentDirectory. Just skip this
3945 comment if you don't like whining.
3947 - SetCurrentDirectory only supports paths of up to MAX_PATH - 1 chars,
3948 including a trailing backslash. That's an absolute restriction, even
3951 - SetCurrentDirectory fails for directories with strict permissions even
3952 for processes with the SE_BACKUP_NAME privilege enabled. The reason
3953 is apparently that SetCurrentDirectory calls NtOpenFile without the
3954 FILE_OPEN_FOR_BACKUP_INTENT flag set.
3956 - SetCurrentDirectory does not support case-sensitivity.
3958 - Unlinking a cwd fails because SetCurrentDirectory seems to open
3959 directories so that deleting the directory is disallowed.
3961 - SetCurrentDirectory can naturally not work on virtual Cygwin paths
3962 like /proc or /cygdrive.
3964 Unfortunately, even though we have access to the Win32 process parameter
3965 block, we can't just replace the directory handle. Starting with Vista,
3966 the handle is used elsewhere, and just replacing the handle in the process
3967 parameter block shows quite surprising results.
3968 FIXME: If we ever find a *safe* way to replace the directory handle in
3969 the process parameter block, we're back in business.
3971 Nevertheless, doing entirely without SetCurrentDirectory is not really
3972 feasible, because it breaks too many mixed applications using the Win32
3975 Therefore we handle the CWD all by ourselves and just keep the Win32
3976 CWD in sync. However, to avoid surprising behaviour in the Win32 API
3977 when we are in a CWD which is inaccessible as Win32 CWD, we set the
3978 Win32 CWD to a "weird" directory in which all relative filesystem-related
3981 cwd_lock.acquire ();
3985 upath = *nat_cwd->get_nt_native_path ();
3986 if (nat_cwd->isspecial ())
3987 virtual_path = true;
3990 /* Memorize old DismountCount before opening the dir. This value is
3991 stored in the FAST_CWD structure on Vista and later. It would be
3992 simpler to fetch the old DismountCount in override_win32_cwd, but
3993 Windows also fetches it before opening the directory handle. It's
3994 not quite clear if that's really required, but since we don't know
3995 the side effects of this action, we better follow Windows' lead. */
3996 ULONG old_dismount_count = SharedUserData.DismountCount;
3997 /* Open a directory handle with FILE_OPEN_FOR_BACKUP_INTENT and with all
3998 sharing flags set. The handle is right now used in exceptions.cc only,
3999 but that might change in future. */
4004 OBJECT_ATTRIBUTES attr;
4008 /* On init, just reopen Win32 CWD with desired access flags.
4009 We can access the PEB without lock, because no other thread
4010 can change the CWD. */
4011 RtlInitUnicodeString (&upath, L"");
4012 InitializeObjectAttributes (&attr, &upath,
4013 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
4014 peb.ProcessParameters->CurrentDirectoryHandle, NULL);
4017 InitializeObjectAttributes (&attr, &upath,
4018 nat_cwd->objcaseinsensitive () | OBJ_INHERIT,
4020 /* First try without FILE_OPEN_FOR_BACKUP_INTENT, to find out if the
4021 directory is valid for Win32 apps. And, no, we can't just call
4022 SetCurrentDirectory here, since that would potentially break
4023 case-sensitivity. */
4024 status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
4025 FILE_SHARE_VALID_FLAGS,
4027 | FILE_SYNCHRONOUS_IO_NONALERT);
4028 if (status == STATUS_ACCESS_DENIED)
4030 status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
4031 FILE_SHARE_VALID_FLAGS,
4033 | FILE_SYNCHRONOUS_IO_NONALERT
4034 | FILE_OPEN_FOR_BACKUP_INTENT);
4035 inaccessible_path = true;
4037 if (!NT_SUCCESS (status))
4039 cwd_lock.release ();
4040 __seterrno_from_nt_status (status);
4044 /* Set new handle. Note that we simply overwrite the old handle here
4045 without closing it. The handle is also used as Win32 CWD handle in
4046 the user parameter block, and it will be closed in override_win32_cwd,
4052 /* On init, just fetch the Win32 dir from the PEB. We can access
4053 the PEB without lock, because no other thread can change the CWD
4055 PUNICODE_STRING pdir = &peb.ProcessParameters->CurrentDirectoryName;
4056 RtlInitEmptyUnicodeString (&win32,
4057 (PWCHAR) crealloc_abort (win32.Buffer,
4060 pdir->Length + sizeof (WCHAR));
4061 RtlCopyUnicodeString (&win32, pdir);
4063 PWSTR eoBuffer = win32.Buffer + (win32.Length / sizeof (WCHAR));
4064 /* Remove trailing slash if one exists. */
4065 if ((eoBuffer - win32.Buffer) > 3 && eoBuffer[-1] == L'\\')
4066 win32.Length -= sizeof (WCHAR);
4067 if (eoBuffer[0] == L'\\')
4074 if (!virtual_path) /* don't mangle virtual path. */
4076 /* Convert into Win32 path and compute length. */
4077 if (upath.Buffer[1] == L'?')
4080 upath.Length -= 4 * sizeof (WCHAR);
4081 if (upath.Buffer[1] != L':')
4085 upath.Length -= 2 * sizeof (WCHAR);
4091 /* Path via native NT namespace. Prepend GLOBALROOT prefix
4092 to create a valid Win32 path. */
4093 PWCHAR buf = (PWCHAR) alloca (upath.Length
4094 + ro_u_globalroot.Length
4096 wcpcpy (wcpcpy (buf, ro_u_globalroot.Buffer), upath.Buffer);
4098 upath.Length += ro_u_globalroot.Length;
4100 PWSTR eoBuffer = upath.Buffer + (upath.Length / sizeof (WCHAR));
4101 /* Remove trailing slash if one exists. */
4102 if ((eoBuffer - upath.Buffer) > 3 && eoBuffer[-1] == L'\\')
4103 upath.Length -= sizeof (WCHAR);
4105 RtlInitEmptyUnicodeString (&win32,
4106 (PWCHAR) crealloc_abort (win32.Buffer,
4109 upath.Length + sizeof (WCHAR));
4110 RtlCopyUnicodeString (&win32, &upath);
4112 win32.Buffer[0] = L'\\';
4114 /* Make sure it's NUL-terminated. */
4115 win32.Buffer[win32.Length / sizeof (WCHAR)] = L'\0';
4117 /* Set drive_length, used in path conversion, and error code, used in
4118 spawn_guts to decide whether a native Win32 app can be started or not. */
4130 PWCHAR ptr = wcschr (win32.Buffer + 2, L'\\');
4132 ptr = wcschr (ptr + 1, L'\\');
4134 drive_length = ptr - win32.Buffer;
4136 drive_length = win32.Length / sizeof (WCHAR);
4138 if (inaccessible_path)
4140 else if (win32.Length > (MAX_PATH - 2) * sizeof (WCHAR))
4141 error = ENAMETOOLONG;
4145 /* Keep the Win32 CWD in sync. Don't check for error, other than for
4146 strace output. Try to keep overhead low. */
4147 override_win32_cwd (!nat_cwd, old_dismount_count);
4149 /* Eventually, create POSIX path if it's not set on entry. */
4153 posix_cwd = (const char *) tp.c_get ();
4154 mount_table->conv_to_posix_path (win32.Buffer, (char *) posix_cwd, 0);
4156 posix = (char *) crealloc_abort (posix, strlen (posix_cwd) + 1);
4157 stpcpy (posix, posix_cwd);
4159 cwd_lock.release ();
4164 cwdstuff::get_error_desc () const
4166 switch (cygheap->cwd.get_error ())
4169 return "has restricted permissions which render it\n"
4170 "inaccessible as Win32 working directory";
4172 return "is a virtual Cygwin directory which does\n"
4173 "not exist for a native Windows application";
4175 return "has a path longer than allowed for a\n"
4176 "Win32 working directory";
4180 /* That shouldn't occur, unless we defined a new error code
4181 in cwdstuff::set. */
4182 return "is not accessible for some unknown reason";
4185 /* Store incoming wchar_t path as current posix cwd. This is called from
4186 setlocale so that the cwd is always stored in the right charset. */
4188 cwdstuff::reset_posix (wchar_t *w_cwd)
4190 size_t len = sys_wcstombs (NULL, (size_t) -1, w_cwd);
4191 posix = (char *) crealloc_abort (posix, len + 1);
4192 sys_wcstombs (posix, len + 1, w_cwd);
4196 cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
4203 else if (buf == NULL)
4204 ulen = (unsigned) -1;
4211 cwd_lock.acquire ();
4216 tocopy = tp.c_get ();
4217 sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer,
4218 win32.Length / sizeof (WCHAR));
4223 debug_printf ("posix %s", posix);
4224 if (strlen (tocopy) >= ulen)
4232 buf = (char *) malloc (strlen (tocopy) + 1);
4233 strcpy (buf, tocopy);
4234 if (!buf[0]) /* Should only happen when chroot */
4238 cwd_lock.release ();
4241 syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
4242 buf, buf, ulen, need_posix, with_chroot, errno);
4247 int etc::curr_ix = 0;
4248 /* Note that the first elements of the below arrays are unused */
4249 bool etc::change_possible[MAX_ETC_FILES + 1];
4250 OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1];
4251 LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1];
4254 etc::init (int n, POBJECT_ATTRIBUTES attr)
4258 else if (++curr_ix <= MAX_ETC_FILES)
4261 api_fatal ("internal error");
4264 change_possible[n] = false;
4265 test_file_change (n);
4266 paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix);
4271 etc::test_file_change (int n)
4274 FILE_NETWORK_OPEN_INFORMATION fnoi;
4277 status = NtQueryFullAttributesFile (&fn[n], &fnoi);
4278 if (!NT_SUCCESS (status))
4281 memset (last_modified + n, 0, sizeof (last_modified[n]));
4282 debug_printf ("NtQueryFullAttributesFile (%S) failed, %p",
4283 fn[n].ObjectName, status);
4287 res = CompareFileTime ((FILETIME *) &fnoi.LastWriteTime,
4288 (FILETIME *) last_modified + n) > 0;
4289 last_modified[n].QuadPart = fnoi.LastWriteTime.QuadPart;
4292 paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4297 etc::dir_changed (int n)
4299 if (!change_possible[n])
4301 static HANDLE changed_h NO_COPY;
4307 OBJECT_ATTRIBUTES attr;
4309 path_conv dir ("/etc");
4310 status = NtOpenFile (&changed_h, SYNCHRONIZE | FILE_LIST_DIRECTORY,
4311 dir.get_object_attr (attr, sec_none_nih), &io,
4312 FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE);
4313 if (!NT_SUCCESS (status))
4316 system_printf ("NtOpenFile (%S) failed, %p",
4317 dir.get_nt_native_path (), status);
4319 changed_h = INVALID_HANDLE_VALUE;
4323 status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4325 FILE_NOTIFY_CHANGE_LAST_WRITE
4326 | FILE_NOTIFY_CHANGE_FILE_NAME,
4328 if (!NT_SUCCESS (status))
4331 system_printf ("NtNotifyChangeDirectoryFile (1) failed, %p",
4334 NtClose (changed_h);
4335 changed_h = INVALID_HANDLE_VALUE;
4338 memset (change_possible, true, sizeof (change_possible));
4341 if (changed_h == INVALID_HANDLE_VALUE)
4342 change_possible[n] = true;
4343 else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
4345 status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
4347 FILE_NOTIFY_CHANGE_LAST_WRITE
4348 | FILE_NOTIFY_CHANGE_FILE_NAME,
4350 if (!NT_SUCCESS (status))
4353 system_printf ("NtNotifyChangeDirectoryFile (2) failed, %p",
4356 NtClose (changed_h);
4357 changed_h = INVALID_HANDLE_VALUE;
4359 memset (change_possible, true, sizeof change_possible);
4363 paranoid_printf ("fn[%d] %S change_possible %d",
4364 n, fn[n].ObjectName, change_possible[n]);
4365 return change_possible[n];
4369 etc::file_changed (int n)
4372 if (dir_changed (n) && test_file_change (n))
4374 change_possible[n] = false; /* Change is no longer possible */
4375 paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
4379 /* No need to be reentrant or thread-safe according to SUSv3.
4380 / and \\ are treated equally. Leading drive specifiers are
4381 kept intact as far as it makes sense. Everything else is
4382 POSIX compatible. */
4384 basename (char *path)
4387 char *c, *d, *bs = path;
4389 if (!path || !*path)
4390 return strcpy (buf, ".");
4391 if (isalpha (path[0]) && path[1] == ':')
4393 else if (strspn (path, "/\\") > 1)
4395 c = strrchr (bs, '/');
4396 if ((d = strrchr (c ?: bs, '\\')) > c)
4400 /* Trailing (back)slashes are eliminated. */
4401 while (c && c > bs && c[1] == '\0')
4404 c = strrchr (bs, '/');
4405 if ((d = strrchr (c ?: bs, '\\')) > c)
4408 if (c && (c > bs || c[1]))
4413 stpncpy (buf, path, bs - path);
4414 stpcpy (buf + (bs - path), ".");
4420 /* No need to be reentrant or thread-safe according to SUSv3.
4421 / and \\ are treated equally. Leading drive specifiers and
4422 leading double (back)slashes are kept intact as far as it
4423 makes sense. Everything else is POSIX compatible. */
4425 dirname (char *path)
4428 char *c, *d, *bs = path;
4430 if (!path || !*path)
4431 return strcpy (buf, ".");
4432 if (isalpha (path[0]) && path[1] == ':')
4434 else if (strspn (path, "/\\") > 1)
4436 c = strrchr (bs, '/');
4437 if ((d = strrchr (c ?: bs, '\\')) > c)
4441 /* Trailing (back)slashes are eliminated. */
4442 while (c && c > bs && c[1] == '\0')
4445 c = strrchr (bs, '/');
4446 if ((d = strrchr (c ?: bs, '\\')) > c)
4453 /* More trailing (back)slashes are eliminated. */
4454 while (c > bs && (*c == '/' || *c == '\\'))
4462 stpncpy (buf, path, bs - path);
4463 stpcpy (buf + (bs - path), ".");