1 /* path.cc: path support.
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 /* This module's job is to
10 - convert between POSIX and Win32 style filenames,
11 - support the `mount' functionality,
12 - support symlinks for files and directories
14 Pathnames are handled as follows:
16 - A \ or : in a path denotes a pure windows spec.
17 - Paths beginning with // (or \\) are not translated (i.e. looked
18 up in the mount table) and are assumed to be UNC path names.
20 The goal in the above set of rules is to allow both POSIX and Win32
21 flavors of pathnames without either interfering. The rules are
22 intended to be as close to a superset of both as possible.
24 Note that you can have more than one path to a file. The mount
25 table is always prefered when translating Win32 paths to POSIX
26 paths. Win32 paths in mount table entries may be UNC paths or
27 standard Win32 paths starting with <drive-letter>:
29 Text vs Binary issues are not considered here in path style
30 decisions, although the appropriate flags are retrieved and
31 stored in various structures.
33 Removing mounted filesystem support would simplify things greatly,
34 but having it gives us a mechanism of treating disk that lives on a
35 UNIX machine as having UNIX semantics [it allows one to edit a text
36 file on that disk and not have cr's magically appear and perhaps
37 break apps running on UNIX boxes]. It also useful to be able to
38 layout a hierarchy without changing the underlying directories.
40 The semantics of mounting file systems is not intended to precisely
41 follow normal UNIX systems.
43 Each DOS drive is defined to have a current directory. Supporting
44 this would complicate things so for now things are defined so that
48 /* This file includes both the XPG and GNU basename functions, with the
49 former exported as "basename" for ABI compatibility but the latter
50 declared as such for source compatibility with glibc. This tells
51 <string.h> not to declare the GNU variant in order to prevent a conflicting
52 declaration error with the XPG variant implemented herein. */
53 #define basename basename
55 #include <w32api/winioctl.h>
56 #include <w32api/shlobj.h>
57 #include <sys/param.h>
58 #include <sys/cygwin.h>
66 #include "shared_info.h"
71 suffix_info stat_suffixes
[] =
74 suffix_info (".exe", 1),
80 char contents
[SYMLINK_MAX
+ 1];
85 unsigned pc_flags
; /* Relevant pathconv_arg flags from path_conv caller */
94 int check (char *path
, const suffix_info
*suffixes
, fs_info
&fs
,
95 path_conv_handle
&conv_hdl
);
97 bool parse_device (const char *);
98 int check_sysfile (HANDLE h
);
99 int check_shortcut (HANDLE h
);
100 int check_reparse_point (HANDLE h
, bool remote
);
101 int check_nfs_symlink (HANDLE h
);
102 int posixify (char *srcbuf
);
103 bool set_error (int);
106 muto NO_COPY
cwdstuff::cwd_lock
;
108 static const GUID GUID_shortcut
109 = { 0x00021401L
, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
113 WSH_FLAG_IDLIST
= 0x01, /* Contains an ITEMIDLIST. */
114 WSH_FLAG_FILE
= 0x02, /* Contains a file locator element. */
115 WSH_FLAG_DESC
= 0x04, /* Contains a description. */
116 WSH_FLAG_RELPATH
= 0x08, /* Contains a relative path. */
117 WSH_FLAG_WD
= 0x10, /* Contains a working dir. */
118 WSH_FLAG_CMDLINE
= 0x20, /* Contains command line args. */
119 WSH_FLAG_ICON
= 0x40 /* Contains a custom icon. */
122 struct win_shortcut_hdr
124 DWORD size
; /* Header size in bytes. Must contain 0x4c. */
125 GUID magic
; /* GUID of shortcut files. */
126 DWORD flags
; /* Content flags. See above. */
128 /* The next fields from attr to icon_no are always set to 0 in Cygwin
129 and U/Win shortcuts. */
130 DWORD attr
; /* Target file attributes. */
131 FILETIME ctime
; /* These filetime items are never touched by the */
132 FILETIME mtime
; /* system, apparently. Values don't matter. */
134 DWORD filesize
; /* Target filesize. */
135 DWORD icon_no
; /* Icon number. */
137 DWORD run
; /* Values defined in winuser.h. Use SW_NORMAL. */
138 DWORD hotkey
; /* Hotkey value. Set to 0. */
139 DWORD dummy
[2]; /* Future extension probably. Always 0. */
142 /* Return non-zero if PATH1 is a prefix of PATH2.
143 Both are assumed to be of the same path style and / vs \ usage.
145 LEN1 = strlen (PATH1). It's passed because often it's already known.
148 /foo/ is a prefix of /foo <-- may seem odd, but desired
149 /foo is a prefix of /foo/
150 / is a prefix of /foo/bar
151 / is not a prefix of foo/bar
152 foo/ is a prefix foo/bar
153 /foo is not a prefix of /foobar
157 path_prefix_p (const char *path1
, const char *path2
, int len1
,
158 bool caseinsensitive
)
160 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
161 if (len1
> 0 && isdirsep (path1
[len1
- 1]))
165 return isdirsep (path2
[0]) && !isdirsep (path2
[1]);
167 if (isdirsep (path2
[len1
]) || path2
[len1
] == 0 || path1
[len1
- 1] == ':')
168 return caseinsensitive
? strncasematch (path1
, path2
, len1
)
169 : !strncmp (path1
, path2
, len1
);
174 /* Return non-zero if paths match in first len chars.
175 Check is dependent of the case sensitivity setting. */
177 pathnmatch (const char *path1
, const char *path2
, int len
, bool caseinsensitive
)
179 return caseinsensitive
180 ? strncasematch (path1
, path2
, len
) : !strncmp (path1
, path2
, len
);
183 /* Return non-zero if paths match. Check is dependent of the case
184 sensitivity setting. */
186 pathmatch (const char *path1
, const char *path2
, bool caseinsensitive
)
188 return caseinsensitive
189 ? strcasematch (path1
, path2
) : !strcmp (path1
, path2
);
192 /* TODO: This function is used in mkdir and rmdir to generate correct
193 error messages in case of paths ending in /. or /.. components.
194 Right now, normalize_posix_path will just normalize
195 those components away, which changes the semantics. */
197 has_dot_last_component (const char *dir
, bool test_dot_dot
)
199 /* SUSv3: . and .. are not allowed as last components in various system
200 calls. Don't test for backslash path separator since that's a Win32
201 path following Win32 rules. */
202 const char *last_comp
= strchr (dir
, '\0');
204 if (last_comp
== dir
)
205 return false; /* Empty string. Probably shouldn't happen here? */
207 /* Detect run of trailing slashes */
208 while (last_comp
> dir
&& *--last_comp
== '/')
211 /* Detect just a run of slashes or a path that does not end with a slash. */
212 if (*last_comp
!= '.')
215 /* We know we have a trailing dot here. Check that it really is a standalone "."
216 path component by checking that it is at the beginning of the string or is
218 if (last_comp
== dir
|| *--last_comp
== '/')
221 /* If we're not checking for '..' we're done. Ditto if we're now pointing to
223 if (!test_dot_dot
|| *last_comp
!= '.')
224 return false; /* either not testing for .. or this was not '..' */
226 /* Repeat previous test for standalone or path component. */
227 return last_comp
== dir
|| last_comp
[-1] == '/';
230 /* Normalize a POSIX path.
231 All duplicate /'s, except for 2 leading /'s, are deleted.
232 The result is 0 for success, or an errno error value. */
235 normalize_posix_path (const char *src
, char *dst
, char *&tail
)
237 const char *in_src
= src
;
238 char *dst_start
= dst
;
239 bool check_parent
= false;
240 syscall_printf ("src %s", src
);
242 if ((isdrive (src
) && isdirsep (src
[2])) || *src
== '\\')
246 if (!isslash (src
[0]))
248 if (!cygheap
->cwd
.get (dst
))
250 tail
= strchr (tail
, '\0');
251 if (isslash (dst
[0]) && isslash (dst
[1]))
255 if (tail
== dst_start
+ 1 && *dst_start
== '/')
259 if (tail
> dst
&& !isslash (tail
[-1]))
262 /* Two leading /'s? If so, preserve them. */
263 else if (isslash (src
[1]) && !isslash (src
[2]))
273 /* Strip runs of /'s. */
295 if (!isslash (src
[1]))
298 else if (src
[2] && !isslash (src
[2]))
302 /* According to POSIX semantics all elements of path must
303 exist. To follow it, we must validate our path before
304 removing the trailing component. Check_parent is needed
305 for performance optimization, in order not to verify paths
306 which are already verified. For example this prevents
307 double check in case of foo/bar/../.. */
310 if (tail
> dst_start
) /* Don't check for / or // dir. */
313 debug_printf ("checking %s before '..'", dst
);
314 /* In conjunction with native and NFS symlinks,
315 this call can result in a recursion which eats
316 up our tmp_pathbuf buffers. This in turn results
317 in a api_fatal call. To avoid that, we're
318 checking our remaining buffers and return an
319 error code instead. Note that this only happens
320 if the path contains 15 or more relative native/NFS
321 symlinks with a ".." in the target path. */
323 if (!tp
.check_usage (4, 3))
325 path_conv
head (dst
, PC_SYM_FOLLOW
| PC_POSIX
);
328 /* At this point, dst is a normalized path. If the
329 normalized path created by path_conv does not
330 match the normalized path we're just testing, then
331 the path in dst contains native symlinks. If we
332 just plunge along, removing the previous path
333 component, we may end up removing a symlink from
334 the path and the resulting path will be invalid.
335 So we replace dst with what we found in head
336 instead. All the work replacing symlinks has been
337 done in that path anyway, so why repeat it? */
338 tail
= stpcpy (dst
, head
.get_posix ());
340 check_parent
= false;
342 while (tail
> dst_start
&& !isslash (*--tail
))
350 if ((tail
- dst
) >= NT_MAX_PATH
)
352 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src
);
360 debug_printf ("%s = normalize_posix_path (%s)", dst
, in_src
);
364 int err
= normalize_win32_path (in_src
, dst
, tail
);
366 for (char *p
= dst
; (p
= strchr (p
, '\\')); p
++)
372 path_conv::add_ext_from_sym (symlink_info
&sym
)
374 if (sym
.ext_here
&& *sym
.ext_here
)
376 suffix
= path
+ sym
.extn
;
377 if (sym
.ext_tacked_on
)
378 strcpy ((char *) suffix
, sym
.ext_here
);
382 static void __reg2
mkrelpath (char *dst
, bool caseinsensitive
);
385 mkrelpath (char *path
, bool caseinsensitive
)
388 char *cwd_win32
= tp
.c_get ();
389 if (!cygheap
->cwd
.get (cwd_win32
, 0))
392 unsigned cwdlen
= strlen (cwd_win32
);
393 if (!path_prefix_p (cwd_win32
, path
, cwdlen
, caseinsensitive
))
396 size_t n
= strlen (path
);
404 tail
+= isdirsep (cwd_win32
[cwdlen
- 1]) ? cwdlen
: cwdlen
+ 1;
406 memmove (path
, tail
, strlen (tail
) + 1);
412 path_conv::set_posix (const char *path_copy
)
416 size_t n
= strlen (path_copy
) + 1;
417 char *p
= (char *) crealloc_abort ((void *) posix_path
, n
);
418 posix_path
= (const char *) memcpy (p
, path_copy
, n
);
423 str2uni_cat (UNICODE_STRING
&tgt
, const char *srcstr
)
425 int len
= sys_mbstowcs (tgt
.Buffer
+ tgt
.Length
/ sizeof (WCHAR
),
426 (tgt
.MaximumLength
- tgt
.Length
) / sizeof (WCHAR
),
429 tgt
.Length
+= (len
- 1) * sizeof (WCHAR
);
433 get_nt_native_path (const char *path
, UNICODE_STRING
& upath
, bool dos
)
436 if (path
[0] == '/') /* special path w/o NT path representation. */
437 str2uni_cat (upath
, path
);
438 else if (path
[0] != '\\') /* X:\... or relative path. */
440 if (path
[1] == ':') /* X:\... */
442 RtlAppendUnicodeStringToString (&upath
, &ro_u_natp
);
443 str2uni_cat (upath
, path
);
444 /* The drive letter must be upper case. */
445 upath
.Buffer
[4] = towupper (upath
.Buffer
[4]);
446 transform_chars (&upath
, 7);
448 else /* relative path */
450 str2uni_cat (upath
, path
);
451 transform_chars (&upath
, 0);
454 else if (path
[1] != '\\') /* \Device\... */
455 str2uni_cat (upath
, path
);
456 else if ((path
[2] != '.' && path
[2] != '?')
457 || path
[3] != '\\') /* \\server\share\... */
459 RtlAppendUnicodeStringToString (&upath
, &ro_u_uncp
);
460 str2uni_cat (upath
, path
+ 2);
461 transform_chars (&upath
, 8);
463 else /* \\.\device or \\?\foo */
465 RtlAppendUnicodeStringToString (&upath
, &ro_u_natp
);
466 str2uni_cat (upath
, path
+ 4);
470 /* Unfortunately we can't just use transform_chars with the tfx_rev_chars
471 table since only leading and trailing spaces and dots are affected.
472 So we step to every backslash and fix surrounding dots and spaces.
473 That makes these broken filesystems a bit slower, but, hey. */
474 PWCHAR cp
= upath
.Buffer
+ 7;
475 PWCHAR cend
= upath
.Buffer
+ upath
.Length
/ sizeof (WCHAR
);
480 while (*ccp
== L
'.' || *ccp
== L
' ')
482 while (cp
[1] == L
' ')
485 while (*--cp
== L
'.' || *cp
== L
' ')
491 /* Handle with extrem care! Only used in a certain instance in try_to_bin.
492 Every other usage needs a careful check. */
494 path_conv::set_nt_native_path (PUNICODE_STRING new_path
)
496 wide_path
= (PWCHAR
) crealloc_abort (wide_path
, new_path
->MaximumLength
);
497 memcpy (wide_path
, new_path
->Buffer
, new_path
->Length
);
498 uni_path
.Length
= new_path
->Length
;
499 uni_path
.MaximumLength
= new_path
->MaximumLength
;
500 uni_path
.Buffer
= wide_path
;
504 path_conv::get_nt_native_path ()
514 uni_path
.MaximumLength
= (strlen (path
) + 10) * sizeof (WCHAR
);
515 wide_path
= (PWCHAR
) cmalloc_abort (HEAP_STR
, uni_path
.MaximumLength
);
516 uni_path
.Buffer
= wide_path
;
517 ::get_nt_native_path (path
, uni_path
, has_dos_filenames_only ());
524 path_conv::get_wide_win32_path (PWCHAR wc
)
526 get_nt_native_path ();
529 wcpcpy (wc
, wide_path
);
536 getfileattr (const char *path
, bool caseinsensitive
) /* path has to be always absolute. */
539 UNICODE_STRING upath
;
540 OBJECT_ATTRIBUTES attr
;
541 FILE_BASIC_INFORMATION fbi
;
546 InitializeObjectAttributes (&attr
, &upath
,
547 caseinsensitive
? OBJ_CASE_INSENSITIVE
: 0,
549 get_nt_native_path (path
, upath
, false);
551 status
= NtQueryAttributesFile (&attr
, &fbi
);
552 if (NT_SUCCESS (status
))
553 return fbi
.FileAttributes
;
555 if (status
!= STATUS_OBJECT_NAME_NOT_FOUND
556 && status
!= STATUS_NO_SUCH_FILE
) /* File not found on 9x share */
558 /* File exists but access denied. Try to get attribute through
560 UNICODE_STRING dirname
, basename
;
562 FILE_BOTH_DIR_INFORMATION fdi
;
564 RtlSplitUnicodePath (&upath
, &dirname
, &basename
);
565 InitializeObjectAttributes (&attr
, &dirname
,
566 caseinsensitive
? OBJ_CASE_INSENSITIVE
: 0,
568 status
= NtOpenFile (&dir
, SYNCHRONIZE
| FILE_LIST_DIRECTORY
,
569 &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
570 FILE_SYNCHRONOUS_IO_NONALERT
571 | FILE_OPEN_FOR_BACKUP_INTENT
572 | FILE_DIRECTORY_FILE
);
573 if (NT_SUCCESS (status
))
575 status
= NtQueryDirectoryFile (dir
, NULL
, NULL
, 0, &io
,
577 FileBothDirectoryInformation
,
578 TRUE
, &basename
, TRUE
);
580 if (NT_SUCCESS (status
) || status
== STATUS_BUFFER_OVERFLOW
)
581 return fdi
.FileAttributes
;
584 SetLastError (RtlNtStatusToDosError (status
));
585 return INVALID_FILE_ATTRIBUTES
;
588 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
589 passing to Win32 API routines.
591 If an error occurs, `error' is set to the errno value.
592 Otherwise it is set to 0.
595 SYMLINK_FOLLOW - convert to PATH symlink points to
596 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
597 SYMLINK_IGNORE - do not check PATH for symlinks
598 SYMLINK_CONTENTS - just return symlink contents
601 /* TODO: This implementation is only preliminary. For internal
602 purposes it's necessary to have a path_conv::check function which
603 takes a UNICODE_STRING src path, otherwise we waste a lot of time
604 for converting back and forth. The below implementation does
605 realy nothing but converting to char *, until path_conv handles
606 wide-char paths directly. */
608 path_conv::check (const UNICODE_STRING
*src
, unsigned opt
,
609 const suffix_info
*suffixes
)
612 char *path
= tp
.c_get ();
614 user_shared
->warned_msdos
= true;
615 sys_wcstombs (path
, NT_MAX_PATH
, src
->Buffer
, src
->Length
/ sizeof (WCHAR
));
616 path_conv::check (path
, opt
, suffixes
);
620 path_conv::check (const char *src
, unsigned opt
,
621 const suffix_info
*suffixes
)
623 /* The tmp_buf array is used when expanding symlinks. It is NT_MAX_PATH * 2
624 in length so that we can hold the expanded symlink plus a trailer. */
626 char *path_copy
= tp
.c_get ();
627 char *pathbuf
= tp
.c_get ();
628 char *tmp_buf
= tp
.t_get ();
629 char *THIS_path
= tp
.c_get ();
631 bool need_directory
= 0;
632 bool add_ext
= false;
634 char *tail
, *path_end
;
637 static path_conv last_path_conv
;
638 static char last_src
[CYG_MAX_PATH
];
640 if (*last_src
&& strcmp (last_src
, src
) == 0)
642 *this = last_path_conv
;
653 fileattr
= INVALID_FILE_ATTRIBUTES
;
654 caseinsensitive
= OBJ_CASE_INSENSITIVE
;
660 cfree (modifiable_path ());
663 close_conv_handle ();
667 cfree ((void *) posix_path
);
670 int component
= 0; // Number of translated components
672 if (!(opt
& PC_NULLEMPTY
))
680 bool is_msdos
= false;
681 /* This loop handles symlink expansion. */
684 is_relpath
= !isabspath (src
);
685 error
= normalize_posix_path (src
, path_copy
, tail
);
695 /* Detect if the user was looking for a directory. We have to strip
696 the trailing slash initially while trying to add extensions but
697 take it into account during processing */
698 if (tail
> path_copy
+ 2 && isslash (tail
[-1]))
705 /* Scan path_copy from right to left looking either for a symlink
706 or an actual existing file. If an existing file is found, just
707 return. If a symlink is found, exit the for loop.
708 Also: be careful to preserve the errno returned from
709 symlink.check as the caller may need it. */
710 /* FIXME: Do we have to worry about multiple \'s here? */
711 component
= 0; // Number of translated components
712 sym
.contents
[0] = '\0';
716 /* Make sure to check certain flags on last component only. */
717 for (unsigned pc_flags
= opt
& (PC_NO_ACCESS_CHECK
| PC_KEEP_HANDLE
);
721 const suffix_info
*suff
;
724 /* Don't allow symlink.check to set anything in the path_conv
725 class if we're working on an inner component of the path */
734 full_path
= THIS_path
;
737 retry_fs_via_processfd
:
739 /* Convert to native path spec sans symbolic link info. */
740 error
= mount_table
->conv_to_win32_path (path_copy
, full_path
,
741 dev
, &sym
.mount_flags
);
746 sym
.pc_flags
= pc_flags
;
754 if (iscygdrive_dev (dev
))
757 fileattr
= FILE_ATTRIBUTE_DIRECTORY
758 | FILE_ATTRIBUTE_READONLY
;
761 fileattr
= getfileattr (THIS_path
,
762 sym
.mount_flags
& MOUNT_NOPOSIX
);
767 else if (isdev_dev (dev
))
769 /* Make sure that the path handling goes on as with FH_FS. */
771 else if (isvirtual_dev (dev
))
773 /* FIXME: Calling build_fhandler here is not the right way to
775 fhandler_virtual
*fh
= (fhandler_virtual
*)
776 build_fh_dev (dev
, path_copy
);
777 virtual_ftype_t file_type
;
779 file_type
= virt_none
;
782 file_type
= fh
->exists ();
783 if (file_type
== virt_symlink
784 || file_type
== virt_fdsymlink
)
787 symlen
= sym
.set (fh
->get_filebuf ());
789 else if (file_type
== virt_fsdir
&& dev
== FH_PROCESSFD
)
791 /* FIXME: This is YA bad hack to workaround that
792 we're checking for isvirtual_dev at this point.
793 This should only happen if the file is actually
794 a virtual file, and NOT already if the preceeding
795 path components constitute a virtual file.
797 Anyway, what we do here is this: If the descriptor
798 symlink points to a dir, and if there are trailing
799 path components, it's actually pointing somewhere
800 else. The format_process_fd function returns the
801 full path, resolved symlink plus trailing path
802 components, in its filebuf. This is a POSIX path
803 we know nothing about, so we have to convert it to
804 native again, calling conv_to_win32_path. Since
805 basically nothing happened yet, just copy it over
806 into full_path and jump back to the
807 conv_to_win32_path call. What a mess. */
808 stpcpy (path_copy
, fh
->get_filebuf ());
810 goto retry_fs_via_processfd
;
819 fileattr
= FILE_ATTRIBUTE_DIRECTORY
;
826 /* Allow open/linkat to do the right thing. */
827 if (opt
& PC_SYM_NOFOLLOW_PROCFD
)
829 opt
&= ~PC_SYM_FOLLOW
;
830 sym
.path_flags
|= PATH_RESOLVE_PROCFD
;
834 goto is_virtual_symlink
;
846 dev
.parse (FH_SOCKET
);
851 /* Access to real file or directory via block device
852 entry in /proc/sys. Convert to real file and go with
855 goto is_fs_via_procsys
;
857 /* Block special device. If the trailing slash has been
858 requested, the target is the root directory of the
859 filesystem on this block device. So we convert this
860 to a real file and attach the backslash. */
861 if (component
== 0 && need_directory
)
864 strcat (full_path
, "\\");
865 fileattr
= FILE_ATTRIBUTE_DIRECTORY
866 | FILE_ATTRIBUTE_DEVICE
;
872 fileattr
= FILE_ATTRIBUTE_DEVICE
;
876 fileattr
= INVALID_FILE_ATTRIBUTES
;
877 goto virtual_component_retry
;
879 if (component
== 0 || dev
!= FH_NETDRIVE
)
880 mount_flags
|= MOUNT_RO
;
883 /* devn should not be a device. If it is, then stop parsing. */
884 else if (dev
!= FH_FS
)
887 mount_flags
= sym
.mount_flags
;
888 path_flags
= sym
.path_flags
;
894 goto out
; /* Found a device. Stop parsing. */
897 /* If path is only a drivename, Windows interprets it as the
898 current working directory on this drive instead of the root
899 dir which is what we want. So we need the trailing backslash
901 if (full_path
[0] && full_path
[1] == ':' && full_path
[2] == '\0')
907 /* If the incoming path was given in DOS notation, always treat
908 it as caseinsensitive,noacl path. This must be set before
909 calling sym.check, otherwise the path is potentially treated
912 sym
.mount_flags
|= MOUNT_NOPOSIX
| MOUNT_NOACL
;
916 symlen
= sym
.check (full_path
, suff
, fs
, conv_handle
);
927 dev
.parse (sym
.major
, sym
.minor
);
930 fileattr
= sym
.fileattr
;
934 if (sym
.path_flags
& PATH_SOCKET
)
941 fileattr
= sym
.fileattr
;
942 #ifdef __WITH_AF_UNIX
943 dev
.parse ((sym
.path_flags
& PATH_REP
) ? FH_UNIX
: FH_LOCAL
);
945 dev
.parse (FH_LOCAL
);
946 #endif /* __WITH_AF_UNIX */
948 mount_flags
= sym
.mount_flags
;
949 path_flags
= sym
.path_flags
;
955 /* Make sure that /dev always exists. */
956 fileattr
= isdev_dev (dev
) ? FILE_ATTRIBUTE_DIRECTORY
958 mount_flags
= sym
.mount_flags
;
959 path_flags
= sym
.path_flags
;
961 else if (isdev_dev (dev
))
963 /* If we're looking for a non-existing file below /dev,
964 make sure that the device type is converted to FH_FS, so
965 that subsequent code handles the file correctly. Unless
966 /dev itself doesn't exist on disk. In that case /dev
967 is handled as virtual filesystem, and virtual filesystems
968 are read-only. The PC_KEEP_HANDLE check allows to check
969 for a call from an informational system call. In that
970 case we just stick to ENOENT, and the device type doesn't
972 if (sym
.error
== ENOENT
&& !(opt
& PC_KEEP_HANDLE
))
978 /* If symlink.check found an existing non-symlink file, then
979 it sets the appropriate flag. It also sets any suffix found
981 if (!sym
.issymlink
&& sym
.fileattr
!= INVALID_FILE_ATTRIBUTES
)
986 else if (!(sym
.fileattr
& FILE_ATTRIBUTE_DIRECTORY
))
991 goto out
; // file found
993 /* Found a symlink if symlen > 0. If component == 0, then the
994 src path itself was a symlink. If !follow_mode then
995 we're done. Otherwise we have to insert the path found
996 into the full path that we are building and perform all of
997 these operations again on the newly derived path. */
1001 && (!(opt
& PC_SYM_FOLLOW
)
1002 || (is_known_reparse_point ()
1003 && (opt
& PC_SYM_NOFOLLOW_REP
))))
1005 /* Usually a trailing slash requires to follow a symlink,
1006 even with PC_SYM_NOFOLLOW. The reason is that "foo/"
1007 is equivalent to "foo/." so the symlink is in fact not
1008 the last path component.
1010 PC_SYM_NOFOLLOW_DIR is used to indicate that the
1011 last path component is the target symlink and the
1012 trailing slash is supposed to be ignored. */
1013 if (!need_directory
|| (opt
& PC_SYM_NOFOLLOW_DIR
))
1015 /* last component of path is a symlink. */
1016 set_symlink (symlen
);
1017 /* make sure not to set errno to ENOTDIR. */
1019 if (opt
& PC_SYM_CONTENTS
)
1021 strcpy (THIS_path
, sym
.contents
);
1028 /* Following a symlink we can't trust the collected
1029 filesystem information any longer. */
1031 /* Close handle, if we have any. Otherwise we're collecting
1032 handles while following symlinks. */
1033 conv_handle
.close ();
1036 else if (sym
.error
&& sym
.error
!= ENOENT
)
1041 /* No existing file found. */
1043 virtual_component_retry
:
1044 /* Find the new "tail" of the path, e.g. in '/for/bar/baz',
1045 /baz is the tail. */
1046 if (tail
!= path_end
)
1048 while (--tail
> path_copy
+ 1 && *tail
!= '/') {}
1049 /* Exit loop if there is no tail or we are at the
1050 beginning of a UNC path */
1051 if (tail
<= path_copy
+ 1)
1052 goto out
; // all done
1054 /* Haven't found an existing pathname component yet.
1055 Pinch off the tail and try again. */
1060 /* Arrive here if above loop detected a symlink. */
1061 if (++loop
> SYMLOOP_MAX
)
1063 error
= ELOOP
; // Eep.
1067 /* Place the link content, possibly with head and/or tail,
1071 if (isabspath (sym
.contents
))
1072 headptr
= tmp_buf
; /* absolute path */
1075 /* Copy the first part of the path (with ending /) and point to
1077 char *prevtail
= tail
;
1078 while (--prevtail
> path_copy
&& *prevtail
!= '/') {}
1079 int headlen
= prevtail
- path_copy
+ 1;;
1080 memcpy (tmp_buf
, path_copy
, headlen
);
1081 headptr
= &tmp_buf
[headlen
];
1084 /* Make sure there is enough space */
1085 if (headptr
+ symlen
>= tmp_buf
+ (2 * NT_MAX_PATH
))
1088 error
= ENAMETOOLONG
;
1089 set_path ("::ENAMETOOLONG::");
1093 /* Copy the symlink contents to the end of tmp_buf.
1095 for (char *p
= sym
.contents
; *p
; p
++)
1096 *headptr
++ = *p
== '\\' ? '/' : *p
;
1099 /* Copy any tail component (with the 0) */
1100 if (tail
++ < path_end
)
1102 /* Add a slash if needed. There is space. */
1103 if (*(headptr
- 1) != '/')
1105 int taillen
= path_end
- tail
+ 1;
1106 if (headptr
+ taillen
> tmp_buf
+ (2 * NT_MAX_PATH
))
1108 memcpy (headptr
, tail
, taillen
);
1111 /* Evaluate everything all over again. */
1115 if (!(opt
& PC_SYM_CONTENTS
))
1119 set_path (THIS_path
);
1121 add_ext_from_sym (sym
);
1122 if (dev
== FH_NETDRIVE
&& component
)
1124 /* This case indicates a non-existant resp. a non-retrievable
1125 share. This happens for instance if the share is a printer.
1126 In this case the path must not be treated like a FH_NETDRIVE,
1127 but like a FH_FS instead, so the usual open call for files
1131 else if (isproc_dev (dev
) && fileattr
== INVALID_FILE_ATTRIBUTES
)
1133 /* FIXME: Usually we don't set error to ENOENT if a file doesn't
1134 exist. This is typically indicated by the fileattr content.
1135 So, why here? The downside is that cygwin_conv_path just gets
1136 an error for these paths so it reports the error back to the
1137 application. Unlike in all other cases of non-existant files,
1138 for which check doesn't set error, so cygwin_conv_path just
1139 returns the path, as intended. */
1143 else if (!need_directory
|| error
)
1144 /* nothing to do */;
1145 else if (fileattr
== INVALID_FILE_ATTRIBUTES
)
1146 /* Reattach trailing dirsep in native path. */
1147 strcat (modifiable_path (), "\\");
1148 else if (fileattr
& FILE_ATTRIBUTE_DIRECTORY
)
1149 path_flags
&= ~PATH_SYMLINK
;
1152 debug_printf ("%s is a non-directory", path
);
1159 /* If FS hasn't been checked already in symlink_info::check,
1161 if (fs
.inited ()|| fs
.update (get_nt_native_path (), NULL
))
1163 /* Incoming DOS paths are treated like DOS paths in native
1164 Windows applications. No ACLs, just default settings. */
1166 fs
.has_acls (false);
1167 debug_printf ("this->path(%s), has_acls(%d)",
1168 path
, fs
.has_acls ());
1169 /* CV: We could use this->has_acls() but I want to make sure that
1170 we don't forget that the MOUNT_NOACL flag must be taken into
1172 if (!(mount_flags
& MOUNT_NOACL
) && fs
.has_acls ())
1173 set_exec (0); /* We really don't know if this is executable or
1174 not here but set it to not executable since
1175 it will be figured out later by anything
1176 which cares about this. */
1178 /* If the FS has been found to have unreliable inodes, note
1179 that in mount_flags. */
1180 if (!fs
.hasgood_inode ())
1181 mount_flags
|= MOUNT_IHASH
;
1182 /* If the OS is caseinsensitive or the FS is caseinsensitive,
1183 don't handle path casesensitive. */
1184 if (cygwin_shared
->obcaseinsensitive
|| fs
.caseinsensitive ())
1185 mount_flags
|= MOUNT_NOPOSIX
;
1186 caseinsensitive
= (mount_flags
& MOUNT_NOPOSIX
)
1187 ? OBJ_CASE_INSENSITIVE
: 0;
1188 if (exec_state () != dont_know_if_executable
)
1192 else if (issymlink () || issocket ())
1196 if (opt
& PC_NOFULL
)
1200 mkrelpath (this->modifiable_path (), !!caseinsensitive
);
1201 /* Invalidate wide_path so that wide relpath can be created
1202 in later calls to get_nt_native_path or get_wide_win32_path. */
1209 size_t n
= strlen (this->path
);
1210 /* Do not add trailing \ to UNC device names like \\.\a: */
1211 if (this->path
[n
- 1] != '\\' &&
1212 (strncmp (this->path
, "\\\\.\\", 4) != 0))
1214 this->modifiable_path ()[n
] = '\\';
1215 this->modifiable_path ()[n
+ 1] = '\0';
1221 path_flags
|= PATH_OPEN
;
1224 path_flags
|= PATH_CTTY
;
1228 if (tail
< path_end
&& tail
> path_copy
+ 1)
1230 set_posix (path_copy
);
1236 last_path_conv
= *this;
1237 strcpy (last_src
, src
);
1258 path_conv::serialize (HANDLE h
, unsigned int &n
) const
1261 size_t nlen
= 0, plen
= 0;
1265 nlen
= strlen (path
) + 1;
1267 plen
= strlen (posix_path
) + 1;
1268 n
= sizeof (pc_flat
) + nlen
+ plen
;
1269 pcf
= (pc_flat
*) cmalloc (HEAP_COMMUNE
, n
);
1275 memcpy ((void *) &pcf
->pc
, this, sizeof *this);
1277 pcf
->name_len
= nlen
;
1278 pcf
->posix_len
= plen
;
1281 p
= stpcpy (p
, path
) + 1;
1283 stpcpy (p
, posix_path
);
1288 path_conv::deserialize (void *bufp
)
1290 pc_flat
*pcf
= (pc_flat
*) bufp
;
1294 memcpy ((void *) this, &pcf
->pc
, sizeof *this);
1295 wide_path
= uni_path
.Buffer
= NULL
;
1296 uni_path
.MaximumLength
= uni_path
.Length
= 0;
1297 path
= posix_path
= NULL
;
1306 dev
.parse (pcf
->pc
.dev
);
1312 path_conv::~path_conv ()
1316 cfree ((void *) posix_path
);
1321 cfree (modifiable_path ());
1329 close_conv_handle ();
1333 path_conv::is_binary ()
1336 PWCHAR bintest
= tp
.w_get ();
1339 return GetBinaryTypeW (get_wide_win32_path (bintest
), &bin
)
1340 && (bin
== SCS_32BIT_BINARY
|| bin
== SCS_64BIT_BINARY
);
1343 /* Helper function to fill the fai datastructure for a file. */
1345 file_get_fai (HANDLE h
, PFILE_ALL_INFORMATION pfai
)
1350 /* Some FSes (Netapps) don't implement FileNetworkOpenInformation. */
1351 status
= NtQueryInformationFile (h
, &io
, pfai
, sizeof *pfai
,
1352 FileAllInformation
);
1353 if (likely (status
== STATUS_BUFFER_OVERFLOW
))
1354 status
= STATUS_SUCCESS
;
1355 /* Filesystems with broken FileAllInformation exist, too. See the thread
1356 starting with https://cygwin.com/ml/cygwin/2016-07/msg00350.html. */
1357 else if (!NT_SUCCESS (status
) && status
!= STATUS_ACCESS_DENIED
)
1359 memset (pfai
, 0, sizeof *pfai
);
1360 status
= NtQueryInformationFile (h
, &io
, &pfai
->BasicInformation
,
1361 sizeof pfai
->BasicInformation
,
1362 FileBasicInformation
);
1363 if (NT_SUCCESS (status
))
1365 /* The return value of FileInternalInformation is largely ignored.
1366 We only make absolutely sure the inode number is set to 0 in
1368 status
= NtQueryInformationFile (h
, &io
, &pfai
->InternalInformation
,
1369 sizeof pfai
->InternalInformation
,
1370 FileInternalInformation
);
1371 if (!NT_SUCCESS (status
))
1372 pfai
->InternalInformation
.IndexNumber
.QuadPart
= 0LL;
1373 status
= NtQueryInformationFile (h
, &io
, &pfai
->StandardInformation
,
1374 sizeof pfai
->StandardInformation
,
1375 FileStandardInformation
);
1381 /* Normalize a Win32 path.
1382 /'s are converted to \'s in the process.
1383 All duplicate \'s, except for 2 leading \'s, are deleted.
1385 The result is 0 for success, or an errno error value.
1386 FIXME: A lot of this should be mergeable with the POSIX critter. */
1388 normalize_win32_path (const char *src
, char *dst
, char *&tail
)
1390 const char *src_start
= src
;
1391 const char *dst_start
= dst
;
1392 bool beg_src_slash
= isdirsep (src
[0]);
1395 /* Skip Win32 long path name prefix and NT object directory prefix. */
1396 if (beg_src_slash
&& (src
[1] == '?' || isdirsep (src
[1]))
1397 && src
[2] == '?' && isdirsep (src
[3]))
1400 if (isdrive (src
) && (isdirsep (src
[2]) || !src
[2]))
1401 beg_src_slash
= false;
1402 else if (!strncmp (src
, "UNC", 3) && isdirsep (src
[3]))
1403 /* native UNC path */
1404 src
+= 2; /* Fortunately the first char is not copied... */
1408 if (beg_src_slash
&& isdirsep (src
[1]))
1410 if (isdirsep (src
[2]))
1412 /* More than two slashes are just folded into one. */
1414 while (isdirsep (src
[1]))
1419 /* Two slashes start a network or device path. */
1422 if (src
[1] == '.' && isdirsep (src
[2]))
1430 /* If backslash is missing in src, add one. */
1431 if (!isdirsep (src
[0]))
1434 if (tail
== dst_start
)
1438 /* Always convert drive letter to uppercase for case sensitivity. */
1439 *tail
++ = cyg_toupper (*src
++);
1442 /* If backslash is missing in src, add one. */
1443 if (!isdirsep (src
[0]))
1446 else if (*src
!= '/')
1448 /* Make sure dst points to the rightmost backslash which must not
1449 be backtracked over during ".." evaluation. This is either
1450 the backslash after the network path prefix (i.e. "\\") or
1451 the backslash after a drive letter (i.e. C:\"). */
1454 tail
+= cygheap
->cwd
.get_drive (dst
);
1455 /* network path, drive == '\\\\'? Decrement tail to avoid
1456 triple backslash in output. */
1461 else if (cygheap
->cwd
.get (dst
, 0))
1463 tail
= strchr (tail
, '\0');
1464 if (tail
[-1] != '\\')
1471 return get_errno ();
1475 /* At this point dst points to the first backslash, even if it only gets
1476 written in the first iteration of the following loop. Backing up to
1477 handle ".." components can not underrun that border (thus avoiding
1478 subsequent buffer underruns with fatal results). */
1481 /* Strip duplicate /'s. */
1482 if (isdirsep (src
[0]) && isdirsep (src
[1]))
1485 else if (src
[0] == '.' && isdirsep (src
[1])
1486 && (src
== src_start
|| isdirsep (src
[-1])))
1489 /* Skip /'s to the next path component. */
1490 while (isdirsep (*src
))
1494 /* Backup if "..". */
1495 else if (src
[0] == '.' && src
[1] == '.' && tail
[-1] == '\\')
1497 if (!isdirsep (src
[2]) && src
[2] != '\0')
1501 /* Back up over /, but not if it's the first one. */
1504 /* Now back up to the next /. */
1505 while (tail
> dst
+ 1 && tail
[-1] != '\\' && tail
[-2] != ':')
1508 /* Skip /'s to the next path component. */
1509 while (isdirsep (*src
))
1513 /* Otherwise, add char to result. */
1522 if ((tail
- dst
) >= NT_MAX_PATH
)
1523 return ENAMETOOLONG
;
1525 if (tail
> dst
+ 1 && tail
[-1] == '.' && tail
[-2] == '\\')
1528 debug_printf ("%s = normalize_win32_path (%s)", dst_start
, src_start
);
1532 /* Various utilities. */
1534 /* nofinalslash: Remove trailing / and \ from SRC (except for the
1535 first one). It is ok for src == dst. */
1538 nofinalslash (const char *src
, char *dst
)
1540 int len
= strlen (src
);
1542 memcpy (dst
, src
, len
+ 1);
1543 while (len
> 1 && isdirsep (dst
[--len
]))
1547 /* conv_path_list: Convert a list of path names to/from Win32/POSIX. */
1550 conv_path_list (const char *src
, char *dst
, size_t size
,
1551 cygwin_conv_path_t what
)
1554 char src_delim
, dst_delim
;
1556 bool env_cvt
= false;
1558 if (what
== (cygwin_conv_path_t
) ENV_CVT
)
1560 what
= CCP_WIN_A_TO_POSIX
| CCP_RELATIVE
;
1563 if ((what
& CCP_CONVTYPE_MASK
) == CCP_WIN_A_TO_POSIX
)
1575 len
= strlen (src
) + 1;
1576 if (len
<= NT_MAX_PATH
* sizeof (WCHAR
))
1577 srcbuf
= (char *) tp
.w_get ();
1579 srcbuf
= (char *) alloca (len
);
1583 bool saw_empty
= false;
1586 char *srcpath
= srcbuf
;
1587 char *s
= strccpy (srcpath
, &src
, src_delim
);
1588 size_t len
= s
- srcpath
;
1589 if (len
>= NT_MAX_PATH
)
1594 /* Paths in Win32 path lists in the environment (%Path%), are often
1595 enclosed in quotes (usually paths with spaces). Trailing backslashes
1596 are common, too. Remove them. */
1599 if (*srcpath
== '"')
1605 while (len
&& s
[-1] == '\\')
1614 err
= cygwin_conv_path (what
, srcpath
, d
, size
- (d
- dst
));
1616 else if ((what
& CCP_CONVTYPE_MASK
) == CCP_POSIX_TO_WIN_A
)
1619 err
= cygwin_conv_path (what
, ".", d
, size
- (d
- dst
));
1629 d
= strchr (d
, '\0');
1643 /********************** Symbolic Link Support **************************/
1645 /* Create a symlink from FROMPATH to TOPATH. */
1648 symlink (const char *oldpath
, const char *newpath
)
1650 path_conv win32_newpath
;
1654 if (!*oldpath
|| !*newpath
)
1660 /* Trailing dirsep is a no-no, only errno differs. */
1661 bool has_trailing_dirsep
= isdirsep (newpath
[strlen (newpath
) - 1]);
1662 win32_newpath
.check (newpath
,
1663 PC_SYM_NOFOLLOW
| PC_SYM_NOFOLLOW_DIR
| PC_POSIX
,
1666 if (win32_newpath
.error
|| has_trailing_dirsep
)
1668 set_errno (win32_newpath
.error
?:
1669 win32_newpath
.exists () ? EEXIST
: ENOENT
);
1673 return symlink_worker (oldpath
, win32_newpath
, false);
1675 __except (EFAULT
) {}
1681 symlink_nfs (const char *oldpath
, path_conv
&win32_newpath
)
1683 /* On NFS, create symlinks by calling NtCreateFile with an EA of type
1684 NfsSymlinkTargetName containing ... the symlink target name. */
1686 PFILE_FULL_EA_INFORMATION pffei
;
1689 OBJECT_ATTRIBUTES attr
;
1692 pffei
= (PFILE_FULL_EA_INFORMATION
) tp
.w_get ();
1693 pffei
->NextEntryOffset
= 0;
1695 pffei
->EaNameLength
= sizeof (NFS_SYML_TARGET
) - 1;
1696 char *EaValue
= stpcpy (pffei
->EaName
, NFS_SYML_TARGET
) + 1;
1697 pffei
->EaValueLength
= sizeof (WCHAR
) *
1698 (sys_mbstowcs ((PWCHAR
) EaValue
, NT_MAX_PATH
, oldpath
) - 1);
1699 status
= NtCreateFile (&fh
, FILE_WRITE_DATA
| FILE_WRITE_EA
| SYNCHRONIZE
,
1700 win32_newpath
.get_object_attr (attr
, sec_none_nih
),
1701 &io
, NULL
, FILE_ATTRIBUTE_SYSTEM
,
1702 FILE_SHARE_VALID_FLAGS
, FILE_CREATE
,
1703 FILE_SYNCHRONOUS_IO_NONALERT
1704 | FILE_OPEN_FOR_BACKUP_INTENT
,
1705 pffei
, NT_MAX_PATH
* sizeof (WCHAR
));
1706 if (!NT_SUCCESS (status
))
1708 __seterrno_from_nt_status (status
);
1715 /* Count backslashes between s and e. */
1717 cnt_bs (PWCHAR s
, PWCHAR e
)
1727 #ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
1728 #define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 2
1732 symlink_native (const char *oldpath
, path_conv
&win32_newpath
)
1735 path_conv win32_oldpath
;
1736 PUNICODE_STRING final_oldpath
, final_newpath
;
1737 UNICODE_STRING final_oldpath_buf
;
1740 if (isabspath (oldpath
))
1742 win32_oldpath
.check (oldpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
1743 final_oldpath
= win32_oldpath
.get_nt_native_path ();
1747 /* The symlink target is relative to the directory in which
1748 the symlink gets created, not relative to the cwd. Therefore
1749 we have to mangle the path quite a bit before calling path_conv. */
1750 ssize_t len
= strrchr (win32_newpath
.get_posix (), '/')
1751 - win32_newpath
.get_posix () + 1;
1752 char *absoldpath
= tp
.t_get ();
1753 stpcpy (stpncpy (absoldpath
, win32_newpath
.get_posix (), len
),
1755 win32_oldpath
.check (absoldpath
, PC_SYM_NOFOLLOW
, stat_suffixes
);
1757 /* Try hard to keep Windows symlink path relative. */
1759 /* 1. Find common path prefix. Skip leading \\?\, but take pre-increment
1760 of the following loop into account. */
1761 PWCHAR c_old
= win32_oldpath
.get_nt_native_path ()->Buffer
+ 3;
1762 PWCHAR c_new
= win32_newpath
.get_nt_native_path ()->Buffer
+ 3;
1763 /* Windows compatible == always check case insensitive. */
1764 while (towupper (*++c_old
) == towupper (*++c_new
))
1766 /* The last component could share a common prefix, so make sure we end
1767 up on the first char after the last common backslash. */
1768 while (c_old
[-1] != L
'\\')
1771 /* 2. Check if prefix is long enough. The prefix must at least points to
1772 a complete device: \\?\X:\ or \\?\UNC\server\share\ are the minimum
1773 prefix strings. We start counting behind the \\?\ for speed. */
1774 int num
= cnt_bs (win32_oldpath
.get_nt_native_path ()->Buffer
+ 4, c_old
);
1775 if (num
< 1 /* locale drive. */
1776 || (win32_oldpath
.get_nt_native_path ()->Buffer
[5] != L
':'
1777 && num
< 3)) /* UNC path. */
1779 /* 3a. No valid common path prefix: Create absolute symlink. */
1780 final_oldpath
= win32_oldpath
.get_nt_native_path ();
1784 /* 3b. Common path prefx. Count number of additional directories
1785 in symlink's path, and prepend as much ".." path components
1786 to the target path. */
1787 PWCHAR e_new
= win32_newpath
.get_nt_native_path ()->Buffer
1788 + win32_newpath
.get_nt_native_path ()->Length
1790 num
= cnt_bs (c_new
, e_new
);
1791 final_oldpath
= &final_oldpath_buf
;
1792 final_oldpath
->Buffer
= tp
.w_get ();
1793 PWCHAR e_old
= final_oldpath
->Buffer
;
1795 e_old
= wcpcpy (e_old
, L
"..\\");
1796 wcpcpy (e_old
, c_old
);
1799 /* If the symlink target doesn't exist, don't create native symlink.
1800 Otherwise the directory flag in the symlink is potentially wrong
1801 when the target comes into existence, and native tools will fail.
1802 This is so screwball. This is no problem on AFS, fortunately. */
1803 if (!win32_oldpath
.exists () && !win32_oldpath
.fs_is_afs ())
1805 SetLastError (ERROR_FILE_NOT_FOUND
);
1808 /* Don't allow native symlinks to Cygwin special files. However, the
1809 caller shoud know because this case shouldn't be covered by the
1810 default "nativestrict" behaviour, so we use a special return code. */
1811 if (win32_oldpath
.isspecial ())
1813 /* Convert native paths to Win32 UNC paths. */
1814 final_newpath
= win32_newpath
.get_nt_native_path ();
1815 final_newpath
->Buffer
[1] = L
'\\';
1816 /* oldpath may be relative. Make sure to convert only absolute paths
1818 if (final_oldpath
->Buffer
[0] == L
'\\')
1820 /* Starting with Windows 8.1, the ShellExecuteW function does not
1821 handle the long path prefix correctly for symlink targets. Thus,
1822 we create simple short paths < MAX_PATH without long path prefix. */
1823 if (RtlEqualUnicodePathPrefix (final_oldpath
, &ro_u_uncp
, TRUE
)
1824 && final_oldpath
->Length
< (MAX_PATH
+ 6) * sizeof (WCHAR
))
1826 final_oldpath
->Buffer
+= 6;
1827 final_oldpath
->Buffer
[0] = L
'\\';
1829 else if (final_oldpath
->Length
< (MAX_PATH
+ 4) * sizeof (WCHAR
))
1830 final_oldpath
->Buffer
+= 4;
1831 else /* Stick to long path, fix native prefix for Win32 API calls. */
1832 final_oldpath
->Buffer
[1] = L
'\\';
1834 /* Try to create native symlink. */
1835 flags
= win32_oldpath
.isdir () ? SYMBOLIC_LINK_FLAG_DIRECTORY
: 0;
1836 if (wincap
.has_unprivileged_createsymlink ())
1837 flags
|= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
;
1838 if (!CreateSymbolicLinkW (final_newpath
->Buffer
, final_oldpath
->Buffer
,
1841 /* Repair native newpath, we still need it. */
1842 final_newpath
->Buffer
[1] = L
'?';
1848 #ifndef IO_REPARSE_TAG_LX_SYMLINK
1849 #define IO_REPARSE_TAG_LX_SYMLINK (0xa000001d)
1852 typedef struct _REPARSE_LX_SYMLINK_BUFFER
1855 WORD ReparseDataLength
;
1858 DWORD FileType
; /* Take member name with a grain of salt. Value is
1859 apparently always 2 for symlinks. */
1860 char PathBuffer
[1];/* POSIX path as given to symlink(2).
1861 Path is not \0 terminated.
1862 Length is ReparseDataLength - sizeof (FileType).
1864 Chars given in incompatible codesets, e. g. umlauts
1865 in ISO-8859-x, are converted to the Unicode
1866 REPLACEMENT CHARACTER 0xfffd == \xef\xbf\bd */
1867 } LxSymlinkReparseBuffer
;
1868 } REPARSE_LX_SYMLINK_BUFFER
,*PREPARSE_LX_SYMLINK_BUFFER
;
1871 symlink_wsl (const char *oldpath
, path_conv
&win32_newpath
)
1874 PREPARSE_LX_SYMLINK_BUFFER rpl
= (PREPARSE_LX_SYMLINK_BUFFER
) tp
.c_get ();
1875 char *path_buf
= rpl
->LxSymlinkReparseBuffer
.PathBuffer
;
1876 const int max_pathlen
= MAXIMUM_REPARSE_DATA_BUFFER_SIZE
1877 - offsetof (REPARSE_LX_SYMLINK_BUFFER
,
1878 LxSymlinkReparseBuffer
.PathBuffer
);
1879 PWCHAR utf16
= tp
.w_get ();
1882 OBJECT_ATTRIBUTES attr
;
1886 rpl
->ReparseTag
= IO_REPARSE_TAG_LX_SYMLINK
;
1888 rpl
->LxSymlinkReparseBuffer
.FileType
= 2;
1889 /* Convert cygdrive prefix to "/mnt" for WSL compatibility, but only if
1890 cygdrive prefix is not "/", otherwise suffer random "/mnt" symlinks... */
1891 if (mount_table
->cygdrive_len
> 1
1892 && path_prefix_p (mount_table
->cygdrive
, oldpath
,
1893 mount_table
->cygdrive_len
, false))
1894 stpcpy (stpcpy (path_buf
, "/mnt"),
1895 oldpath
+ mount_table
->cygdrive_len
- 1);
1897 *stpncpy (path_buf
, oldpath
, max_pathlen
) = '\0';
1898 /* Convert target path to UTF-16 and then back to UTF-8 to make sure the
1899 WSL symlink is in UTF-8, independent of the current Cygwin codeset. */
1900 sys_mbstowcs (utf16
, NT_MAX_PATH
, path_buf
);
1901 len
= WideCharToMultiByte (CP_UTF8
, 0, utf16
, -1, path_buf
, max_pathlen
,
1903 /* Length is omitting trailing \0. */
1904 rpl
->ReparseDataLength
= sizeof (DWORD
) + len
- 1;
1905 /* Create reparse point. */
1906 status
= NtCreateFile (&fh
, DELETE
| FILE_GENERIC_WRITE
1907 | READ_CONTROL
| WRITE_DAC
,
1908 win32_newpath
.get_object_attr (attr
, sec_none_nih
),
1909 &io
, NULL
, FILE_ATTRIBUTE_NORMAL
,
1910 FILE_SHARE_VALID_FLAGS
, FILE_CREATE
,
1911 FILE_SYNCHRONOUS_IO_NONALERT
1912 | FILE_NON_DIRECTORY_FILE
1913 | FILE_OPEN_FOR_BACKUP_INTENT
1914 | FILE_OPEN_REPARSE_POINT
,
1916 if (!NT_SUCCESS (status
))
1918 SetLastError (RtlNtStatusToDosError (status
));
1921 set_created_file_access (fh
, win32_newpath
, S_IFLNK
| STD_RBITS
| STD_WBITS
);
1922 status
= NtFsControlFile (fh
, NULL
, NULL
, NULL
, &io
, FSCTL_SET_REPARSE_POINT
,
1923 (LPVOID
) rpl
, REPARSE_DATA_BUFFER_HEADER_SIZE
1924 + rpl
->ReparseDataLength
,
1926 if (!NT_SUCCESS (status
))
1928 SetLastError (RtlNtStatusToDosError (status
));
1929 FILE_DISPOSITION_INFORMATION fdi
= { TRUE
};
1930 status
= NtSetInformationFile (fh
, &io
, &fdi
, sizeof fdi
,
1931 FileDispositionInformation
);
1933 if (!NT_SUCCESS (status
))
1934 debug_printf ("Setting delete dispostion failed, status = %y", status
);
1942 symlink_worker (const char *oldpath
, path_conv
&win32_newpath
, bool isdevice
)
1950 /* POSIX says that empty 'newpath' is invalid input while empty
1951 'oldpath' is valid -- it's symlink resolver job to verify if
1952 symlink contents point to existing filesystem object */
1955 if (strlen (oldpath
) > SYMLINK_MAX
)
1957 set_errno (ENAMETOOLONG
);
1961 /* Default symlink type is determined by global allow_winsymlinks
1962 variable. Device files are always shortcuts. */
1963 wsym_type
= isdevice
? WSYM_lnk
: allow_winsymlinks
;
1964 /* NFS has its own, dedicated way to create symlinks. */
1965 if (win32_newpath
.fs_is_nfs ())
1966 wsym_type
= WSYM_nfs
;
1967 /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O
1968 attribute. Therefore we create symlinks on MVFS always as shortcuts. */
1969 else if (win32_newpath
.fs_is_mvfs ())
1970 wsym_type
= WSYM_lnk
;
1971 /* AFS only supports native symlinks. */
1972 else if (win32_newpath
.fs_is_afs ())
1973 wsym_type
= WSYM_nativestrict
;
1974 /* Don't try native symlinks on FSes not supporting reparse points. */
1975 else if ((wsym_type
== WSYM_native
|| wsym_type
== WSYM_nativestrict
)
1976 && !(win32_newpath
.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS
))
1977 wsym_type
= WSYM_sysfile
;
1979 /* Attach .lnk suffix when shortcut is requested. */
1980 if (wsym_type
== WSYM_lnk
&& !win32_newpath
.exists ()
1981 && (isdevice
|| !win32_newpath
.fs_is_nfs ()))
1983 char *newplnk
= tp
.c_get ();
1984 stpcpy (stpcpy (newplnk
, win32_newpath
.get_posix ()), ".lnk");
1985 win32_newpath
.check (newplnk
, PC_SYM_NOFOLLOW
| PC_POSIX
);
1988 if (win32_newpath
.error
)
1990 set_errno (win32_newpath
.error
);
1994 syscall_printf ("symlink (%s, %S) wsym_type %d", oldpath
,
1995 win32_newpath
.get_nt_native_path (), wsym_type
);
1997 if ((!isdevice
&& win32_newpath
.exists ())
1998 || (win32_newpath
.isdevice () && !win32_newpath
.is_fs_special ()))
2004 /* Handle NFS, native symlinks and WSL symlinks in their own functions. */
2008 res
= symlink_nfs (oldpath
, win32_newpath
);
2011 case WSYM_nativestrict
:
2012 res
= symlink_native (oldpath
, win32_newpath
);
2015 /* Strictly native? Too bad, unless the target is a Cygwin
2017 if (res
== -1 && wsym_type
== WSYM_nativestrict
)
2022 /* Otherwise, fall back to default symlink type. */
2023 wsym_type
= WSYM_sysfile
;
2026 if (win32_newpath
.fs_flags () & FILE_SUPPORTS_REPARSE_POINTS
)
2028 res
= symlink_wsl (oldpath
, win32_newpath
);
2032 /* On FSes not supporting reparse points, or in case of an error
2033 creating the WSL symlink, fall back to creating the plain old
2034 SYSTEM file symlink. */
2040 if (wsym_type
== WSYM_lnk
)
2042 path_conv win32_oldpath
;
2043 ITEMIDLIST
*pidl
= NULL
;
2044 size_t full_len
= 0;
2045 unsigned short oldpath_len
, desc_len
, relpath_len
, pidl_len
= 0;
2046 char desc
[MAX_PATH
+ 1], *relpath
;
2050 /* First create an IDLIST to learn how big our shortcut is
2054 /* The symlink target is relative to the directory in which the
2055 symlink gets created, not relative to the cwd. Therefore we
2056 have to mangle the path quite a bit before calling path_conv.*/
2057 if (isabspath (oldpath
))
2058 win32_oldpath
.check (oldpath
,
2063 len
= strrchr (win32_newpath
.get_posix (), '/')
2064 - win32_newpath
.get_posix () + 1;
2065 char *absoldpath
= tp
.t_get ();
2066 stpcpy (stpncpy (absoldpath
, win32_newpath
.get_posix (),
2069 win32_oldpath
.check (absoldpath
, PC_SYM_NOFOLLOW
,
2072 if (SUCCEEDED (SHGetDesktopFolder (&psl
)))
2074 WCHAR wc_path
[win32_oldpath
.get_wide_win32_path_len () + 1];
2075 win32_oldpath
.get_wide_win32_path (wc_path
);
2076 /* Amazing but true: Even though the ParseDisplayName method
2077 takes a wide char path name, it does not understand the
2078 Win32 prefix for long pathnames! So we have to tack off
2079 the prefix and convert the path to the "normal" syntax
2080 for ParseDisplayName. */
2081 PWCHAR wc
= wc_path
+ 4;
2082 if (wc
[1] != L
':') /* native UNC path */
2085 if (SUCCEEDED (res
= psl
->ParseDisplayName (NULL
, NULL
, wc
,
2091 for (p
= pidl
; p
->mkid
.cb
> 0;
2092 p
= (ITEMIDLIST
*)((char *) p
+ p
->mkid
.cb
))
2094 pidl_len
= (char *) p
- (char *) pidl
+ 2;
2099 /* Compute size of shortcut file. */
2100 full_len
= sizeof (win_shortcut_hdr
);
2102 full_len
+= sizeof (unsigned short) + pidl_len
;
2103 oldpath_len
= strlen (oldpath
);
2104 /* Unfortunately the length of the description is restricted to a
2105 length of 2000 bytes. We don't want to add considerations for
2106 the different lengths and even 2000 bytes is not enough for long
2107 path names. So what we do here is to set the description to the
2108 POSIX path only if the path is not longer than MAX_PATH characters.
2109 We append the full path name after the regular shortcut data
2110 (see below), which works fine with Windows Explorer as well
2111 as older Cygwin versions (as long as the whole file isn't bigger
2112 than 8K). The description field is only used for backward
2113 compatibility to older Cygwin versions and those versions are
2114 not capable of handling long path names anyway. */
2115 desc_len
= stpcpy (desc
, oldpath_len
> MAX_PATH
2116 ? "[path too long]" : oldpath
) - desc
;
2117 full_len
+= sizeof (unsigned short) + desc_len
;
2118 /* Devices get the oldpath string unchanged as relative path. */
2121 relpath_len
= oldpath_len
;
2122 stpcpy (relpath
= tp
.c_get (), oldpath
);
2126 relpath_len
= strlen (win32_oldpath
.get_win32 ());
2127 stpcpy (relpath
= tp
.c_get (), win32_oldpath
.get_win32 ());
2129 full_len
+= sizeof (unsigned short) + relpath_len
;
2130 full_len
+= sizeof (unsigned short) + oldpath_len
;
2131 /* 1 byte more for trailing 0 written by stpcpy. */
2132 if (full_len
< NT_MAX_PATH
* sizeof (WCHAR
))
2135 buf
= (char *) alloca (full_len
+ 1);
2137 /* Create shortcut header */
2138 win_shortcut_hdr
*shortcut_header
= (win_shortcut_hdr
*) buf
;
2139 memset (shortcut_header
, 0, sizeof *shortcut_header
);
2140 shortcut_header
->size
= sizeof *shortcut_header
;
2141 shortcut_header
->magic
= GUID_shortcut
;
2142 shortcut_header
->flags
= (WSH_FLAG_DESC
| WSH_FLAG_RELPATH
);
2144 shortcut_header
->flags
|= WSH_FLAG_IDLIST
;
2145 shortcut_header
->run
= SW_NORMAL
;
2146 cp
= buf
+ sizeof (win_shortcut_hdr
);
2151 *(unsigned short *)cp
= pidl_len
;
2152 memcpy (cp
+= 2, pidl
, pidl_len
);
2154 CoTaskMemFree (pidl
);
2157 /* Create description */
2158 *(unsigned short *)cp
= desc_len
;
2159 cp
= stpcpy (cp
+= 2, desc
);
2161 /* Create relpath */
2162 *(unsigned short *)cp
= relpath_len
;
2163 cp
= stpcpy (cp
+= 2, relpath
);
2165 /* Append the POSIX path after the regular shortcut data for
2166 the long path support. */
2167 unsigned short *plen
= (unsigned short *) cp
;
2169 *(PWCHAR
) cp
= 0xfeff; /* BOM */
2171 *plen
= sys_mbstowcs ((PWCHAR
) cp
, NT_MAX_PATH
, oldpath
)
2177 /* Default technique creating a symlink. */
2179 cp
= stpcpy (buf
, SYMLINK_COOKIE
);
2180 *(PWCHAR
) cp
= 0xfeff; /* BOM */
2182 /* Note that the terminating nul is written. */
2183 cp
+= sys_mbstowcs ((PWCHAR
) cp
, NT_MAX_PATH
, oldpath
)
2187 OBJECT_ATTRIBUTES attr
;
2193 access
= DELETE
| FILE_GENERIC_WRITE
;
2194 if (isdevice
&& win32_newpath
.exists ())
2196 status
= NtOpenFile (&fh
, FILE_WRITE_ATTRIBUTES
,
2197 win32_newpath
.get_object_attr (attr
,
2199 &io
, 0, FILE_OPEN_FOR_BACKUP_INTENT
);
2200 if (!NT_SUCCESS (status
))
2202 __seterrno_from_nt_status (status
);
2205 status
= NtSetAttributesFile (fh
, FILE_ATTRIBUTE_NORMAL
);
2207 if (!NT_SUCCESS (status
))
2209 __seterrno_from_nt_status (status
);
2213 else if (!isdevice
&& win32_newpath
.has_acls ()
2214 && !win32_newpath
.isremote ())
2215 /* If the filesystem supports ACLs, we will overwrite the DACL after the
2216 call to NtCreateFile. This requires a handle with READ_CONTROL and
2217 WRITE_DAC access, otherwise get_file_sd and set_file_sd both have to
2218 open the file again.
2219 FIXME: On remote NTFS shares open sometimes fails because even the
2220 creator of the file doesn't have the right to change the DACL.
2221 I don't know what setting that is or how to recognize such a share,
2222 so for now we don't request WRITE_DAC on remote drives. */
2223 access
|= READ_CONTROL
| WRITE_DAC
;
2225 status
= NtCreateFile (&fh
, access
,
2226 win32_newpath
.get_object_attr (attr
, sec_none_nih
),
2227 &io
, NULL
, FILE_ATTRIBUTE_NORMAL
,
2228 FILE_SHARE_VALID_FLAGS
,
2229 isdevice
? FILE_OVERWRITE_IF
: FILE_CREATE
,
2230 FILE_SYNCHRONOUS_IO_NONALERT
2231 | FILE_NON_DIRECTORY_FILE
2232 | FILE_OPEN_FOR_BACKUP_INTENT
,
2234 if (!NT_SUCCESS (status
))
2236 __seterrno_from_nt_status (status
);
2239 if (io
.Information
== FILE_CREATED
&& win32_newpath
.has_acls ())
2240 set_created_file_access (fh
, win32_newpath
,
2241 S_IFLNK
| STD_RBITS
| STD_WBITS
);
2242 status
= NtWriteFile (fh
, NULL
, NULL
, NULL
, &io
, buf
, cp
- buf
,
2244 if (NT_SUCCESS (status
) && io
.Information
== (ULONG
) (cp
- buf
))
2246 status
= NtSetAttributesFile (fh
, wsym_type
== WSYM_lnk
2247 ? FILE_ATTRIBUTE_READONLY
2248 : FILE_ATTRIBUTE_SYSTEM
);
2249 if (!NT_SUCCESS (status
))
2250 debug_printf ("Setting attributes failed, status = %y", status
);
2255 __seterrno_from_nt_status (status
);
2256 FILE_DISPOSITION_INFORMATION fdi
= { TRUE
};
2257 status
= NtSetInformationFile (fh
, &io
, &fdi
, sizeof fdi
,
2258 FileDispositionInformation
);
2259 if (!NT_SUCCESS (status
))
2260 debug_printf ("Setting delete dispostion failed, status = %y",
2266 __except (EFAULT
) {}
2268 syscall_printf ("%d = symlink_worker(%s, %s, %d)",
2269 res
, oldpath
, win32_newpath
.get_posix (), isdevice
);
2274 cmp_shortcut_header (win_shortcut_hdr
*file_header
)
2276 /* A Cygwin or U/Win shortcut only contains a description and a relpath.
2277 Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
2278 always set to SW_NORMAL. */
2279 return file_header
->size
== sizeof (win_shortcut_hdr
)
2280 && !memcmp (&file_header
->magic
, &GUID_shortcut
, sizeof GUID_shortcut
)
2281 && (file_header
->flags
& ~WSH_FLAG_IDLIST
)
2282 == (WSH_FLAG_DESC
| WSH_FLAG_RELPATH
)
2283 && file_header
->run
== SW_NORMAL
;
2287 symlink_info::check_shortcut (HANDLE h
)
2290 win_shortcut_hdr
*file_header
;
2296 FILE_STANDARD_INFORMATION fsi
;
2297 LARGE_INTEGER off
= { QuadPart
:0LL };
2299 status
= NtQueryInformationFile (h
, &io
, &fsi
, sizeof fsi
,
2300 FileStandardInformation
);
2301 if (!NT_SUCCESS (status
))
2306 if (fsi
.EndOfFile
.QuadPart
<= (LONGLONG
) sizeof (win_shortcut_hdr
)
2307 || fsi
.EndOfFile
.QuadPart
> 4 * 65536)
2309 if (fsi
.EndOfFile
.LowPart
< NT_MAX_PATH
* sizeof (WCHAR
))
2310 buf
= (char *) tp
.w_get ();
2312 buf
= (char *) alloca (fsi
.EndOfFile
.LowPart
+ 1);
2313 status
= NtReadFile (h
, NULL
, NULL
, NULL
, &io
, buf
, fsi
.EndOfFile
.LowPart
,
2315 if (!NT_SUCCESS (status
))
2317 if (status
!= STATUS_END_OF_FILE
)
2321 file_header
= (win_shortcut_hdr
*) buf
;
2322 if (io
.Information
!= fsi
.EndOfFile
.LowPart
2323 || !cmp_shortcut_header (file_header
))
2325 cp
= buf
+ sizeof (win_shortcut_hdr
);
2326 if (file_header
->flags
& WSH_FLAG_IDLIST
) /* Skip ITEMIDLIST */
2327 cp
+= *(unsigned short *) cp
+ 2;
2328 if (!(len
= *(unsigned short *) cp
))
2331 /* Check if this is a device file - these start with the sequence :\\ */
2332 if (strncmp (cp
, ":\\", 2) == 0)
2333 res
= strlen (strcpy (contents
, cp
)); /* Don't mess with device files */
2336 /* Has appended full path? If so, use it instead of description. */
2337 unsigned short relpath_len
= *(unsigned short *) (cp
+ len
);
2338 if (cp
+ len
+ 2 + relpath_len
< buf
+ fsi
.EndOfFile
.LowPart
)
2340 cp
+= len
+ 2 + relpath_len
;
2341 len
= *(unsigned short *) cp
;
2344 if (*(PWCHAR
) cp
== 0xfeff) /* BOM */
2346 char *tmpbuf
= tp
.c_get ();
2347 if (sys_wcstombs (tmpbuf
, NT_MAX_PATH
, (PWCHAR
) (cp
+ 2))
2350 res
= posixify (tmpbuf
);
2352 else if (len
> SYMLINK_MAX
)
2357 res
= posixify (cp
);
2360 if (res
) /* It's a symlink. */
2361 path_flags
|= PATH_SYMLINK
| PATH_LNK
;
2366 symlink_info::check_sysfile (HANDLE h
)
2369 char cookie_buf
[sizeof (SYMLINK_COOKIE
) - 1];
2370 char *srcbuf
= tp
.c_get ();
2374 bool interix_symlink
= false;
2375 LARGE_INTEGER off
= { QuadPart
:0LL };
2377 status
= NtReadFile (h
, NULL
, NULL
, NULL
, &io
, cookie_buf
,
2378 sizeof (cookie_buf
), &off
, NULL
);
2379 if (!NT_SUCCESS (status
))
2381 debug_printf ("ReadFile1 failed %y", status
);
2382 if (status
!= STATUS_END_OF_FILE
)
2386 off
.QuadPart
= io
.Information
;
2387 if (io
.Information
== sizeof (cookie_buf
)
2388 && memcmp (cookie_buf
, SYMLINK_COOKIE
, sizeof (cookie_buf
)) == 0)
2390 /* It's a symlink. */
2391 path_flags
|= PATH_SYMLINK
;
2393 else if (io
.Information
== sizeof (cookie_buf
)
2394 && memcmp (cookie_buf
, SOCKET_COOKIE
, sizeof (cookie_buf
)) == 0)
2395 path_flags
|= PATH_SOCKET
;
2396 else if (io
.Information
>= sizeof (INTERIX_SYMLINK_COOKIE
)
2397 && memcmp (cookie_buf
, INTERIX_SYMLINK_COOKIE
,
2398 sizeof (INTERIX_SYMLINK_COOKIE
) - 1) == 0)
2400 /* It's an Interix symlink. */
2401 path_flags
|= PATH_SYMLINK
;
2402 interix_symlink
= true;
2403 /* Interix symlink cookies are shorter than Cygwin symlink cookies, so
2404 in case of an Interix symlink cooky we have read too far into the
2405 file. Set file pointer back to the position right after the cookie. */
2406 off
.QuadPart
= sizeof (INTERIX_SYMLINK_COOKIE
) - 1;
2408 if (path_flags
& PATH_SYMLINK
)
2410 status
= NtReadFile (h
, NULL
, NULL
, NULL
, &io
, srcbuf
,
2411 NT_MAX_PATH
, &off
, NULL
);
2412 if (!NT_SUCCESS (status
))
2414 debug_printf ("ReadFile2 failed");
2415 if (status
!= STATUS_END_OF_FILE
)
2418 else if (*(PWCHAR
) srcbuf
== 0xfeff /* BOM */
2421 /* Add trailing 0 to Interix symlink target. Skip BOM in Cygwin
2423 if (interix_symlink
)
2424 ((PWCHAR
) srcbuf
)[io
.Information
/ sizeof (WCHAR
)] = L
'\0';
2427 char *tmpbuf
= tp
.c_get ();
2428 if (sys_wcstombs (tmpbuf
, NT_MAX_PATH
, (PWCHAR
) srcbuf
)
2430 debug_printf ("symlink string too long");
2432 res
= posixify (tmpbuf
);
2434 else if (io
.Information
> SYMLINK_MAX
+ 1)
2435 debug_printf ("symlink string too long");
2437 res
= posixify (srcbuf
);
2443 check_reparse_point_string (PUNICODE_STRING subst
)
2445 /* Native mount points, or native non-relative symbolic links,
2446 can be treated as posix symlinks only if the SubstituteName
2447 can be converted from a native NT object namespace name to
2448 a win32 name. We only know how to convert names with two
2452 Other reparse points will be treated as files or
2453 directories, not as posix symlinks.
2455 if (RtlEqualUnicodePathPrefix (subst
, &ro_u_natp
, FALSE
))
2457 if (subst
->Length
>= 6 * sizeof(WCHAR
) && subst
->Buffer
[5] == L
':' &&
2458 (subst
->Length
== 6 * sizeof(WCHAR
) || subst
->Buffer
[6] == L
'\\'))
2460 else if (subst
->Length
>= 8 * sizeof(WCHAR
) &&
2461 wcsncmp (subst
->Buffer
+ 4, L
"UNC\\", 4) == 0)
2473 check_reparse_point_target (HANDLE h
, bool remote
, PREPARSE_DATA_BUFFER rp
,
2474 PUNICODE_STRING psymbuf
)
2479 /* On remote drives or under heavy load, NtFsControlFile can return with
2480 STATUS_PENDING. If so, instead of creating an event object, just set
2481 io.Status to an invalid value and perform a minimal wait until io.Status
2483 memset (&io
, 0xff, sizeof io
);
2484 status
= NtFsControlFile (h
, NULL
, NULL
, NULL
, &io
,
2485 FSCTL_GET_REPARSE_POINT
, NULL
, 0, (LPVOID
) rp
,
2486 MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
2487 if (status
== STATUS_PENDING
)
2489 while (io
.Status
== (NTSTATUS
) 0xffffffff)
2493 if (!NT_SUCCESS (status
))
2495 debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %y",
2497 /* When accessing the root dir of some remote drives (observed with
2498 OS X shares), the FILE_ATTRIBUTE_REPARSE_POINT flag is set, but
2499 the followup call to NtFsControlFile(FSCTL_GET_REPARSE_POINT)
2500 returns with STATUS_NOT_A_REPARSE_POINT. That's quite buggy, but
2501 we cope here with this scenario by not setting an error code. */
2502 if (status
== STATUS_NOT_A_REPARSE_POINT
)
2506 if (rp
->ReparseTag
== IO_REPARSE_TAG_SYMLINK
)
2508 /* Windows evaluates native symlink literally. If a remote symlink points
2509 to, say, C:\foo, it will be handled as if the target is the local file
2510 C:\foo. That comes in handy since that's how symlinks are treated under
2512 RtlInitCountedUnicodeString (psymbuf
,
2513 (PWCHAR
)((PBYTE
) rp
->SymbolicLinkReparseBuffer
.PathBuffer
2514 + rp
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
),
2515 rp
->SymbolicLinkReparseBuffer
.SubstituteNameLength
);
2516 if ((rp
->SymbolicLinkReparseBuffer
.Flags
& SYMLINK_FLAG_RELATIVE
) ||
2517 check_reparse_point_string (psymbuf
))
2518 return PATH_SYMLINK
| PATH_REP
;
2520 else if (!remote
&& rp
->ReparseTag
== IO_REPARSE_TAG_MOUNT_POINT
)
2522 /* Don't handle junctions on remote filesystems as symlinks. This type
2523 of reparse point is handled transparently by the OS so that the
2524 target of the junction is the remote directory it is supposed to
2525 point to. If we handle it as symlink, it will be mistreated as
2526 pointing to a dir on the local system. */
2527 RtlInitCountedUnicodeString (psymbuf
,
2528 (PWCHAR
)((PBYTE
) rp
->MountPointReparseBuffer
.PathBuffer
2529 + rp
->MountPointReparseBuffer
.SubstituteNameOffset
),
2530 rp
->MountPointReparseBuffer
.SubstituteNameLength
);
2531 if (RtlEqualUnicodePathPrefix (psymbuf
, &ro_u_volume
, TRUE
))
2533 /* Volume mount point. Not treated as symlink. The return
2534 value -EPERM is a hint for the caller to treat this as a
2535 volume mount point. */
2538 if (check_reparse_point_string (psymbuf
))
2539 return PATH_SYMLINK
| PATH_REP
;
2541 else if (rp
->ReparseTag
== IO_REPARSE_TAG_LX_SYMLINK
)
2543 /* WSL symlink. Problem: We have to convert the path to UTF-16 for
2544 the caller. Reparse points are 16K max. The buffer given to rp
2545 is 32K. So there's enough trailing space in the buffer to convert
2546 to UTF-16 and let psymbuf point to it. */
2547 PREPARSE_LX_SYMLINK_BUFFER rpl
= (PREPARSE_LX_SYMLINK_BUFFER
) rp
;
2548 char *path_buf
= rpl
->LxSymlinkReparseBuffer
.PathBuffer
;
2549 DWORD path_len
= rpl
->ReparseDataLength
- sizeof (DWORD
);
2550 bool full_path
= false;
2551 const size_t drv_prefix_len
= strlen ("/mnt");
2556 /* 0-terminate path_buf for easier testing. */
2557 path_buf
[path_len
] = '\0';
2558 if (path_prefix_p ("/mnt", path_buf
, drv_prefix_len
, false))
2560 size_t len
= strlen (path_buf
);
2562 if (len
<= drv_prefix_len
+ 1)
2564 /* /mnt or /mnt/. Replace with cygdrive prefix. */
2565 stpcpy (path_buf
, mount_table
->cygdrive
);
2566 path_len
= mount_table
->cygdrive_len
;
2567 if (len
== drv_prefix_len
)
2569 path_buf
[mount_table
->cygdrive_len
- 1] = '\0';
2572 rp
->ReparseDataLength
= path_len
+ sizeof (DWORD
);
2574 else if (islower (path_buf
[drv_prefix_len
+ 1])
2575 && (path_len
== drv_prefix_len
+ 2
2576 || path_buf
[drv_prefix_len
+ 2] == '/'))
2578 /* Skip forward to the slash leading the drive letter.
2579 That leaves room for adding the colon. */
2580 path_buf
+= drv_prefix_len
;
2581 path_len
-= drv_prefix_len
;
2585 /* Compute buffer for path converted to UTF-16. */
2586 utf16_ptr
= (PBYTE
) rpl
+ sizeof (REPARSE_LX_SYMLINK_BUFFER
)
2587 + rp
->ReparseDataLength
;
2588 /* Skip \0-termination added above. */
2590 /* Make sure pointer is aligned */
2591 while ((intptr_t) utf16_ptr
% sizeof (WCHAR
))
2593 utf16_buf
= (PWCHAR
) utf16_ptr
;
2594 utf16_bufsize
= NT_MAX_PATH
- (utf16_buf
- (PWCHAR
) rpl
);
2595 /* Now convert path to UTF-16. */
2596 utf16_bufsize
= MultiByteToWideChar (CP_UTF8
, 0, path_buf
, path_len
,
2597 utf16_buf
, utf16_bufsize
);
2602 utf16_buf
[0] = utf16_buf
[1]; /* Move drive letter to front */
2603 utf16_buf
[1] = L
':'; /* Add colon */
2605 RtlInitCountedUnicodeString (psymbuf
, utf16_buf
,
2606 utf16_bufsize
* sizeof (WCHAR
));
2607 return PATH_SYMLINK
| PATH_REP
;
2611 #ifdef __WITH_AF_UNIX
2612 else if (rp
->ReparseTag
== IO_REPARSE_TAG_CYGUNIX
)
2614 PREPARSE_GUID_DATA_BUFFER rgp
= (PREPARSE_GUID_DATA_BUFFER
) rp
;
2616 if (memcmp (CYGWIN_SOCKET_GUID
, &rgp
->ReparseGuid
, sizeof (GUID
)) == 0)
2617 return PATH_SOCKET
| PATH_REP
;
2619 #endif /* __WITH_AF_UNIX */
2624 symlink_info::check_reparse_point (HANDLE h
, bool remote
)
2627 PREPARSE_DATA_BUFFER rp
= (PREPARSE_DATA_BUFFER
) tp
.c_get ();
2628 UNICODE_STRING symbuf
;
2629 char srcbuf
[SYMLINK_MAX
+ 7];
2631 int ret
= check_reparse_point_target (h
, remote
, rp
, &symbuf
);
2639 /* Maybe it's a reparse point, but it's certainly not one we recognize.
2640 Drop REPARSE attribute so we don't try to use the flag accidentally.
2641 It's just some arbitrary file or directory for us. */
2642 fileattr
&= ~FILE_ATTRIBUTE_REPARSE_POINT
;
2645 /* ret is > 0, so it's a known reparse point, path in symbuf. */
2647 if (ret
& PATH_SYMLINK
)
2648 sys_wcstombs (srcbuf
, SYMLINK_MAX
+ 7, symbuf
.Buffer
,
2649 symbuf
.Length
/ sizeof (WCHAR
));
2650 /* A symlink is never a directory. */
2651 fileattr
&= ~FILE_ATTRIBUTE_DIRECTORY
;
2652 return posixify (srcbuf
);
2656 symlink_info::check_nfs_symlink (HANDLE h
)
2662 FILE_GET_EA_INFORMATION fgei
;
2663 char buf
[sizeof (NFS_SYML_TARGET
)];
2665 PFILE_FULL_EA_INFORMATION pffei
;
2668 /* To find out if the file is a symlink and to get the symlink target,
2669 try to fetch the NfsSymlinkTargetName EA. */
2670 fgei_buf
.fgei
.NextEntryOffset
= 0;
2671 fgei_buf
.fgei
.EaNameLength
= sizeof (NFS_SYML_TARGET
) - 1;
2672 stpcpy (fgei_buf
.fgei
.EaName
, NFS_SYML_TARGET
);
2673 pffei
= (PFILE_FULL_EA_INFORMATION
) tp
.w_get ();
2674 status
= NtQueryEaFile (h
, &io
, pffei
, NT_MAX_PATH
* sizeof (WCHAR
), TRUE
,
2675 &fgei_buf
.fgei
, sizeof fgei_buf
, NULL
, TRUE
);
2676 if (NT_SUCCESS (status
) && pffei
->EaValueLength
> 0)
2678 PWCHAR spath
= (PWCHAR
)
2679 (pffei
->EaName
+ pffei
->EaNameLength
+ 1);
2680 res
= sys_wcstombs (contents
, SYMLINK_MAX
+ 1,
2681 spath
, pffei
->EaValueLength
);
2682 path_flags
|= PATH_SYMLINK
;
2688 symlink_info::posixify (char *srcbuf
)
2690 /* The definition for a path in a native symlink is a bit weird. The Flags
2691 value seem to contain 0 for absolute paths (stored as NT native path)
2692 and 1 for relative paths. Relative paths are paths not starting with a
2693 drive letter. These are not converted to NT native, but stored as
2694 given. A path starting with a single backslash is relative to the
2695 current drive thus a "relative" value (Flags == 1).
2696 Funny enough it's possible to store paths with slashes instead of
2697 backslashes, but they are evaluated incorrectly by subsequent Windows
2698 calls like CreateFile (ERROR_INVALID_NAME). So, what we do here is to
2699 take paths starting with slashes at face value, evaluating them as
2700 Cygwin specific POSIX paths.
2701 A path starting with two slashes(!) or backslashes is converted into an
2702 NT UNC path. Unfortunately, in contrast to POSIX rules, paths starting
2703 with three or more (back)slashes are also converted into UNC paths,
2704 just incorrectly sticking to one redundant leading backslash. We go
2705 along with this behaviour to avoid scenarios in which native tools access
2706 other files than Cygwin.
2707 The above rules are used exactly the same way on Cygwin specific symlinks
2708 (sysfiles and shortcuts) to eliminate non-POSIX paths in the output. */
2710 /* Eliminate native NT prefixes. */
2711 if (srcbuf
[0] == '\\' && !strncmp (srcbuf
+ 1, "??\\", 3))
2714 if (srcbuf
[1] != ':') /* native UNC path */
2715 *(srcbuf
+= 2) = '\\';
2717 if (isdrive (srcbuf
))
2718 mount_table
->conv_to_posix_path (srcbuf
, contents
, 0);
2719 else if (srcbuf
[0] == '\\')
2721 if (srcbuf
[1] == '\\') /* UNC path */
2722 slashify (srcbuf
, contents
, 0);
2723 else /* Paths starting with \ are current drive relative. */
2725 char cvtbuf
[SYMLINK_MAX
+ 1];
2727 stpcpy (cvtbuf
+ cygheap
->cwd
.get_drive (cvtbuf
), srcbuf
);
2728 mount_table
->conv_to_posix_path (cvtbuf
, contents
, 0);
2731 else /* Everything else is taken as is. */
2732 slashify (srcbuf
, contents
, 0);
2733 return strlen (contents
);
2742 SCAN_JUSTCHECKTHIS
, /* Never try to append a suffix. */
2750 const suffix_info
*suffixes
, *suffixes_start
;
2756 char *has (const char *, const suffix_info
*);
2758 int lnk_match () {return nextstate
>= SCAN_APPENDLNK
;}
2759 size_t name_len () {return namelen
;}
2763 suffix_scan::has (const char *in_path
, const suffix_info
*in_suffixes
)
2765 nextstate
= SCAN_BEG
;
2766 suffixes
= suffixes_start
= in_suffixes
;
2768 const char *fname
= strrchr (in_path
, '\\');
2769 fname
= fname
? fname
+ 1 : in_path
;
2770 char *ext_here
= strrchr (fname
, '.');
2772 eopath
= strchr (path
, '\0');
2779 /* Check if the extension matches a known extension */
2780 for (const suffix_info
*ex
= in_suffixes
; ex
->name
!= NULL
; ex
++)
2781 if (ascii_strcasematch (ext_here
, ex
->name
))
2783 nextstate
= SCAN_JUSTCHECK
;
2784 suffixes
= NULL
; /* Has an extension so don't scan for one. */
2789 /* Didn't match. Use last resort -- .lnk. */
2790 if (ascii_strcasematch (ext_here
, ".lnk"))
2792 nextstate
= SCAN_HASLNK
;
2800 namelen
= eopath
- fname
;
2801 /* Avoid attaching suffixes if the resulting filename would be invalid.
2802 For performance reasons we don't check the length of a suffix, since
2803 we know that all suffixes are 4 chars in length.
2805 FIXME: This is not really correct. A fully functional test should
2806 work on wide character paths. This would probably also speed
2807 up symlink_info::check. */
2808 if (namelen
> NAME_MAX
- 4)
2810 nextstate
= SCAN_JUSTCHECKTHIS
;
2817 suffix_scan::next ()
2825 suffixes
= suffixes_start
;
2828 nextstate
= SCAN_LNK
;
2831 nextstate
= SCAN_EXTRALNK
;
2832 /* fall through to suffix checking below */
2835 nextstate
= SCAN_APPENDLNK
; /* Skip SCAN_BEG */
2838 nextstate
= SCAN_DONE
;
2841 case SCAN_JUSTCHECK
:
2842 nextstate
= SCAN_LNK
;
2844 case SCAN_JUSTCHECKTHIS
:
2845 nextstate
= SCAN_DONE
;
2848 case SCAN_APPENDLNK
:
2849 nextstate
= SCAN_DONE
;
2850 if (namelen
+ (*eopath
? 8 : 4) > NAME_MAX
)
2855 strcat (eopath
, ".lnk");
2862 while (suffixes
&& suffixes
->name
)
2863 if (nextstate
== SCAN_EXTRALNK
2864 && (!suffixes
->addon
|| namelen
> NAME_MAX
- 8))
2868 strcpy (eopath
, suffixes
->name
);
2869 if (nextstate
== SCAN_EXTRALNK
)
2870 strcat (eopath
, ".lnk");
2879 symlink_info::set_error (int in_errno
)
2882 if (!(pc_flags
& PC_NO_ACCESS_CHECK
)
2883 || in_errno
== ENAMETOOLONG
|| in_errno
== EIO
)
2888 else if (in_errno
== ENOENT
)
2892 fileattr
= FILE_ATTRIBUTE_NORMAL
;
2899 symlink_info::parse_device (const char *contents
)
2906 mymajor
= strtol (contents
+= 2, &endptr
, 16);
2907 if (endptr
== contents
)
2908 return isdevice
= false;
2911 myminor
= strtol (++contents
, &endptr
, 16);
2912 if (endptr
== contents
)
2913 return isdevice
= false;
2916 mymode
= strtol (++contents
, &endptr
, 16);
2917 if (endptr
== contents
)
2918 return isdevice
= false;
2920 if ((mymode
& S_IFMT
) == S_IFIFO
)
2922 mymajor
= _major (FH_FIFO
);
2923 myminor
= _minor (FH_FIFO
);
2929 return isdevice
= true;
2932 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2934 If PATH is a symlink, put the value of the symlink--the file to
2935 which it points--into BUF. The value stored in BUF is not
2936 necessarily null terminated. BUFLEN is the length of BUF; only up
2937 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2938 which case nothing will be stored.
2940 Set *SYML if PATH is a symlink.
2942 Set *EXEC if PATH appears to be executable. This is an efficiency
2943 hack because we sometimes have to open the file anyhow. *EXEC will
2944 not be set for every executable file.
2946 Return -1 on error, 0 if PATH is not a symlink, or the length
2947 stored into BUF if PATH is a symlink. */
2950 symlink_info::check (char *path
, const suffix_info
*suffixes
, fs_info
&fs
,
2951 path_conv_handle
&conv_hdl
)
2956 UNICODE_STRING upath
;
2957 OBJECT_ATTRIBUTES attr
;
2961 const ULONG ci_flag
= cygwin_shared
->obcaseinsensitive
2962 || (mount_flags
& MOUNT_NOPOSIX
)
2963 ? OBJ_CASE_INSENSITIVE
: 0;
2964 /* TODO: Temporarily do all char->UNICODE conversion here. This should
2965 already be slightly faster than using Ascii functions. */
2968 InitializeObjectAttributes (&attr
, &upath
, ci_flag
, NULL
, NULL
);
2970 /* This label is used in case we encounter a FS which only handles
2971 DOS paths. See below. */
2972 bool restarted
= false;
2983 // mount_flags is an incoming value set in path_conv */
2986 PVOID eabuf
= &nfs_aol_ffei
;
2987 ULONG easize
= sizeof nfs_aol_ffei
;
2989 ext_here
= suffix
.has (path
, suffixes
);
2990 extn
= ext_here
- path
;
2991 bool had_ext
= !!*ext_here
;
2993 /* If the filename is too long, don't even try. */
2994 if (suffix
.name_len () > NAME_MAX
)
2996 set_error (ENAMETOOLONG
);
2997 goto file_not_symlink
;
3000 while (suffix
.next ())
3003 get_nt_native_path (suffix
.path
, upath
, mount_flags
& MOUNT_DOS
);
3009 /* The EA given to NtCreateFile allows to get a handle to a symlink on
3010 an NFS share, rather than getting a handle to the target of the
3011 symlink (which would spoil the task of this method quite a bit).
3012 Fortunately it's ignored on most other file systems so we don't have
3013 to special case NFS too much. */
3014 status
= NtCreateFile (&h
,
3015 READ_CONTROL
| FILE_READ_ATTRIBUTES
| FILE_READ_EA
,
3016 &attr
, &io
, NULL
, 0, FILE_SHARE_VALID_FLAGS
,
3018 FILE_OPEN_REPARSE_POINT
3019 | FILE_OPEN_FOR_BACKUP_INTENT
,
3021 debug_printf ("%y = NtCreateFile (%S)", status
, &upath
);
3022 /* No right to access EAs or EAs not supported? */
3023 if (!NT_SUCCESS (status
)
3024 && (status
== STATUS_ACCESS_DENIED
3025 || status
== STATUS_EAS_NOT_SUPPORTED
3026 || status
== STATUS_NOT_SUPPORTED
3027 || status
== STATUS_INVALID_NETWORK_RESPONSE
3028 /* Or a bug in Samba 3.2.x (x <= 7) when accessing a share's
3029 root dir which has EAs enabled? */
3030 || status
== STATUS_INVALID_PARAMETER
))
3032 /* If EAs are not supported, there's no sense to check them again
3033 with suffixes attached. So we set eabuf/easize to 0 here once. */
3034 if (status
== STATUS_EAS_NOT_SUPPORTED
3035 || status
== STATUS_NOT_SUPPORTED
)
3040 status
= NtOpenFile (&h
, READ_CONTROL
| FILE_READ_ATTRIBUTES
,
3041 &attr
, &io
, FILE_SHARE_VALID_FLAGS
,
3042 FILE_OPEN_REPARSE_POINT
3043 | FILE_OPEN_FOR_BACKUP_INTENT
);
3044 debug_printf ("%y = NtOpenFile (no-EAs %S)", status
, &upath
);
3046 if (status
== STATUS_OBJECT_NAME_NOT_FOUND
)
3048 /* There are filesystems out in the wild (Netapp, NWFS, and others)
3049 which are uncapable of generating pathnames outside the Win32
3050 rules. That means, filenames on these FSes must not have a
3051 leading space or trailing dots and spaces. This code snippet
3052 manages them. I really hope it's streamlined enough not to
3053 slow down normal operation. This extra check only kicks in if
3054 we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't
3055 already attach a suffix. */
3056 if (!restarted
&& !*ext_here
&& ext_here
[-1] != '\\'
3057 && !(mount_flags
& MOUNT_DOS
))
3059 /* Check for trailing dot or space or leading space in
3061 char *p
= ext_here
- 1;
3062 if (*p
!= '.' && *p
!= ' ')
3064 while (*--p
!= '\\')
3071 /* If so, check if file resides on one of the known broken
3072 FSes only supporting filenames following DOS rules. */
3073 fs
.update (&upath
, NULL
);
3074 if (fs
.has_dos_filenames_only ())
3076 /* If so, try again. Since we now know the FS, the
3077 filenames will be tweaked to follow DOS rules via the
3078 third parameter in the call to get_nt_native_path. */
3079 mount_flags
|= MOUNT_DOS
;
3086 else if (status
== STATUS_NETWORK_OPEN_RESTRICTION
3087 || status
== STATUS_SYMLINK_CLASS_DISABLED
)
3089 /* These status codes are returned if you try to open a native
3090 symlink and the usage of this kind of symlink is forbidden
3091 (see fsutil). Since we can't open them at all, not even for
3092 stat purposes, we have to return a POSIX error code which is
3093 at least a bit helpful.
3095 Additionally Windows 8 introduces a bug in NFS: If you have
3096 a symlink to a directory, with symlinks underneath, resolving
3097 the second level of symlinks fails if remote->remote symlinks
3098 are disabled in fsutil. Unfortunately that's the default. */
3103 if (NT_SUCCESS (status
)
3104 /* Check file system while we're having the file open anyway.
3105 This speeds up path_conv noticably (~10%). */
3106 && (fs
.inited () || fs
.update (&upath
, h
)))
3108 status
= conv_hdl
.get_finfo (h
, fs
.is_nfs ());
3109 if (NT_SUCCESS (status
))
3110 fileattr
= conv_hdl
.get_dosattr (fs
.is_nfs ());
3112 if (!NT_SUCCESS (status
))
3114 debug_printf ("%y = NtQueryInformationFile (%S)", status
, &upath
);
3115 fileattr
= INVALID_FILE_ATTRIBUTES
;
3117 /* One of the inner path components is invalid, or the path contains
3118 invalid characters. Bail out with ENOENT.
3120 STATUS_IO_REPARSE_TAG_NOT_HANDLED is returned when trying to
3121 traversing a WSL symlink. For all practical purposes it's
3122 equivalent to traversing SYSTEM- or LNK-type symlink returning
3123 STATUS_OBJECT_PATH_NOT_FOUND.
3125 Note that additional STATUS_OBJECT_PATH_INVALID and
3126 STATUS_OBJECT_PATH_SYNTAX_BAD status codes exist. The first one
3127 is seemingly not generated by NtQueryInformationFile, the latter
3128 is only generated if the path is no absolute path within the
3129 NT name space, which should not happen and would point to an
3130 error in get_nt_native_path. Both status codes are deliberately
3131 not tested here unless proved necessary. */
3132 if (status
== STATUS_OBJECT_PATH_NOT_FOUND
3133 || status
== STATUS_IO_REPARSE_TAG_NOT_HANDLED
3134 || status
== STATUS_OBJECT_NAME_INVALID
3135 || status
== STATUS_BAD_NETWORK_PATH
3136 || status
== STATUS_BAD_NETWORK_NAME
3137 || status
== STATUS_NO_MEDIA_IN_DEVICE
)
3140 if (ext_tacked_on
&& !had_ext
)
3143 ext_tacked_on
= false;
3147 goto file_not_symlink
;
3149 if (status
!= STATUS_OBJECT_NAME_NOT_FOUND
3150 && status
!= STATUS_NO_SUCH_FILE
) /* ENOENT on NFS or 9x share */
3152 /* The file exists, but the user can't access it for one reason
3153 or the other. To get the file attributes we try to access the
3154 information by opening the parent directory and getting the
3155 file attributes using a matching NtQueryDirectoryFile call. */
3156 UNICODE_STRING dirname
, basename
;
3157 OBJECT_ATTRIBUTES dattr
;
3160 FILE_ID_BOTH_DIR_INFORMATION fdi
;
3161 WCHAR dummy_buf
[NAME_MAX
+ 1];
3164 RtlSplitUnicodePath (&upath
, &dirname
, &basename
);
3165 InitializeObjectAttributes (&dattr
, &dirname
, ci_flag
,
3167 status
= NtOpenFile (&dir
, SYNCHRONIZE
| FILE_LIST_DIRECTORY
,
3168 &dattr
, &io
, FILE_SHARE_VALID_FLAGS
,
3169 FILE_SYNCHRONOUS_IO_NONALERT
3170 | FILE_OPEN_FOR_BACKUP_INTENT
3171 | FILE_DIRECTORY_FILE
);
3172 if (!NT_SUCCESS (status
))
3174 debug_printf ("%y = NtOpenFile(%S)", status
, &dirname
);
3175 /* There's a special case if the file is itself the root
3176 of a drive which is not accessible by the current user.
3177 This case is only recognized by the length of the
3178 basename part. If it's 0, the incoming file is the
3179 root of a drive. So we at least know it's a directory. */
3180 if (basename
.Length
)
3181 fileattr
= FILE_ATTRIBUTE_DIRECTORY
;
3185 set_error (geterrno_from_nt_status (status
));
3190 status
= NtQueryDirectoryFile (dir
, NULL
, NULL
, NULL
, &io
,
3191 &fdi_buf
, sizeof fdi_buf
,
3192 FileIdBothDirectoryInformation
,
3193 TRUE
, &basename
, TRUE
);
3194 /* Take the opportunity to check file system while we're
3195 having the handle to the parent dir. */
3196 fs
.update (&upath
, dir
);
3198 if (!NT_SUCCESS (status
))
3200 debug_printf ("%y = NtQueryDirectoryFile(%S)",
3202 if (status
== STATUS_NO_SUCH_FILE
)
3204 /* This can happen when trying to access files
3205 which match DOS device names on SMB shares.
3206 NtOpenFile failed with STATUS_ACCESS_DENIED,
3207 but the NtQueryDirectoryFile tells us the
3208 file doesn't exist. We're suspicious in this
3209 case and retry with the next suffix instead of
3218 PFILE_ALL_INFORMATION pfai
= conv_hdl
.fai ();
3220 fileattr
= fdi_buf
.fdi
.FileAttributes
;
3221 memcpy (&pfai
->BasicInformation
.CreationTime
,
3222 &fdi_buf
.fdi
.CreationTime
,
3223 4 * sizeof (LARGE_INTEGER
));
3224 pfai
->BasicInformation
.FileAttributes
= fileattr
;
3225 pfai
->StandardInformation
.AllocationSize
.QuadPart
3226 = fdi_buf
.fdi
.AllocationSize
.QuadPart
;
3227 pfai
->StandardInformation
.EndOfFile
.QuadPart
3228 = fdi_buf
.fdi
.EndOfFile
.QuadPart
;
3229 pfai
->StandardInformation
.NumberOfLinks
= 1;
3230 pfai
->InternalInformation
.IndexNumber
.QuadPart
3231 = fdi_buf
.fdi
.FileId
.QuadPart
;
3234 ext_tacked_on
= !!*ext_here
;
3235 goto file_not_symlink
;
3241 ext_tacked_on
= !!*ext_here
;
3242 /* Don't allow to returns directories with appended suffix. If we found
3243 a directory with a suffix which has been appended here, then this
3244 directory doesn't match the request. So, just do as usual if file
3245 hasn't been found. */
3246 if (ext_tacked_on
&& !had_ext
&& (fileattr
& FILE_ATTRIBUTE_DIRECTORY
))
3254 /* Reparse points are potentially symlinks. This check must be
3255 performed before checking the SYSTEM attribute for sysfile
3256 symlinks, since reparse points can have this flag set, too. */
3257 if ((fileattr
& FILE_ATTRIBUTE_REPARSE_POINT
))
3259 res
= check_reparse_point (h
, fs
.is_remote_drive ());
3262 /* A symlink is never a directory. */
3263 conv_hdl
.fai ()->BasicInformation
.FileAttributes
3264 &= ~FILE_ATTRIBUTE_DIRECTORY
;
3269 /* Volume moint point or unrecognized reparse point type.
3270 Make sure the open handle is not used in later stat calls.
3271 The handle has been opened with the FILE_OPEN_REPARSE_POINT
3272 flag, so it's a handle to the reparse point, not a handle
3273 to the volumes root dir. */
3274 pc_flags
&= ~PC_KEEP_HANDLE
;
3275 /* Volume mount point: The filesystem information for the top
3276 level directory should be for the volume top level directory,
3277 rather than for the reparse point itself. So we fetch the
3278 filesystem information again, but with a NULL handle.
3279 This does what we want because fs_info::update opens the
3280 handle without FILE_OPEN_REPARSE_POINT. */
3282 fs
.update (&upath
, NULL
);
3286 /* Windows shortcuts are potentially treated as symlinks. Valid Cygwin
3287 & U/WIN shortcuts are R/O, but definitely not directories. */
3288 else if ((fileattr
& (FILE_ATTRIBUTE_READONLY
| FILE_ATTRIBUTE_DIRECTORY
))
3289 == FILE_ATTRIBUTE_READONLY
&& suffix
.lnk_match ())
3293 status
= NtOpenFile (&sym_h
, SYNCHRONIZE
| GENERIC_READ
, &attr
, &io
,
3294 FILE_SHARE_VALID_FLAGS
,
3295 FILE_OPEN_FOR_BACKUP_INTENT
3296 | FILE_SYNCHRONOUS_IO_NONALERT
);
3297 if (!NT_SUCCESS (status
))
3301 res
= check_shortcut (sym_h
);
3306 /* If searching for `foo' and then finding a `foo.lnk' which
3307 is no shortcut, return the same as if file not found. */
3310 fileattr
= INVALID_FILE_ATTRIBUTES
;
3315 else if (contents
[0] != ':' || contents
[1] != '\\'
3316 || !parse_device (contents
))
3320 /* If searching for `foo' and then finding a `foo.lnk' which is
3321 no shortcut, return the same as if file not found. */
3322 else if (suffix
.lnk_match () && ext_tacked_on
)
3324 fileattr
= INVALID_FILE_ATTRIBUTES
;
3329 /* This is the old Cygwin method creating symlinks. A symlink will
3330 have the `system' file attribute. Only files can be symlinks
3331 (which can be symlinks to directories). */
3332 else if ((fileattr
& (FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_DIRECTORY
))
3333 == FILE_ATTRIBUTE_SYSTEM
)
3337 status
= NtOpenFile (&sym_h
, SYNCHRONIZE
| GENERIC_READ
, &attr
, &io
,
3338 FILE_SHARE_VALID_FLAGS
,
3339 FILE_OPEN_FOR_BACKUP_INTENT
3340 | FILE_SYNCHRONOUS_IO_NONALERT
);
3342 if (!NT_SUCCESS (status
))
3346 res
= check_sysfile (sym_h
);
3353 /* If the file is on an NFS share and could be opened with extended
3354 attributes, check if it's a symlink. Only files can be symlinks
3355 (which can be symlinks to directories). */
3356 else if (fs
.is_nfs () && (conv_hdl
.nfsattr ()->type
& 7) == NF3LNK
)
3358 res
= check_nfs_symlink (h
);
3366 syscall_printf ("%s", isdevice
? "is a device" : "not a symlink");
3373 if (pc_flags
& PC_KEEP_HANDLE
)
3379 syscall_printf ("%d = symlink.check(%s, %p) (mount_flags %y, path_flags %y)",
3380 res
, suffix
.path
, contents
, mount_flags
, path_flags
);
3384 /* "path" is the path in a virtual symlink. Set a symlink_info struct from
3385 that and proceed with further path checking afterwards. */
3387 symlink_info::set (char *path
)
3389 strcpy (contents
, path
);
3391 path_flags
= PATH_SYMLINK
;
3392 fileattr
= FILE_ATTRIBUTE_NORMAL
;
3396 ext_tacked_on
= false;
3398 extn
= major
= minor
= mode
= 0;
3399 return strlen (path
);
3402 /* readlink system call */
3405 readlink (const char *__restrict path
, char *__restrict buf
, size_t buflen
)
3409 set_errno (ENAMETOOLONG
);
3413 path_conv
pathbuf (path
, PC_SYM_CONTENTS
, stat_suffixes
);
3417 set_errno (pathbuf
.error
);
3418 syscall_printf ("-1 = readlink (%s, %p, %lu)", path
, buf
, buflen
);
3422 if (!pathbuf
.exists ())
3428 if (!pathbuf
.issymlink ())
3430 if (pathbuf
.exists ())
3435 size_t pathbuf_len
= strlen (pathbuf
.get_win32 ());
3436 ssize_t len
= MIN (buflen
, pathbuf_len
);
3437 memcpy (buf
, pathbuf
.get_win32 (), len
);
3439 /* errno set by symlink.check if error */
3443 /* Some programs rely on st_dev/st_ino being unique for each file.
3444 Hash the path name and hope for the best. The hash arg is not
3445 always initialized to zero since readdir needs to compute the
3446 dirent ino_t based on a combination of the hash of the directory
3447 done during the opendir call and the hash or the filename within
3448 the directory. FIXME: Not bullet-proof. */
3449 /* Cygwin internal */
3451 hash_path_name (ino_t hash
, PUNICODE_STRING name
)
3453 if (name
->Length
== 0)
3456 /* Build up hash. Name is already normalized */
3457 USHORT len
= name
->Length
/ sizeof (WCHAR
);
3458 for (USHORT idx
= 0; idx
< len
; ++idx
)
3459 hash
= RtlUpcaseUnicodeChar (name
->Buffer
[idx
])
3460 + (hash
<< 6) + (hash
<< 16) - hash
;
3465 hash_path_name (ino_t hash
, PCWSTR name
)
3467 UNICODE_STRING uname
;
3468 RtlInitUnicodeString (&uname
, name
);
3469 return hash_path_name (hash
, &uname
);
3473 hash_path_name (ino_t hash
, const char *name
)
3475 UNICODE_STRING uname
;
3476 RtlCreateUnicodeStringFromAsciiz (&uname
, name
);
3477 ino_t ret
= hash_path_name (hash
, &uname
);
3478 RtlFreeUnicodeString (&uname
);
3483 getcwd (char *buf
, size_t ulen
)
3489 if (ulen
== 0 && buf
)
3492 res
= cygheap
->cwd
.get (buf
, 1, 1, ulen
);
3494 __except (EFAULT
) {}
3499 /* getwd: Legacy. */
3503 return getcwd (buf
, PATH_MAX
+ 1); /*Per SuSv3!*/
3507 get_current_dir_name (void)
3509 const char *pwd
= getenv ("PWD");
3510 char *cwd
= getcwd (NULL
, 0);
3511 struct stat pwdbuf
, cwdbuf
;
3513 if (pwd
&& strcmp (pwd
, cwd
) != 0
3514 && stat64 (pwd
, &pwdbuf
) == 0
3515 && stat64 (cwd
, &cwdbuf
) == 0
3516 && pwdbuf
.st_dev
== cwdbuf
.st_dev
3517 && pwdbuf
.st_ino
== cwdbuf
.st_ino
)
3519 cwd
= (char *) realloc (cwd
, strlen (pwd
) + 1);
3526 /* chdir: POSIX 5.2.1.1 */
3528 chdir (const char *in_dir
)
3540 syscall_printf ("dir '%s'", in_dir
);
3542 /* Convert path. PC_NONULLEMPTY ensures that we don't check for
3543 NULL/empty/invalid again. */
3544 path_conv
path (in_dir
, PC_SYM_FOLLOW
| PC_POSIX
| PC_NONULLEMPTY
);
3547 set_errno (path
.error
);
3548 syscall_printf ("-1 = chdir (%s)", in_dir
);
3552 const char *posix_cwd
= NULL
;
3553 dev_t devn
= path
.get_device ();
3554 if (!path
.exists ())
3556 else if (!path
.isdir ())
3557 set_errno (ENOTDIR
);
3558 else if (!isvirtual_dev (devn
))
3560 /* The sequence chdir("xx"); chdir(".."); must be a noop if xx
3561 is not a symlink. This is exploited by find.exe.
3562 The posix_cwd is just path.get_posix ().
3563 In other cases we let cwd.set obtain the Posix path through
3565 if (!isdrive (path
.get_posix ()))
3566 posix_cwd
= path
.get_posix ();
3571 posix_cwd
= path
.get_posix ();
3576 res
= cygheap
->cwd
.set (&path
, posix_cwd
);
3578 /* Note that we're accessing cwd.posix without a lock here.
3579 I didn't think it was worth locking just for strace. */
3580 syscall_printf ("%R = chdir() cygheap->cwd.posix '%s' native '%S'", res
,
3581 cygheap
->cwd
.get_posix (), path
.get_nt_native_path ());
3595 cygheap_fdget
cfd (fd
);
3597 res
= chdir (cfd
->get_name ());
3601 syscall_printf ("%R = fchdir(%d)", res
, fd
);
3605 /******************** Exported Path Routines *********************/
3607 /* Cover functions to the path conversion routines.
3608 These are exported to the world as cygwin_foo by cygwin.din. */
3610 #define return_with_errno(x) \
3620 cygwin_conv_path (cygwin_conv_path_t what
, const void *from
, void *to
,
3629 int how
= what
& CCP_CONVFLAGS_MASK
;
3630 what
&= CCP_CONVTYPE_MASK
;
3643 case CCP_POSIX_TO_WIN_A
:
3645 p
.check ((const char *) from
,
3646 PC_POSIX
| PC_SYM_FOLLOW
| PC_SYM_NOFOLLOW_REP
3647 | PC_NO_ACCESS_CHECK
3648 | ((how
& CCP_RELATIVE
) ? PC_NOFULL
: 0), stat_suffixes
);
3651 set_errno (p
.error
);
3654 PUNICODE_STRING up
= p
.get_nt_native_path ();
3656 sys_wcstombs (buf
, NT_MAX_PATH
,
3657 up
->Buffer
, up
->Length
/ sizeof (WCHAR
));
3658 /* Convert native path to standard DOS path. */
3659 if (!strncmp (buf
, "\\??\\", 4))
3662 if (buf
[1] != ':') /* native UNC path */
3665 else if (*buf
== '\\')
3667 /* Device name points to somewhere else in the NT namespace.
3668 Use GLOBALROOT prefix to convert to Win32 path. */
3669 char *p
= buf
+ sys_wcstombs (buf
, NT_MAX_PATH
,
3670 ro_u_globalroot
.Buffer
,
3671 ro_u_globalroot
.Length
3673 sys_wcstombs (p
, NT_MAX_PATH
- (p
- buf
),
3674 up
->Buffer
, up
->Length
/ sizeof (WCHAR
));
3676 lsiz
= strlen (buf
) + 1;
3677 /* TODO: Incoming "." is a special case which leads to a trailing
3678 backslash ".\\" in the Win32 path. That's a result of the
3679 conversion in normalize_posix_path. This should not occur
3680 so the below code is just a band-aid. */
3681 if ((how
& CCP_RELATIVE
) && !strcmp ((const char *) from
, ".")
3682 && !strcmp (buf
, ".\\"))
3689 case CCP_POSIX_TO_WIN_W
:
3690 p
.check ((const char *) from
,
3691 PC_POSIX
| PC_SYM_FOLLOW
| PC_SYM_NOFOLLOW_REP
3692 | PC_NO_ACCESS_CHECK
3693 | ((how
& CCP_RELATIVE
) ? PC_NOFULL
: 0), stat_suffixes
);
3696 set_errno (p
.error
);
3699 /* Relative Windows paths are always restricted to MAX_PATH chars. */
3700 if ((how
& CCP_RELATIVE
) && !isabspath (p
.get_win32 ())
3701 && sys_mbstowcs (NULL
, 0, p
.get_win32 ()) > MAX_PATH
)
3703 /* Recreate as absolute path. */
3704 p
.check ((const char *) from
, PC_POSIX
| PC_SYM_FOLLOW
3705 | PC_NO_ACCESS_CHECK
);
3708 set_errno (p
.error
);
3712 lsiz
= p
.get_wide_win32_path_len () + 1;
3713 path
= p
.get_nt_native_path ()->Buffer
;
3715 /* Convert native path to standard DOS path. */
3716 if (!wcsncmp (path
, L
"\\??\\", 4))
3720 /* Drop long path prefix for short pathnames. Unfortunately there's
3721 quite a bunch of Win32 functions, especially in user32.dll,
3722 apparently, which don't grok long path names at all, not even
3723 in the UNICODE API. */
3724 if ((path
[5] == L
':' && lsiz
<= MAX_PATH
+ 4)
3725 || (!wcsncmp (path
+ 4, L
"UNC\\", 4) && lsiz
<= MAX_PATH
+ 6))
3729 if (path
[1] != L
':')
3731 *(path
+= 2) = '\\';
3736 else if (*path
== L
'\\')
3738 /* Device name points to somewhere else in the NT namespace.
3739 Use GLOBALROOT prefix to convert to Win32 path. */
3740 to
= (void *) wcpcpy ((wchar_t *) to
, ro_u_globalroot
.Buffer
);
3741 lsiz
+= ro_u_globalroot
.Length
/ sizeof (WCHAR
);
3743 /* TODO: Same ".\\" band-aid as in CCP_POSIX_TO_WIN_A case. */
3744 if ((how
& CCP_RELATIVE
) && !strcmp ((const char *) from
, ".")
3745 && !wcscmp (path
, L
".\\"))
3750 lsiz
*= sizeof (WCHAR
);
3752 case CCP_WIN_A_TO_POSIX
:
3754 error
= mount_table
->conv_to_posix_path ((const char *) from
, buf
,
3755 how
| __CCP_APP_SLASH
);
3758 set_errno (p
.error
);
3761 lsiz
= strlen (buf
) + 1;
3763 case CCP_WIN_W_TO_POSIX
:
3765 error
= mount_table
->conv_to_posix_path ((const PWCHAR
) from
, buf
,
3766 how
| __CCP_APP_SLASH
);
3772 lsiz
= strlen (buf
) + 1;
3790 case CCP_POSIX_TO_WIN_A
:
3791 case CCP_WIN_A_TO_POSIX
:
3792 case CCP_WIN_W_TO_POSIX
:
3793 stpcpy ((char *) to
, buf
);
3795 case CCP_POSIX_TO_WIN_W
:
3796 wcpcpy ((PWCHAR
) to
, path
);
3801 __except (EFAULT
) {}
3807 cygwin_create_path (cygwin_conv_path_t what
, const void *from
)
3810 ssize_t size
= cygwin_conv_path (what
, from
, NULL
, 0);
3813 else if (!(to
= malloc (size
)))
3815 if (cygwin_conv_path (what
, from
, to
, size
) == -1)
3826 cygwin_conv_to_win32_path (const char *path
, char *win32_path
)
3828 return cygwin_conv_path (CCP_POSIX_TO_WIN_A
| CCP_RELATIVE
, path
, win32_path
,
3833 cygwin_conv_to_full_win32_path (const char *path
, char *win32_path
)
3835 return cygwin_conv_path (CCP_POSIX_TO_WIN_A
| CCP_ABSOLUTE
, path
, win32_path
,
3839 /* This is exported to the world as cygwin_foo by cygwin.din. */
3842 cygwin_conv_to_posix_path (const char *path
, char *posix_path
)
3844 return cygwin_conv_path (CCP_WIN_A_TO_POSIX
| CCP_RELATIVE
, path
, posix_path
,
3849 cygwin_conv_to_full_posix_path (const char *path
, char *posix_path
)
3851 return cygwin_conv_path (CCP_WIN_A_TO_POSIX
| CCP_ABSOLUTE
, path
, posix_path
,
3855 #endif /* __i386__ */
3857 /* The realpath function is required by POSIX:2008. */
3860 realpath (const char *__restrict path
, char *__restrict resolved
)
3865 /* Make sure the right errno is returned if path is NULL. */
3872 /* Guard reading from a potentially invalid path and writing to a
3873 potentially invalid resolved. */
3876 /* Win32 drive letter paths and, generally, any path starting with a
3877 backslash, have to be converted to a POSIX path first, because
3878 path_conv leaves the incoming path untouched except for converting
3879 backslashes to forward slashes. This also covers '\\?\ and '\??\'
3881 if (isdrive (path
) || path
[0] == '\\')
3883 tpath
= tp
.c_get ();
3884 mount_table
->conv_to_posix_path (path
, tpath
, 0);
3887 tpath
= (char *) path
;
3889 path_conv
real_path (tpath
, PC_SYM_FOLLOW
| PC_POSIX
, stat_suffixes
);
3892 /* POSIX 2008 requires malloc'ing if resolved is NULL, and states
3893 that using non-NULL resolved is asking for portability
3896 if (!real_path
.error
&& real_path
.exists ())
3901 malloc (strlen (real_path
.get_posix ()) + 1);
3905 strcpy (resolved
, real_path
.get_posix ());
3909 /* FIXME: on error, Linux puts the name of the path
3910 component which could not be resolved into RESOLVED, but POSIX
3911 does not require this. */
3914 set_errno (real_path
.error
?: ENOENT
);
3916 __except (EFAULT
) {}
3921 /* Linux provides this extension. Since the only portable use of
3922 realpath requires a NULL second argument, we might as well have a
3923 one-argument wrapper. */
3925 canonicalize_file_name (const char *path
)
3927 return realpath (path
, NULL
);
3930 /* Return non-zero if path is a POSIX path list.
3931 This is exported to the world as cygwin_foo by cygwin.din.
3934 <sect1 id="add-func-cygwin-posix-path-list-p">
3935 <para>Rather than use a mode to say what the "proper" path list
3936 format is, we allow any, and give apps the tools they need to
3937 convert between the two. If a ';' is present in the path list it's
3938 a Win32 path list. Otherwise, if the first path begins with
3939 [letter]: (in which case it can be the only element since if it
3940 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
3941 it's a POSIX path list.</para>
3947 cygwin_posix_path_list_p (const char *path
)
3949 int posix_p
= !(strchr (path
, ';') || isdrive (path
));
3953 /* These are used for apps that need to convert env vars like PATH back and
3954 forth. The conversion is a two step process. First, an upper bound on the
3955 size of the buffer needed is computed. Then the conversion is done. This
3956 allows the caller to use alloca if it wants. */
3959 conv_path_list_buf_size (const char *path_list
, bool to_posix
)
3961 int i
, num_elms
, max_mount_path_len
, size
;
3964 path_conv
pc(".", PC_POSIX
);
3965 /* The theory is that an upper bound is
3966 current_size + (num_elms * max_mount_path_len) */
3967 /* FIXME: This method is questionable in the long run. */
3970 char delim
= to_posix
? ';' : ':';
3971 for (p
= path_list
, num_elms
= nrel
= 0; p
; num_elms
++)
3975 p
= strchr (++p
, delim
);
3978 /* 7: strlen ("//c") + slop, a conservative initial value */
3979 for (max_mount_path_len
= sizeof ("/cygdrive/X"), i
= 0;
3980 i
< mount_table
->nmounts
; i
++)
3982 int mount_len
= (to_posix
3983 ? mount_table
->mount
[i
].posix_pathlen
3984 : mount_table
->mount
[i
].native_pathlen
);
3985 if (max_mount_path_len
< mount_len
)
3986 max_mount_path_len
= mount_len
;
3990 size
= strlen (path_list
)
3991 + (num_elms
* max_mount_path_len
)
3992 + (nrel
* strlen (to_posix
? pc
.get_posix () : pc
.get_win32 ()))
3999 env_PATH_to_posix (const void *win32
, void *posix
, size_t size
)
4001 return_with_errno (conv_path_list ((const char *) win32
, (char *) posix
,
4008 cygwin_win32_to_posix_path_list_buf_size (const char *path_list
)
4010 return conv_path_list_buf_size (path_list
, true);
4014 cygwin_posix_to_win32_path_list_buf_size (const char *path_list
)
4016 return conv_path_list_buf_size (path_list
, false);
4020 cygwin_win32_to_posix_path_list (const char *win32
, char *posix
)
4022 return_with_errno (conv_path_list (win32
, posix
, MAX_PATH
,
4023 CCP_WIN_A_TO_POSIX
| CCP_RELATIVE
));
4027 cygwin_posix_to_win32_path_list (const char *posix
, char *win32
)
4029 return_with_errno (conv_path_list (posix
, win32
, MAX_PATH
,
4030 CCP_POSIX_TO_WIN_A
| CCP_RELATIVE
));
4033 #endif /* __i386__ */
4036 cygwin_conv_path_list (cygwin_conv_path_t what
, const void *from
, void *to
,
4041 void *orig_to
= NULL
;
4044 switch (what
& CCP_CONVTYPE_MASK
)
4046 case CCP_WIN_W_TO_POSIX
:
4047 if (!sys_wcstombs_alloc (&winp
, HEAP_NOTHEAP
, (const wchar_t *) from
,
4050 what
= (what
& ~CCP_CONVTYPE_MASK
) | CCP_WIN_A_TO_POSIX
;
4051 from
= (const void *) winp
;
4053 case CCP_POSIX_TO_WIN_W
:
4055 return conv_path_list_buf_size ((const char *) from
, 0)
4057 what
= (what
& ~CCP_CONVTYPE_MASK
) | CCP_POSIX_TO_WIN_A
;
4059 to
= (void *) tp
.w_get ();
4063 switch (what
& CCP_CONVTYPE_MASK
)
4065 case CCP_WIN_A_TO_POSIX
:
4066 case CCP_POSIX_TO_WIN_A
:
4068 return conv_path_list_buf_size ((const char *) from
,
4069 what
== CCP_WIN_A_TO_POSIX
);
4070 ret
= conv_path_list ((const char *) from
, (char *) to
, size
, what
);
4071 /* Free winp buffer in case of CCP_WIN_W_TO_POSIX. */
4074 /* Convert to WCHAR in case of CCP_POSIX_TO_WIN_W. */
4076 sys_mbstowcs ((wchar_t *) orig_to
, size
/ sizeof (WCHAR
),
4077 (const char *) to
, (size_t) -1);
4078 return_with_errno (ret
);
4087 /* cygwin_split_path: Split a path into directory and file name parts.
4088 Buffers DIR and FILE are assumed to be big enough.
4090 Examples (path -> `dir' / `file'):
4093 . -> `.' / `.' (FIXME: should this be `.' / `'?)
4094 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
4096 foo/bar -> `foo' / `bar'
4097 foo/bar/ -> `foo' / `bar'
4099 /foo/bar -> `/foo' / `bar'
4102 c:foo -> `c:/' / `foo'
4103 c:/foo -> `c:/' / `foo'
4107 cygwin_split_path (const char *path
, char *dir
, char *file
)
4109 int dir_started_p
= 0;
4111 /* Deal with drives.
4112 Remember that c:foo <==> c:/foo. */
4124 if (isdirsep (*path
))
4129 /* Determine if there are trailing slashes and "delete" them if present.
4130 We pretend as if they don't exist. */
4131 const char *end
= path
+ strlen (path
);
4132 /* path + 1: keep leading slash. */
4133 while (end
> path
+ 1 && isdirsep (end
[-1]))
4136 /* At this point, END points to one beyond the last character
4137 (with trailing slashes "deleted"). */
4139 /* Point LAST_SLASH at the last slash (duh...). */
4140 const char *last_slash
;
4141 for (last_slash
= end
- 1; last_slash
>= path
; --last_slash
)
4142 if (isdirsep (*last_slash
))
4145 if (last_slash
== path
)
4150 else if (last_slash
> path
)
4152 memcpy (dir
, path
, last_slash
- path
);
4153 dir
[last_slash
- path
] = 0;
4158 ; /* nothing to do */
4164 memcpy (file
, last_slash
+ 1, end
- last_slash
- 1);
4165 file
[end
- last_slash
- 1] = 0;
4169 copy_cwd_str (PUNICODE_STRING tgt
, PUNICODE_STRING src
)
4171 RtlCopyUnicodeString (tgt
, src
);
4172 if (tgt
->Buffer
[tgt
->Length
/ sizeof (WCHAR
) - 1] != L
'\\')
4174 tgt
->Buffer
[tgt
->Length
/ sizeof (WCHAR
)] = L
'\\';
4175 tgt
->Length
+= sizeof (WCHAR
);
4179 /*****************************************************************************/
4181 /* The find_fast_cwd_pointer function and parts of the
4182 cwdstuff::override_win32_cwd method are based on code using the
4185 Copyright 2010 John Carey. All rights reserved.
4187 Redistribution and use in source and binary forms, with or without
4188 modification, are permitted provided that the following conditions
4191 1. Redistributions of source code must retain the above
4192 copyright notice, this list of conditions and the following
4195 2. Redistributions in binary form must reproduce the above
4196 copyright notice, this list of conditions and the following
4197 disclaimer in the documentation and/or other materials provided
4198 with the distribution.
4200 THIS SOFTWARE IS PROVIDED BY JOHN CAREY ``AS IS'' AND ANY EXPRESS
4201 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4202 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4203 ARE DISCLAIMED. IN NO EVENT SHALL JOHN CAREY OR CONTRIBUTORS BE
4204 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
4205 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
4206 OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
4207 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
4208 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4209 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
4210 USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
4214 fcwd_access_t::SetFSCharacteristics (LONG val
)
4216 /* Special case FSCharacteristics. Didn't exist originally. */
4217 switch (fast_cwd_version ())
4222 f7
.FSCharacteristics
= val
;
4225 f8
.FSCharacteristics
= val
;
4231 fcwd_access_t::fast_cwd_version ()
4233 return cygheap
->cwd
.fast_cwd_version
;
4237 fcwd_access_t::CopyPath (UNICODE_STRING
&target
)
4239 /* Copy the Path contents over into the UNICODE_STRING referenced by
4240 target. This is used to set the CurrentDirectoryName in the
4241 user parameter block. */
4246 fcwd_access_t::Free (PVOID heap
)
4248 /* Decrement the reference count. If it's down to 0, free
4249 structure from heap. */
4250 if (InterlockedDecrement (&ReferenceCount ()) == 0)
4252 /* The handle on init is always a fresh one, not the handle inherited
4253 from the parent process. We always have to close it here.
4254 Note: The handle could be NULL, if we cd'ed into a virtual dir. */
4255 HANDLE h
= DirectoryHandle ();
4258 RtlFreeHeap (heap
, 0, this);
4263 fcwd_access_t::FillIn (HANDLE dir
, PUNICODE_STRING name
,
4264 ULONG old_dismount_count
)
4266 /* Fill in all values into this FAST_CWD structure. */
4267 DirectoryHandle () = dir
;
4268 ReferenceCount () = 1;
4269 OldDismountCount () = old_dismount_count
;
4270 /* The new structure stores the device characteristics of the
4271 volume holding the dir. RtlGetCurrentDirectory_U checks
4272 if the FILE_REMOVABLE_MEDIA flag is set and, if so, checks if
4273 the volume is still the same as the one used when opening
4274 the directory handle.
4275 We don't call NtQueryVolumeInformationFile for the \\?\PIPE,
4276 though. It just returns STATUS_INVALID_HANDLE anyway. */
4277 if (fast_cwd_version () != FCWD_OLD
)
4279 SetFSCharacteristics (0);
4280 if (name
!= &ro_u_pipedir
)
4283 FILE_FS_DEVICE_INFORMATION ffdi
;
4284 if (NT_SUCCESS (NtQueryVolumeInformationFile (dir
, &io
, &ffdi
,
4285 sizeof ffdi
, FileFsDeviceInformation
)))
4286 SetFSCharacteristics (ffdi
.Characteristics
);
4289 RtlInitEmptyUnicodeString (&Path (), Buffer (),
4290 MAX_PATH
* sizeof (WCHAR
));
4291 copy_cwd_str (&Path (), name
);
4295 fcwd_access_t::SetDirHandleFromBufferPointer (PWCHAR buf_p
, HANDLE dir
)
4297 /* Input: The buffer pointer as it's stored in the user parameter block
4298 and a directory handle.
4299 This function computes the address to the FAST_CWD structure based
4300 on the version and overwrites the directory handle. It is only
4301 used if we couldn't figure out the address of fast_cwd_ptr. */
4302 fcwd_access_t
*f_cwd
;
4303 switch (fast_cwd_version ())
4307 f_cwd
= (fcwd_access_t
*)
4308 ((PBYTE
) buf_p
- __builtin_offsetof (FAST_CWD_OLD
, Buffer
));
4311 f_cwd
= (fcwd_access_t
*)
4312 ((PBYTE
) buf_p
- __builtin_offsetof (FAST_CWD_7
, Buffer
));
4315 f_cwd
= (fcwd_access_t
*)
4316 ((PBYTE
) buf_p
- __builtin_offsetof (FAST_CWD_8
, Buffer
));
4319 f_cwd
->DirectoryHandle () = dir
;
4323 fcwd_access_t::SetVersionFromPointer (PBYTE buf_p
, bool is_buffer
)
4325 /* Given a pointer to the FAST_CWD structure (is_buffer == false) or a
4326 pointer to the Buffer within (is_buffer == true), this function
4327 computes the FAST_CWD version by checking that Path.MaximumLength
4328 equals MAX_PATH, and that Path.Buffer == Buffer. */
4330 buf_p
-= __builtin_offsetof (FAST_CWD_8
, Buffer
);
4331 fcwd_access_t
*f_cwd
= (fcwd_access_t
*) buf_p
;
4332 if (f_cwd
->f8
.Path
.MaximumLength
== MAX_PATH
* sizeof (WCHAR
)
4333 && f_cwd
->f8
.Path
.Buffer
== f_cwd
->f8
.Buffer
)
4334 fast_cwd_version () = FCWD_W8
;
4335 else if (f_cwd
->f7
.Path
.MaximumLength
== MAX_PATH
* sizeof (WCHAR
)
4336 && f_cwd
->f7
.Path
.Buffer
== f_cwd
->f7
.Buffer
)
4337 fast_cwd_version () = FCWD_W7
;
4339 fast_cwd_version () = FCWD_OLD
;
4342 /* This function scans the code in ntdll.dll to find the address of the
4343 global variable used to access the CWD. While the pointer is global,
4344 it's not exported from the DLL, unfortunately. Therefore we have to
4345 use some knowledge to figure out the address. */
4349 #define peek32(x) (*(int32_t *)(x))
4351 static fcwd_access_t
**
4352 find_fast_cwd_pointer ()
4354 /* Fetch entry points of relevant functions in ntdll.dll. */
4355 HMODULE ntdll
= GetModuleHandle ("ntdll.dll");
4358 const uint8_t *get_dir
= (const uint8_t *)
4359 GetProcAddress (ntdll
, "RtlGetCurrentDirectory_U");
4360 const uint8_t *ent_crit
= (const uint8_t *)
4361 GetProcAddress (ntdll
, "RtlEnterCriticalSection");
4362 if (!get_dir
|| !ent_crit
)
4364 /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
4365 const uint8_t *rcall
= (const uint8_t *) memchr (get_dir
, 0xe8, 80);
4368 /* Fetch offset from instruction and compute address of called function.
4369 This function actually fetches the current FAST_CWD instance and
4370 performs some other actions, not important to us. */
4371 const uint8_t *use_cwd
= rcall
+ 5 + peek32 (rcall
+ 1);
4372 /* Next we search for the locking mechanism and perform a sanity check.
4373 On Pre-Windows 8 we basically look for the RtlEnterCriticalSection call.
4374 Windows 8 does not call RtlEnterCriticalSection. The code manipulates
4375 the FastPebLock manually, probably because RtlEnterCriticalSection has
4376 been converted to an inline function. Either way, we test if the code
4377 uses the FastPebLock. */
4378 const uint8_t *movrbx
;
4379 const uint8_t *lock
= (const uint8_t *)
4380 memmem ((const char *) use_cwd
, 80,
4381 "\xf0\x0f\xba\x35", 4);
4384 /* The lock instruction tweaks the LockCount member, which is not at
4385 the start of the PRTL_CRITICAL_SECTION structure. So we have to
4386 subtract the offset of LockCount to get the real address. */
4387 PRTL_CRITICAL_SECTION lockaddr
=
4388 (PRTL_CRITICAL_SECTION
) (lock
+ 9 + peek32 (lock
+ 4)
4389 - offsetof (RTL_CRITICAL_SECTION
, LockCount
));
4390 /* Test if lock address is FastPebLock. */
4391 if (lockaddr
!= NtCurrentTeb ()->Peb
->FastPebLock
)
4393 /* Search `mov rel(%rip),%rbx'. This is the instruction fetching the
4394 address of the current fcwd_access_t pointer, and it should be pretty
4395 near to the locking stuff. */
4396 movrbx
= (const uint8_t *) memmem ((const char *) lock
, 40,
4401 /* Usually the callq RtlEnterCriticalSection follows right after
4402 fetching the lock address. */
4403 int call_rtl_offset
= 7;
4404 /* Search `lea rel(%rip),%rcx'. This loads the address of the lock into
4405 %rcx for the subsequent RtlEnterCriticalSection call. */
4406 lock
= (const uint8_t *) memmem ((const char *) use_cwd
, 80,
4410 /* Windows 8.1 Preview calls `lea rel(rip),%r12' then some unrelated
4411 or, then `mov %r12,%rcx', then `callq RtlEnterCriticalSection'. */
4412 lock
= (const uint8_t *) memmem ((const char *) use_cwd
, 80,
4416 call_rtl_offset
= 14;
4418 PRTL_CRITICAL_SECTION lockaddr
=
4419 (PRTL_CRITICAL_SECTION
) (lock
+ 7 + peek32 (lock
+ 3));
4420 /* Test if lock address is FastPebLock. */
4421 if (lockaddr
!= NtCurrentTeb ()->Peb
->FastPebLock
)
4423 /* Next is the `callq RtlEnterCriticalSection'. */
4424 lock
+= call_rtl_offset
;
4425 if (lock
[0] != 0xe8)
4427 const uint8_t *call_addr
= (const uint8_t *)
4428 (lock
+ 5 + peek32 (lock
+ 1));
4429 if (call_addr
!= ent_crit
)
4431 /* In contrast to the above Windows 8 code, we don't have to search
4432 for the `mov rel(%rip),%rbx' instruction. It follows right after
4433 the call to RtlEnterCriticalSection. */
4438 /* Check that the next instruction tests if the fetched value is NULL. */
4439 const uint8_t *testrbx
= (const uint8_t *)
4440 memmem (movrbx
+ 7, 3, "\x48\x85\xdb", 3);
4443 /* Compute address of the fcwd_access_t ** pointer. */
4444 return (fcwd_access_t
**) (testrbx
+ peek32 (movrbx
+ 3));
4448 #define peek32(x) (*(uint32_t *)(x))
4450 static fcwd_access_t
**
4451 find_fast_cwd_pointer ()
4453 /* Fetch entry points of relevant functions in ntdll.dll. */
4454 HMODULE ntdll
= GetModuleHandle ("ntdll.dll");
4457 const uint8_t *get_dir
= (const uint8_t *)
4458 GetProcAddress (ntdll
, "RtlGetCurrentDirectory_U");
4459 const uint8_t *ent_crit
= (const uint8_t *)
4460 GetProcAddress (ntdll
, "RtlEnterCriticalSection");
4461 if (!get_dir
|| !ent_crit
)
4463 /* Search first relative call instruction in RtlGetCurrentDirectory_U. */
4464 const uint8_t *rcall
= (const uint8_t *) memchr (get_dir
, 0xe8, 64);
4467 /* Fetch offset from instruction and compute address of called function.
4468 This function actually fetches the current FAST_CWD instance and
4469 performs some other actions, not important to us. */
4470 ptrdiff_t offset
= (ptrdiff_t) peek32 (rcall
+ 1);
4471 const uint8_t *use_cwd
= rcall
+ 5 + offset
;
4472 /* Find first `push %edi' instruction. */
4473 const uint8_t *pushedi
= (const uint8_t *) memchr (use_cwd
, 0x57, 32);
4476 /* ...which should be followed by `mov crit-sect-addr,%edi' then
4477 `push %edi', or by just a single `push crit-sect-addr'. */
4478 const uint8_t *movedi
= pushedi
+ 1;
4479 const uint8_t *mov_pfast_cwd
;
4480 if (movedi
[0] == 0x8b && movedi
[1] == 0xff) /* mov %edi,%edi -> W8 */
4482 /* Windows 8 does not call RtlEnterCriticalSection. The code manipulates
4483 the FastPebLock manually, probably because RtlEnterCriticalSection has
4484 been converted to an inline function.
4486 Next we search for a `mov some address,%eax'. This address points
4487 to the LockCount member of the FastPebLock structure, so the address
4488 is equal to FastPebLock + 4. */
4489 const uint8_t *moveax
= (const uint8_t *) memchr (movedi
, 0xb8, 16);
4492 offset
= (ptrdiff_t) peek32 (moveax
+ 1) - 4;
4493 /* Compare the address with the known PEB lock as stored in the PEB. */
4494 if ((PRTL_CRITICAL_SECTION
) offset
!= NtCurrentTeb ()->Peb
->FastPebLock
)
4496 /* Now search for the mov instruction fetching the address of the global
4498 mov_pfast_cwd
= moveax
;
4501 mov_pfast_cwd
= (const uint8_t *) memchr (++mov_pfast_cwd
, 0x8b, 48);
4503 while (mov_pfast_cwd
&& mov_pfast_cwd
[1] != 0x1d
4504 && (mov_pfast_cwd
- moveax
) < 48);
4505 if (!mov_pfast_cwd
|| mov_pfast_cwd
[1] != 0x1d)
4510 if (movedi
[0] == 0xbf && movedi
[5] == 0x57)
4512 else if (movedi
[0] == 0x68)
4514 else if (movedi
[0] == 0x88 && movedi
[4] == 0x83 && movedi
[7] == 0x68)
4516 /* Windows 8.1 Preview: The `mov lock_addr,%edi' is actually a
4517 `mov %cl,15(%esp), followed by an `or #-1,%ebx, followed by a
4518 `push lock_addr'. */
4524 /* Compare the address used for the critical section with the known
4525 PEB lock as stored in the PEB. */
4526 if ((PRTL_CRITICAL_SECTION
) peek32 (movedi
+ 1)
4527 != NtCurrentTeb ()->Peb
->FastPebLock
)
4529 /* To check we are seeing the right code, we check our expectation that
4530 the next instruction is a relative call into RtlEnterCriticalSection. */
4531 if (rcall
[0] != 0xe8)
4533 /* Check that this is a relative call to RtlEnterCriticalSection. */
4534 offset
= (ptrdiff_t) peek32 (rcall
+ 1);
4535 if (rcall
+ 5 + offset
!= ent_crit
)
4537 mov_pfast_cwd
= rcall
+ 5;
4539 /* After locking the critical section, the code should read the global
4540 PFAST_CWD * pointer that is guarded by that critical section. */
4541 if (mov_pfast_cwd
[0] != 0x8b)
4543 return (fcwd_access_t
**) peek32 (mov_pfast_cwd
+ 2);
4547 static fcwd_access_t
**
4550 /* Fetch the pointer but don't set the global fast_cwd_ptr yet. First
4551 we have to make sure we know the version of the FAST_CWD structure
4552 used on the system. */
4553 fcwd_access_t
**f_cwd_ptr
= find_fast_cwd_pointer ();
4559 #ifndef PROCESSOR_ARCHITECTURE_ARM64
4560 #define PROCESSOR_ARCHITECTURE_ARM64 12
4565 /* Check if we're running in WOW64 on ARM64. Skip the warning as long as
4566 there's no solution for finding the FAST_CWD pointer on that system.
4568 2018-07-12: Apparently current ARM64 WOW64 has a bug:
4569 It's GetNativeSystemInfo returns PROCESSOR_ARCHITECTURE_INTEL in
4570 wProcessorArchitecture. Since that's an invalid value (a 32 bit
4571 host system hosting a 32 bit emulator for itself?) we can use this
4572 value as an indicator to skip the message as well. */
4573 if (wincap
.is_wow64 ())
4575 GetNativeSystemInfo (&si
);
4576 if (si
.wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_ARM64
4577 || si
.wProcessorArchitecture
== PROCESSOR_ARCHITECTURE_INTEL
)
4580 #endif /* !__x86_64__ */
4583 small_printf ("Cygwin WARNING:\n"
4584 " Couldn't compute FAST_CWD pointer. This typically occurs if you're using\n"
4585 " an older Cygwin version on a newer Windows. Please update to the latest\n"
4586 " available Cygwin version from https://cygwin.com/. If the problem persists,\n"
4587 " please see https://cygwin.com/problems.html\n\n");
4589 if (f_cwd_ptr
&& *f_cwd_ptr
)
4591 /* Just evaluate structure version. */
4592 fcwd_access_t::SetVersionFromPointer ((PBYTE
) *f_cwd_ptr
, false);
4596 /* If we couldn't fetch fast_cwd_ptr, or if fast_cwd_ptr is NULL(*)
4597 we have to figure out the version from the Buffer pointer in the
4600 (*) This is very unlikely to happen when starting the first
4601 Cygwin process, since it only happens when starting the
4602 process in a directory which can't be used as CWD by Win32, or
4603 if the directory doesn't exist. But *if* it happens, we have
4604 no valid FAST_CWD structure, even though upp_cwd_str.Buffer is
4605 not NULL in that case. So we let the OS create a valid
4606 FAST_CWD structure temporarily to have something to work with.
4607 We know the pipe FS works. */
4608 PEB
&peb
= *NtCurrentTeb ()->Peb
;
4610 if (f_cwd_ptr
/* so *f_cwd_ptr == NULL */
4611 && !NT_SUCCESS (RtlSetCurrentDirectory_U (&ro_u_pipedir
)))
4612 api_fatal ("Couldn't set directory to %S temporarily.\n"
4613 "Cannot continue.", &ro_u_pipedir
);
4614 RtlEnterCriticalSection (peb
.FastPebLock
);
4615 fcwd_access_t::SetVersionFromPointer
4616 ((PBYTE
) peb
.ProcessParameters
->CurrentDirectoryName
.Buffer
, true);
4617 RtlLeaveCriticalSection (peb
.FastPebLock
);
4619 /* Eventually, after we set the version as well, set fast_cwd_ptr. */
4624 cwdstuff::override_win32_cwd (bool init
, ULONG old_dismount_count
)
4628 PEB
&peb
= *NtCurrentTeb ()->Peb
;
4629 UNICODE_STRING
&upp_cwd_str
= peb
.ProcessParameters
->CurrentDirectoryName
;
4630 HANDLE
&upp_cwd_hdl
= peb
.ProcessParameters
->CurrentDirectoryHandle
;
4632 if (fast_cwd_ptr
== (fcwd_access_t
**) -1)
4633 fast_cwd_ptr
= find_fast_cwd ();
4636 /* If we got a valid value for fast_cwd_ptr, we can simply replace
4637 the RtlSetCurrentDirectory_U function entirely. */
4638 PVOID heap
= peb
.ProcessHeap
;
4639 /* First allocate a new fcwd_access_t structure on the heap.
4640 The new fcwd_access_t structure is 4 byte bigger than the old one,
4641 but we simply don't care, so we allocate always room for the
4643 fcwd_access_t
*f_cwd
= (fcwd_access_t
*)
4644 RtlAllocateHeap (heap
, 0, sizeof (fcwd_access_t
));
4647 debug_printf ("RtlAllocateHeap failed");
4650 /* Fill in the values. */
4651 f_cwd
->FillIn (dir
, error
? &ro_u_pipedir
: &win32
,
4652 old_dismount_count
);
4653 /* Use PEB lock when switching fast_cwd_ptr to the new FAST_CWD
4654 structure and writing the CWD to the user process parameter
4655 block. This is equivalent to calling RtlAcquirePebLock/
4656 RtlReleasePebLock, but without having to go through the FS
4658 RtlEnterCriticalSection (peb
.FastPebLock
);
4659 fcwd_access_t
*old_cwd
= *fast_cwd_ptr
;
4660 *fast_cwd_ptr
= f_cwd
;
4661 f_cwd
->CopyPath (upp_cwd_str
);
4663 RtlLeaveCriticalSection (peb
.FastPebLock
);
4665 old_cwd
->Free (heap
);
4669 /* Fallback if we failed to find the fast_cwd_ptr value:
4671 - Call RtlSetCurrentDirectory_U.
4672 - Compute new FAST_CWD struct address from buffer pointer in the
4673 user process parameter block.
4674 - Replace the directory handle in the struct with our own handle.
4675 - Close the original handle. RtlSetCurrentDirectory_U already
4676 closed our former dir handle -> no handle leak.
4678 Guard the entire operation with FastPebLock to avoid races
4679 accessing the PEB and FAST_CWD struct.
4681 Unfortunately this method is still prone to a directory usage
4684 - The directory is locked against deletion or renaming between the
4685 RtlSetCurrentDirectory_U and the subsequent NtClose call. */
4686 if (unlikely (upp_cwd_hdl
== NULL
) && init
)
4688 RtlEnterCriticalSection (peb
.FastPebLock
);
4692 RtlSetCurrentDirectory_U (error
? &ro_u_pipedir
: &win32
);
4693 if (!NT_SUCCESS (status
))
4695 RtlLeaveCriticalSection (peb
.FastPebLock
);
4696 debug_printf ("RtlSetCurrentDirectory_U(%S) failed, %y",
4697 error
? &ro_u_pipedir
: &win32
, status
);
4701 fcwd_access_t::SetDirHandleFromBufferPointer(upp_cwd_str
.Buffer
, dir
);
4704 RtlLeaveCriticalSection (peb
.FastPebLock
);
4705 /* The handle on init is always a fresh one, not the handle inherited
4706 from the parent process. We always have to close it here. */
4711 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
4715 cwd_lock
.init ("cwd_lock");
4717 /* Cygwin processes inherit the cwd from their parent. If the win32 path
4718 buffer is not NULL, the cwd struct is already set up, and we only
4719 have to override the Win32 CWD with ours. */
4721 override_win32_cwd (true, SharedUserData
.DismountCount
);
4724 /* Initialize fast_cwd stuff. */
4725 fast_cwd_ptr
= (fcwd_access_t
**) -1;
4726 fast_cwd_version
= FCWD_W7
;
4727 /* Initially re-open the cwd to allow POSIX semantics. */
4732 /* Chdir and fill out the elements of a cwdstuff struct. */
4734 cwdstuff::set (path_conv
*nat_cwd
, const char *posix_cwd
)
4737 UNICODE_STRING upath
;
4738 PEB
&peb
= *NtCurrentTeb ()->Peb
;
4739 bool virtual_path
= false;
4740 bool unc_path
= false;
4741 bool inaccessible_path
= false;
4743 /* Here are the problems with using SetCurrentDirectory. Just skip this
4744 comment if you don't like whining.
4746 - SetCurrentDirectory only supports paths of up to MAX_PATH - 1 chars,
4747 including a trailing backslash. That's an absolute restriction, even
4750 - SetCurrentDirectory fails for directories with strict permissions even
4751 for processes with the SE_BACKUP_NAME privilege enabled. The reason
4752 is apparently that SetCurrentDirectory calls NtOpenFile without the
4753 FILE_OPEN_FOR_BACKUP_INTENT flag set.
4755 - SetCurrentDirectory does not support case-sensitivity.
4757 - Unlinking a cwd fails because SetCurrentDirectory seems to open
4758 directories so that deleting the directory is disallowed.
4760 - SetCurrentDirectory can naturally not work on virtual Cygwin paths
4761 like /proc or /cygdrive.
4763 Nevertheless, doing entirely without SetCurrentDirectory is not really
4764 feasible, because it breaks too many mixed applications using the Win32
4767 Therefore we handle the CWD all by ourselves and just keep the Win32
4768 CWD in sync. However, to avoid surprising behaviour in the Win32 API
4769 when we are in a CWD which is inaccessible as Win32 CWD, we set the
4770 Win32 CWD to a "weird" directory in which all relative filesystem-related
4773 cwd_lock
.acquire ();
4777 upath
= *nat_cwd
->get_nt_native_path ();
4778 if (nat_cwd
->isspecial ())
4779 virtual_path
= true;
4782 /* Memorize old DismountCount before opening the dir. This value is
4783 stored in the FAST_CWD structure. It would be simpler to fetch the
4784 old DismountCount in override_win32_cwd, but Windows also fetches
4785 it before opening the directory handle. It's not quite clear if
4786 that's really required, but since we don't know the side effects of
4787 this action, we better follow Windows' lead. */
4788 ULONG old_dismount_count
= SharedUserData
.DismountCount
;
4789 /* Open a directory handle with FILE_OPEN_FOR_BACKUP_INTENT and with all
4790 sharing flags set. The handle is right now used in exceptions.cc only,
4791 but that might change in future. */
4796 OBJECT_ATTRIBUTES attr
;
4800 /* On init, just reopen Win32 CWD with desired access flags.
4801 We can access the PEB without lock, because no other thread
4802 can change the CWD. However, there's a chance that the handle
4803 is NULL, even though CurrentDirectoryName isn't so we have to
4805 if (!peb
.ProcessParameters
->CurrentDirectoryHandle
)
4807 InitializeObjectAttributes (&attr
,
4808 &peb
.ProcessParameters
->CurrentDirectoryName
,
4809 OBJ_CASE_INSENSITIVE
| OBJ_INHERIT
, NULL
, NULL
);
4813 RtlInitUnicodeString (&upath
, L
"");
4814 InitializeObjectAttributes (&attr
,
4815 &upath
, OBJ_CASE_INSENSITIVE
| OBJ_INHERIT
,
4816 peb
.ProcessParameters
->CurrentDirectoryHandle
,
4821 InitializeObjectAttributes (&attr
, &upath
,
4822 nat_cwd
->objcaseinsensitive () | OBJ_INHERIT
,
4824 /* First try without FILE_OPEN_FOR_BACKUP_INTENT, to find out if the
4825 directory is valid for Win32 apps. And, no, we can't just call
4826 SetCurrentDirectory here, since that would potentially break
4827 case-sensitivity. */
4828 status
= NtOpenFile (&h
, SYNCHRONIZE
| FILE_TRAVERSE
, &attr
, &io
,
4829 FILE_SHARE_VALID_FLAGS
,
4831 | FILE_SYNCHRONOUS_IO_NONALERT
);
4832 if (status
== STATUS_ACCESS_DENIED
)
4834 status
= NtOpenFile (&h
, SYNCHRONIZE
| FILE_TRAVERSE
, &attr
, &io
,
4835 FILE_SHARE_VALID_FLAGS
,
4837 | FILE_SYNCHRONOUS_IO_NONALERT
4838 | FILE_OPEN_FOR_BACKUP_INTENT
);
4839 inaccessible_path
= true;
4841 if (!NT_SUCCESS (status
))
4843 /* Called from chdir? Just fail. */
4846 cwd_lock
.release ();
4847 __seterrno_from_nt_status (status
);
4850 /* Otherwise we're in init and posix hasn't been set yet. Try to
4851 duplicate the handle instead. If that fails, too, set dir to NULL
4852 and carry on. This will at least set posix to some valid path at
4853 process startup, and subsequent getcwd calls don't EFAULT. */
4854 debug_printf ("WARNING: Can't reopen CWD %y '%S', status %y",
4855 peb
.ProcessParameters
->CurrentDirectoryHandle
,
4856 &peb
.ProcessParameters
->CurrentDirectoryName
,
4858 if (!peb
.ProcessParameters
->CurrentDirectoryHandle
4859 || !DuplicateHandle (GetCurrentProcess (),
4860 peb
.ProcessParameters
->CurrentDirectoryHandle
,
4861 GetCurrentProcess (), &h
, 0, TRUE
, 0))
4863 cwd_lock
.release ();
4864 if (peb
.ProcessParameters
->CurrentDirectoryHandle
)
4865 debug_printf ("...and DuplicateHandle failed with %E.");
4870 /* Set new handle. Note that we simply overwrite the old handle here
4871 without closing it. The handle is also used as Win32 CWD handle in
4872 the user parameter block, and it will be closed in override_win32_cwd,
4878 /* On init, just fetch the Win32 dir from the PEB. We can access
4879 the PEB without lock, because no other thread can change the CWD
4881 PUNICODE_STRING pdir
= &peb
.ProcessParameters
->CurrentDirectoryName
;
4882 RtlInitEmptyUnicodeString (&win32
,
4883 (PWCHAR
) crealloc_abort (win32
.Buffer
,
4886 pdir
->Length
+ sizeof (WCHAR
));
4887 RtlCopyUnicodeString (&win32
, pdir
);
4889 PWSTR eoBuffer
= win32
.Buffer
+ (win32
.Length
/ sizeof (WCHAR
));
4890 /* Remove trailing slash if one exists. */
4891 if ((eoBuffer
- win32
.Buffer
) > 3 && eoBuffer
[-1] == L
'\\')
4892 win32
.Length
-= sizeof (WCHAR
);
4893 if (eoBuffer
[0] == L
'\\')
4900 if (!virtual_path
) /* don't mangle virtual path. */
4902 /* Convert into Win32 path and compute length. */
4903 if (upath
.Buffer
[1] == L
'?')
4906 upath
.Length
-= 4 * sizeof (WCHAR
);
4907 if (upath
.Buffer
[1] != L
':')
4911 upath
.Length
-= 2 * sizeof (WCHAR
);
4917 /* Path via native NT namespace. Prepend GLOBALROOT prefix
4918 to create a valid Win32 path. */
4919 PWCHAR buf
= (PWCHAR
) alloca (upath
.Length
4920 + ro_u_globalroot
.Length
4922 wcpcpy (wcpcpy (buf
, ro_u_globalroot
.Buffer
), upath
.Buffer
);
4924 upath
.Length
+= ro_u_globalroot
.Length
;
4926 PWSTR eoBuffer
= upath
.Buffer
+ (upath
.Length
/ sizeof (WCHAR
));
4927 /* Remove trailing slash if one exists. */
4928 if ((eoBuffer
- upath
.Buffer
) > 3 && eoBuffer
[-1] == L
'\\')
4929 upath
.Length
-= sizeof (WCHAR
);
4931 RtlInitEmptyUnicodeString (&win32
,
4932 (PWCHAR
) crealloc_abort (win32
.Buffer
,
4935 upath
.Length
+ sizeof (WCHAR
));
4936 RtlCopyUnicodeString (&win32
, &upath
);
4938 win32
.Buffer
[0] = L
'\\';
4940 /* Make sure it's NUL-terminated. */
4941 win32
.Buffer
[win32
.Length
/ sizeof (WCHAR
)] = L
'\0';
4943 /* Set drive_length, used in path conversion, and error code, used in
4944 spawn_guts to decide whether a native Win32 app can be started or not. */
4956 PWCHAR ptr
= wcschr (win32
.Buffer
+ 2, L
'\\');
4958 ptr
= wcschr (ptr
+ 1, L
'\\');
4960 drive_length
= ptr
- win32
.Buffer
;
4962 drive_length
= win32
.Length
/ sizeof (WCHAR
);
4964 if (inaccessible_path
)
4966 else if (win32
.Length
> (MAX_PATH
- 2) * sizeof (WCHAR
))
4967 error
= ENAMETOOLONG
;
4971 /* Keep the Win32 CWD in sync. Don't check for error, other than for
4972 strace output. Try to keep overhead low. */
4973 override_win32_cwd (!nat_cwd
, old_dismount_count
);
4975 /* Eventually, create POSIX path if it's not set on entry. */
4979 posix_cwd
= (const char *) tp
.c_get ();
4980 mount_table
->conv_to_posix_path (win32
.Buffer
, (char *) posix_cwd
, 0);
4982 posix
= (char *) crealloc_abort (posix
, strlen (posix_cwd
) + 1);
4983 stpcpy (posix
, posix_cwd
);
4985 cwd_lock
.release ();
4990 cwdstuff::get_error_desc () const
4992 switch (cygheap
->cwd
.get_error ())
4995 return "has restricted permissions which render it\n"
4996 "inaccessible as Win32 working directory";
4998 return "is a virtual Cygwin directory which does\n"
4999 "not exist for a native Windows application";
5001 return "has a path longer than allowed for a\n"
5002 "Win32 working directory";
5006 /* That shouldn't occur, unless we defined a new error code
5007 in cwdstuff::set. */
5008 return "is not accessible for some unknown reason";
5011 /* Store incoming wchar_t path as current posix cwd. This is called from
5012 setlocale so that the cwd is always stored in the right charset. */
5014 cwdstuff::reset_posix (wchar_t *w_cwd
)
5016 size_t len
= sys_wcstombs (NULL
, (size_t) -1, w_cwd
);
5017 posix
= (char *) crealloc_abort (posix
, len
+ 1);
5018 sys_wcstombs (posix
, len
+ 1, w_cwd
);
5022 cwdstuff::get (char *buf
, int need_posix
, int with_chroot
, unsigned ulen
)
5027 else if (buf
== NULL
)
5028 ulen
= (unsigned) -1;
5035 cwd_lock
.acquire ();
5040 tocopy
= tp
.c_get ();
5041 sys_wcstombs (tocopy
, NT_MAX_PATH
, win32
.Buffer
,
5042 win32
.Length
/ sizeof (WCHAR
));
5047 debug_printf ("posix %s", posix
);
5048 if (strlen (tocopy
) >= ulen
)
5056 buf
= (char *) malloc (strlen (tocopy
) + 1);
5057 strcpy (buf
, tocopy
);
5058 if (!buf
[0]) /* Should only happen when chroot */
5062 cwd_lock
.release ();
5065 syscall_printf ("(%s) = cwdstuff::get (%p, %u, %d, %d), errno %d",
5066 buf
, buf
, ulen
, need_posix
, with_chroot
, errno
);
5070 /* No need to be reentrant or thread-safe according to SUSv3.
5071 / and \\ are treated equally. Leading drive specifiers are
5072 kept intact as far as it makes sense. Everything else is
5073 POSIX compatible. */
5075 basename (char *path
)
5078 char *c
, *d
, *bs
= path
;
5080 if (!path
|| !*path
)
5081 return strcpy (buf
, ".");
5082 if (isalpha (path
[0]) && path
[1] == ':')
5084 else if (strspn (path
, "/\\") > 1)
5086 c
= strrchr (bs
, '/');
5087 if ((d
= strrchr (c
?: bs
, '\\')) > c
)
5091 /* Trailing (back)slashes are eliminated. */
5092 while (c
&& c
> bs
&& c
[1] == '\0')
5095 c
= strrchr (bs
, '/');
5096 if ((d
= strrchr (c
?: bs
, '\\')) > c
)
5099 if (c
&& (c
> bs
|| c
[1]))
5104 stpncpy (buf
, path
, bs
- path
);
5105 stpcpy (buf
+ (bs
- path
), ".");
5111 /* The differences with the POSIX version above:
5112 - declared in <string.h> (instead of <libgen.h>);
5113 - the argument is never modified, and therefore is marked const;
5114 - the empty string is returned if path is an empty string, "/", or ends
5115 with a trailing slash. */
5117 __gnu_basename (const char *path
)
5120 char *c
, *d
, *bs
= (char *)path
;
5122 if (!path
|| !*path
)
5123 return strcpy (buf
, "");
5124 if (isalpha (path
[0]) && path
[1] == ':')
5126 else if (strspn (path
, "/\\") > 1)
5128 c
= strrchr (bs
, '/');
5129 if ((d
= strrchr (c
?: bs
, '\\')) > c
)
5134 return strcpy (buf
, "");
5135 return (char *)path
;
5138 /* No need to be reentrant or thread-safe according to SUSv3.
5139 / and \\ are treated equally. Leading drive specifiers and
5140 leading double (back)slashes are kept intact as far as it
5141 makes sense. Everything else is POSIX compatible. */
5143 dirname (char *path
)
5146 char *c
, *d
, *bs
= path
;
5148 if (!path
|| !*path
)
5149 return strcpy (buf
, ".");
5150 if (isalpha (path
[0]) && path
[1] == ':')
5152 else if (strspn (path
, "/\\") > 1)
5154 c
= strrchr (bs
, '/');
5155 if ((d
= strrchr (c
?: bs
, '\\')) > c
)
5159 /* Trailing (back)slashes are eliminated. */
5160 while (c
&& c
> bs
&& c
[1] == '\0')
5163 c
= strrchr (bs
, '/');
5164 if ((d
= strrchr (c
?: bs
, '\\')) > c
)
5171 /* More trailing (back)slashes are eliminated. */
5172 while (c
> bs
&& (*c
== '/' || *c
== '\\'))
5180 stpncpy (buf
, path
, bs
- path
);
5181 stpcpy (buf
+ (bs
- path
), ".");