1 /* path.cc: path support.
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 /* This module's job is to
13 - convert between POSIX and Win32 style filenames,
14 - support the `mount' functionality,
15 - support symlinks for files and directories
17 Pathnames are handled as follows:
19 - A \ or : in a path denotes a pure windows spec.
20 - Paths beginning with // (or \\) are not translated (i.e. looked
21 up in the mount table) and are assumed to be UNC path names.
23 The goal in the above set of rules is to allow both POSIX and Win32
24 flavors of pathnames without either interfering. The rules are
25 intended to be as close to a superset of both as possible.
27 Note that you can have more than one path to a file. The mount
28 table is always prefered when translating Win32 paths to POSIX
29 paths. Win32 paths in mount table entries may be UNC paths or
30 standard Win32 paths starting with <drive-letter>:
32 Text vs Binary issues are not considered here in path style
33 decisions, although the appropriate flags are retrieved and
34 stored in various structures.
36 Removing mounted filesystem support would simplify things greatly,
37 but having it gives us a mechanism of treating disk that lives on a
38 UNIX machine as having UNIX semantics [it allows one to edit a text
39 file on that disk and not have cr's magically appear and perhaps
40 break apps running on UNIX boxes]. It also useful to be able to
41 layout a hierarchy without changing the underlying directories.
43 The semantics of mounting file systems is not intended to precisely
44 follow normal UNIX systems.
46 Each DOS drive is defined to have a current directory. Supporting
47 this would complicate things so for now things are defined so that
52 #include "miscfuncs.h"
59 #include <sys/cygwin.h>
66 #include "shared_info.h"
76 bool dos_file_warning = true;
78 suffix_info stat_suffixes[] =
81 suffix_info (".exe", 1),
87 char contents[SYMLINK_MAX + 1];
99 int check (char *path, const suffix_info *suffixes, unsigned opt,
101 int set (char *path);
102 bool parse_device (const char *);
103 int check_sysfile (HANDLE h);
104 int check_shortcut (HANDLE h);
105 int check_reparse_point (HANDLE h);
106 int check_nfs_symlink (HANDLE h);
107 int posixify (char *srcbuf);
108 bool set_error (int);
111 muto NO_COPY cwdstuff::cwd_lock;
113 static const GUID GUID_shortcut
114 = { 0x00021401L, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
117 WSH_FLAG_IDLIST = 0x01, /* Contains an ITEMIDLIST. */
118 WSH_FLAG_FILE = 0x02, /* Contains a file locator element. */
119 WSH_FLAG_DESC = 0x04, /* Contains a description. */
120 WSH_FLAG_RELPATH = 0x08, /* Contains a relative path. */
121 WSH_FLAG_WD = 0x10, /* Contains a working dir. */
122 WSH_FLAG_CMDLINE = 0x20, /* Contains command line args. */
123 WSH_FLAG_ICON = 0x40 /* Contains a custom icon. */
126 struct win_shortcut_hdr
128 DWORD size; /* Header size in bytes. Must contain 0x4c. */
129 GUID magic; /* GUID of shortcut files. */
130 DWORD flags; /* Content flags. See above. */
132 /* The next fields from attr to icon_no are always set to 0 in Cygwin
133 and U/Win shortcuts. */
134 DWORD attr; /* Target file attributes. */
135 FILETIME ctime; /* These filetime items are never touched by the */
136 FILETIME mtime; /* system, apparently. Values don't matter. */
138 DWORD filesize; /* Target filesize. */
139 DWORD icon_no; /* Icon number. */
141 DWORD run; /* Values defined in winuser.h. Use SW_NORMAL. */
142 DWORD hotkey; /* Hotkey value. Set to 0. */
143 DWORD dummy[2]; /* Future extension probably. Always 0. */
146 /* Return non-zero if PATH1 is a prefix of PATH2.
147 Both are assumed to be of the same path style and / vs \ usage.
149 LEN1 = strlen (PATH1). It's passed because often it's already known.
152 /foo/ is a prefix of /foo <-- may seem odd, but desired
153 /foo is a prefix of /foo/
154 / is a prefix of /foo/bar
155 / is not a prefix of foo/bar
156 foo/ is a prefix foo/bar
157 /foo is not a prefix of /foobar
161 path_prefix_p (const char *path1, const char *path2, int len1,
162 bool caseinsensitive)
164 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
165 if (len1 > 0 && isdirsep (path1[len1 - 1]))
169 return isdirsep (path2[0]) && !isdirsep (path2[1]);
171 if (isdirsep (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':')
172 return caseinsensitive ? strncasematch (path1, path2, len1)
173 : !strncmp (path1, path2, len1);
178 /* Return non-zero if paths match in first len chars.
179 Check is dependent of the case sensitivity setting. */
181 pathnmatch (const char *path1, const char *path2, int len, bool caseinsensitive)
183 return caseinsensitive
184 ? strncasematch (path1, path2, len) : !strncmp (path1, path2, len);
187 /* Return non-zero if paths match. Check is dependent of the case
188 sensitivity setting. */
190 pathmatch (const char *path1, const char *path2, bool caseinsensitive)
192 return caseinsensitive
193 ? strcasematch (path1, path2) : !strcmp (path1, path2);
196 /* TODO: This function is used in mkdir and rmdir to generate correct
197 error messages in case of paths ending in /. or /.. components.
198 Right now, normalize_posix_path will just normalize
199 those components away, which changes the semantics. */
201 has_dot_last_component (const char *dir, bool test_dot_dot)
203 /* SUSv3: . and .. are not allowed as last components in various system
204 calls. Don't test for backslash path separator since that's a Win32
205 path following Win32 rules. */
206 const char *last_comp = strrchr (dir, '/');
210 /* Check for trailing slash. If so, hop back to the previous slash. */
212 while (last_comp > dir)
213 if (*--last_comp == '/')
215 if (*last_comp == '/')
218 return last_comp[0] == '.'
219 && ((last_comp[1] == '\0' || last_comp[1] == '/')
221 && last_comp[1] == '.'
222 && (last_comp[2] == '\0' || last_comp[2] == '/')));
225 /* Normalize a POSIX path.
226 All duplicate /'s, except for 2 leading /'s, are deleted.
227 The result is 0 for success, or an errno error value. */
230 normalize_posix_path (const char *src, char *dst, char *&tail)
232 const char *in_src = src;
233 char *dst_start = dst;
234 syscall_printf ("src %s", src);
236 if ((isdrive (src) && isdirsep (src[2])) || *src == '\\')
240 if (!isslash (src[0]))
242 if (!cygheap->cwd.get (dst))
244 tail = strchr (tail, '\0');
245 if (isslash (dst[0]) && isslash (dst[1]))
249 if (tail == dst_start + 1 && *dst_start == '/')
253 if (tail > dst && !isslash (tail[-1]))
256 /* Two leading /'s? If so, preserve them. */
257 else if (isslash (src[1]) && !isslash (src[2]))
267 /* Strip runs of /'s. */
288 if (!isslash (src[1]))
291 else if (src[2] && !isslash (src[2]))
295 while (tail > dst_start && !isslash (*--tail))
303 if ((tail - dst) >= NT_MAX_PATH)
305 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
313 debug_printf ("%s = normalize_posix_path (%s)", dst, in_src);
317 int err = normalize_win32_path (in_src, dst, tail);
319 for (char *p = dst; (p = strchr (p, '\\')); p++)
325 path_conv::add_ext_from_sym (symlink_info &sym)
327 if (sym.ext_here && *sym.ext_here)
329 known_suffix = path + sym.extn;
330 if (sym.ext_tacked_on)
331 strcpy ((char *) known_suffix, sym.ext_here);
335 static void __stdcall mkrelpath (char *dst, bool caseinsensitive)
336 __attribute__ ((regparm (2)));
338 static void __stdcall
339 mkrelpath (char *path, bool caseinsensitive)
342 char *cwd_win32 = tp.c_get ();
343 if (!cygheap->cwd.get (cwd_win32, 0))
346 unsigned cwdlen = strlen (cwd_win32);
347 if (!path_prefix_p (cwd_win32, path, cwdlen, caseinsensitive))
350 size_t n = strlen (path);
358 tail += isdirsep (cwd_win32[cwdlen - 1]) ? cwdlen : cwdlen + 1;
360 memmove (path, tail, strlen (tail) + 1);
366 path_conv::fillin (HANDLE h)
369 FILE_BASIC_INFORMATION fbi;
371 if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
372 FileBasicInformation)))
373 fileattr = fbi.FileAttributes;
375 fileattr = INVALID_FILE_ATTRIBUTES;
379 path_conv::set_normalized_path (const char *path_copy)
383 size_t n = strlen (path_copy) + 1;
384 char *p = (char *) cmalloc_abort (HEAP_STR, n);
385 normalized_path = (const char *) memcpy (p, path_copy, n);
389 WCHAR tfx_chars[] NO_COPY = {
390 0, 1, 2, 3, 4, 5, 6, 7,
391 8, 9, 10, 11, 12, 13, 14, 15,
392 16, 17, 18, 19, 20, 21, 22, 23,
393 24, 25, 26, 27, 28, 29, 30, 31,
394 32, '!', 0xf000 | '"', '#', '$', '%', '&', 39,
395 '(', ')', 0xf000 | '*', '+', ',', '-', '.', '\\',
396 '0', '1', '2', '3', '4', '5', '6', '7',
397 '8', '9', 0xf000 | ':', ';', 0xf000 | '<', '=', 0xf000 | '>', 0xf000 | '?',
398 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
399 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
400 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
401 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
402 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
403 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
404 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
405 'x', 'y', 'z', '{', 0xf000 | '|', '}', '~', 127
409 transform_chars (PWCHAR path, PWCHAR path_end)
411 for (; path <= path_end; ++path)
413 *path = tfx_chars[*path];
418 transform_chars (PUNICODE_STRING upath, USHORT start_idx)
420 transform_chars (upath->Buffer + start_idx,
421 upath->Buffer + upath->Length / sizeof (WCHAR) - 1);
425 str2uni_cat (UNICODE_STRING &tgt, const char *srcstr)
427 int len = sys_mbstowcs (tgt.Buffer + tgt.Length / sizeof (WCHAR),
428 (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR),
431 tgt.Length += (len - 1) * sizeof (WCHAR);
435 get_nt_native_path (const char *path, UNICODE_STRING& upath)
438 if (path[0] == '/') /* special path w/o NT path representation. */
439 str2uni_cat (upath, path);
440 else if (path[0] != '\\') /* X:\... or relative path. */
442 if (path[1] == ':') /* X:\... */
444 RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
445 str2uni_cat (upath, path);
446 /* The drive letter must be upper case. */
447 upath.Buffer[4] = towupper (upath.Buffer[4]);
450 str2uni_cat (upath, path);
451 transform_chars (&upath, 7);
453 else if (path[1] != '\\') /* \Device\... */
454 str2uni_cat (upath, path);
455 else if ((path[2] != '.' && path[2] != '?')
456 || path[3] != '\\') /* \\server\share\... */
458 RtlAppendUnicodeStringToString (&upath, &ro_u_uncp);
459 str2uni_cat (upath, path + 2);
460 transform_chars (&upath, 8);
462 else /* \\.\device or \\?\foo */
464 RtlAppendUnicodeStringToString (&upath, &ro_u_natp);
465 str2uni_cat (upath, path + 4);
471 path_conv::get_nt_native_path ()
476 uni_path.MaximumLength = (strlen (path) + 10) * sizeof (WCHAR);
477 wide_path = (PWCHAR) cmalloc_abort (HEAP_STR, uni_path.MaximumLength);
478 uni_path.Buffer = wide_path;
479 ::get_nt_native_path (path, uni_path);
485 path_conv::get_object_attr (OBJECT_ATTRIBUTES &attr, SECURITY_ATTRIBUTES &sa)
487 if (!get_nt_native_path ())
489 InitializeObjectAttributes (&attr, &uni_path,
490 objcaseinsensitive ()
491 | (sa.bInheritHandle ? OBJ_INHERIT : 0),
492 NULL, sa.lpSecurityDescriptor);
497 path_conv::get_wide_win32_path (PWCHAR wc)
499 get_nt_native_path ();
502 wcpcpy (wc, wide_path);
509 warn_msdos (const char *src)
511 if (user_shared->warned_msdos || !dos_file_warning || !cygwin_finished_initializing)
514 char *posix_path = tp.c_get ();
515 small_printf ("cygwin warning:\n");
516 if (cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, src,
517 posix_path, NT_MAX_PATH))
518 small_printf (" MS-DOS style path detected: %s\n POSIX equivalent preferred.\n",
521 small_printf (" MS-DOS style path detected: %s\n Preferred POSIX equivalent is: %s\n",
523 small_printf (" CYGWIN environment variable option \"nodosfilewarning\" turns off this warning.\n"
524 " Consult the user's guide for more details about POSIX paths:\n"
525 " http://cygwin.com/cygwin-ug-net/using.html#using-pathnames\n");
526 user_shared->warned_msdos = true;
530 getfileattr (const char *path, bool caseinsensitive) /* path has to be always absolute. */
533 UNICODE_STRING upath;
534 OBJECT_ATTRIBUTES attr;
535 FILE_BASIC_INFORMATION fbi;
540 InitializeObjectAttributes (&attr, &upath,
541 caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
543 get_nt_native_path (path, upath);
545 status = NtQueryAttributesFile (&attr, &fbi);
546 if (NT_SUCCESS (status))
547 return fbi.FileAttributes;
549 if (status != STATUS_OBJECT_NAME_NOT_FOUND
550 && status != STATUS_NO_SUCH_FILE) /* File not found on 9x share */
552 /* File exists but access denied. Try to get attribute through
554 UNICODE_STRING dirname, basename;
556 FILE_DIRECTORY_INFORMATION fdi;
558 RtlSplitUnicodePath (&upath, &dirname, &basename);
559 InitializeObjectAttributes (&attr, &dirname,
560 caseinsensitive ? OBJ_CASE_INSENSITIVE : 0,
562 status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
563 &attr, &io, FILE_SHARE_VALID_FLAGS,
564 FILE_SYNCHRONOUS_IO_NONALERT
565 | FILE_OPEN_FOR_BACKUP_INTENT
566 | FILE_DIRECTORY_FILE);
567 if (NT_SUCCESS (status))
569 status = NtQueryDirectoryFile (dir, NULL, NULL, 0, &io,
571 FileDirectoryInformation,
572 TRUE, &basename, TRUE);
574 if (NT_SUCCESS (status) || status == STATUS_BUFFER_OVERFLOW)
575 return fdi.FileAttributes;
578 SetLastError (RtlNtStatusToDosError (status));
579 return INVALID_FILE_ATTRIBUTES;
582 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
583 passing to Win32 API routines.
585 If an error occurs, `error' is set to the errno value.
586 Otherwise it is set to 0.
589 SYMLINK_FOLLOW - convert to PATH symlink points to
590 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
591 SYMLINK_IGNORE - do not check PATH for symlinks
592 SYMLINK_CONTENTS - just return symlink contents
595 /* TODO: This implementation is only preliminary. For internal
596 purposes it's necessary to have a path_conv::check function which
597 takes a UNICODE_STRING src path, otherwise we waste a lot of time
598 for converting back and forth. The below implementation does
599 realy nothing but converting to char *, until path_conv handles
600 wide-char paths directly. */
602 path_conv::check (const UNICODE_STRING *src, unsigned opt,
603 const suffix_info *suffixes)
606 char *path = tp.c_get ();
608 user_shared->warned_msdos = true;
609 sys_wcstombs (path, NT_MAX_PATH, src->Buffer, src->Length / sizeof (WCHAR));
610 path_conv::check (path, opt, suffixes);
614 path_conv::check (const char *src, unsigned opt,
615 const suffix_info *suffixes)
617 /* The tmp_buf array is used when expanding symlinks. It is NT_MAX_PATH * 2
618 in length so that we can hold the expanded symlink plus a trailer. */
620 char *path_copy = tp.c_get ();
621 char *pathbuf = tp.c_get ();
622 char *tmp_buf = tp.t_get ();
623 char *THIS_path = tp.c_get ();
625 bool need_directory = 0;
626 bool saw_symlinks = 0;
627 bool add_ext = false;
629 char *tail, *path_end;
632 static path_conv last_path_conv;
633 static char last_src[CYG_MAX_PATH];
635 if (*last_src && strcmp (last_src, src) == 0)
637 *this = last_path_conv;
643 if (efault.faulted ())
651 fileattr = INVALID_FILE_ATTRIBUTES;
652 caseinsensitive = OBJ_CASE_INSENSITIVE;
658 cfree (modifiable_path ());
661 memset (&dev, 0, sizeof (dev));
665 cfree ((void *) normalized_path);
666 normalized_path = NULL;
668 int component = 0; // Number of translated components
670 if (!(opt & PC_NULLEMPTY))
678 bool is_msdos = false;
679 /* This loop handles symlink expansion. */
685 is_relpath = !isabspath (src);
686 error = normalize_posix_path (src, path_copy, tail);
696 /* Detect if the user was looking for a directory. We have to strip the
697 trailing slash initially while trying to add extensions but take it
698 into account during processing */
699 if (tail > path_copy + 2 && isslash (tail[-1]))
706 /* Scan path_copy from right to left looking either for a symlink
707 or an actual existing file. If an existing file is found, just
708 return. If a symlink is found, exit the for loop.
709 Also: be careful to preserve the errno returned from
710 symlink.check as the caller may need it. */
711 /* FIXME: Do we have to worry about multiple \'s here? */
712 component = 0; // Number of translated components
713 sym.contents[0] = '\0';
717 for (unsigned pflags_or = opt & PC_NO_ACCESS_CHECK; ; pflags_or = 0)
719 const suffix_info *suff;
722 /* Don't allow symlink.check to set anything in the path_conv
723 class if we're working on an inner component of the path */
733 sym.pflags = path_flags;
734 full_path = THIS_path;
737 /* Convert to native path spec sans symbolic link info. */
738 error = mount_table->conv_to_win32_path (path_copy, full_path, dev,
744 sym.pflags |= pflags_or;
746 if (dev.major == DEV_CYGDRIVE_MAJOR)
749 fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY;
752 fileattr = getfileattr (THIS_path,
753 sym.pflags & MOUNT_NOPOSIX);
758 else if (dev == FH_DEV)
762 fileattr = getfileattr (THIS_path, sym.pflags & MOUNT_NOPOSIX);
763 if (!component && fileattr == INVALID_FILE_ATTRIBUTES)
765 fileattr = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY;
770 else if (isvirtual_dev (dev.devn))
772 /* FIXME: Calling build_fhandler here is not the right way to handle this. */
773 fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy);
774 int file_type = fh->exists ();
778 symlen = sym.set (fh->get_filebuf ());
786 fileattr = FILE_ATTRIBUTE_DIRECTORY;
792 case -2: /* /proc/self or /proc/<pid>/symlinks */
793 goto is_virtual_symlink;
794 case -3: /* /proc/<pid>/fd/pipe:[] */
801 case -4: /* /proc/<pid>/fd/socket:[] */
810 fileattr = INVALID_FILE_ATTRIBUTES;
811 goto virtual_component_retry;
813 if (component == 0 || dev.devn != FH_NETDRIVE)
814 path_flags |= PATH_RO;
817 /* devn should not be a device. If it is, then stop parsing now. */
818 else if (dev.devn != FH_FS)
821 path_flags = sym.pflags;
827 goto out; /* Found a device. Stop parsing. */
830 /* If path is only a drivename, Windows interprets it as the
831 current working directory on this drive instead of the root
832 dir which is what we want. So we need the trailing backslash
834 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
840 symlen = sym.check (full_path, suff, opt, fs);
846 dev.parse (sym.major, sym.minor);
849 fileattr = sym.fileattr;
853 if (sym.pflags & PATH_SOCKET)
860 fileattr = sym.fileattr;
868 fileattr = sym.fileattr;
869 path_flags = sym.pflags;
870 /* If the OS is caseinsensitive or the FS is caseinsensitive or
871 the incoming path was given in DOS notation, don't handle
872 path casesensitive. */
873 if (cygwin_shared->obcaseinsensitive || fs.caseinsensitive ()
875 path_flags |= PATH_NOPOSIX;
876 caseinsensitive = (path_flags & PATH_NOPOSIX)
877 ? OBJ_CASE_INSENSITIVE : 0;
880 /* If symlink.check found an existing non-symlink file, then
881 it sets the appropriate flag. It also sets any suffix found
883 if (!sym.issymlink && sym.fileattr != INVALID_FILE_ATTRIBUTES)
888 else if (!(sym.fileattr & FILE_ATTRIBUTE_DIRECTORY))
893 goto out; // file found
895 /* Found a symlink if symlen > 0. If component == 0, then the
896 src path itself was a symlink. If !follow_mode then
897 we're done. Otherwise we have to insert the path found
898 into the full path that we are building and perform all of
899 these operations again on the newly derived path. */
903 if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW))
905 set_symlink (symlen); // last component of path is a symlink.
906 if (opt & PC_SYM_CONTENTS)
908 strcpy (THIS_path, sym.contents);
917 else if (sym.error && sym.error != ENOENT)
922 /* No existing file found. */
924 virtual_component_retry:
925 /* Find the new "tail" of the path, e.g. in '/for/bar/baz',
927 if (tail != path_end)
929 while (--tail > path_copy + 1 && *tail != '/') {}
930 /* Exit loop if there is no tail or we are at the
931 beginning of a UNC path */
932 if (tail <= path_copy + 1)
933 goto out; // all done
935 /* Haven't found an existing pathname component yet.
936 Pinch off the tail and try again. */
941 /* Arrive here if above loop detected a symlink. */
942 if (++loop > SYMLOOP_MAX)
944 error = ELOOP; // Eep.
951 /* Place the link content, possibly with head and/or tail, in tmp_buf */
954 if (isabspath (sym.contents))
955 headptr = tmp_buf; /* absolute path */
958 /* Copy the first part of the path (with ending /) and point to the end. */
959 char *prevtail = tail;
960 while (--prevtail > path_copy && *prevtail != '/') {}
961 int headlen = prevtail - path_copy + 1;;
962 memcpy (tmp_buf, path_copy, headlen);
963 headptr = &tmp_buf[headlen];
966 /* Make sure there is enough space */
967 if (headptr + symlen >= tmp_buf + (2 * NT_MAX_PATH))
970 error = ENAMETOOLONG;
971 set_path ("::ENAMETOOLONG::");
975 /* Copy the symlink contents to the end of tmp_buf.
977 for (char *p = sym.contents; *p; p++)
978 *headptr++ = *p == '\\' ? '/' : *p;
981 /* Copy any tail component (with the 0) */
982 if (tail++ < path_end)
984 /* Add a slash if needed. There is space. */
985 if (*(headptr - 1) != '/')
987 int taillen = path_end - tail + 1;
988 if (headptr + taillen > tmp_buf + (2 * NT_MAX_PATH))
990 memcpy (headptr, tail, taillen);
993 /* Evaluate everything all over again. */
997 if (!(opt & PC_SYM_CONTENTS))
1001 set_path (THIS_path);
1003 add_ext_from_sym (sym);
1004 if (dev.devn == FH_NETDRIVE && component)
1006 /* This case indicates a non-existant resp. a non-retrievable
1007 share. This happens for instance if the share is a printer.
1008 In this case the path must not be treated like a FH_NETDRIVE,
1009 but like a FH_FS instead, so the usual open call for files
1013 else if (isvirtual_dev (dev.devn) && fileattr == INVALID_FILE_ATTRIBUTES)
1018 else if (!need_directory || error)
1019 /* nothing to do */;
1020 else if (fileattr == INVALID_FILE_ATTRIBUTES)
1021 strcat (modifiable_path (), "\\"); /* Reattach trailing dirsep in native path. */
1022 else if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
1023 path_flags &= ~PATH_SYMLINK;
1026 debug_printf ("%s is a non-directory", path);
1033 if (strncmp (path, "\\\\.\\", 4))
1035 if (!tail || tail == path)
1037 else if (tail[-1] != '\\')
1046 /* FS has been checked already for existing files. */
1047 if (exists () || fs.update (get_nt_native_path (), NULL))
1049 /* Incoming DOS paths are treated like DOS paths in native
1050 Windows applications. No ACLs, just default settings. */
1052 fs.has_acls (false);
1053 debug_printf ("this->path(%s), has_acls(%d)", path, fs.has_acls ());
1054 /* CV: We could use this->has_acls() but I want to make sure that
1055 we don't forget that the PATH_NOACL flag must be taken into
1057 if (!(path_flags & PATH_NOACL) && fs.has_acls ())
1058 set_exec (0); /* We really don't know if this is executable or not here
1059 but set it to not executable since it will be figured out
1060 later by anything which cares about this. */
1062 if (exec_state () != dont_know_if_executable)
1066 else if (issymlink () || issocket ())
1070 if (opt & PC_NOFULL)
1074 mkrelpath (this->modifiable_path (), !!caseinsensitive);
1075 /* Invalidate wide_path so that wide relpath can be created
1076 in later calls to get_nt_native_path or get_wide_win32_path. */
1083 size_t n = strlen (this->path);
1084 /* Do not add trailing \ to UNC device names like \\.\a: */
1085 if (this->path[n - 1] != '\\' &&
1086 (strncmp (this->path, "\\\\.\\", 4) != 0))
1088 this->modifiable_path ()[n] = '\\';
1089 this->modifiable_path ()[n + 1] = '\0';
1095 set_has_symlinks ();
1097 if ((opt & PC_POSIX))
1099 if (tail < path_end && tail > path_copy + 1)
1101 set_normalized_path (path_copy);
1102 if (is_msdos && !(opt & PC_NOWARN))
1109 last_path_conv = *this;
1110 strcpy (last_src, src);
1115 path_conv::~path_conv ()
1117 if (normalized_path)
1119 cfree ((void *) normalized_path);
1120 normalized_path = NULL;
1124 cfree (modifiable_path ());
1135 path_conv::is_binary ()
1138 PWCHAR bintest = tp.w_get ();
1141 return GetBinaryTypeW (get_wide_win32_path (bintest), &bin)
1142 && (bin == SCS_32BIT_BINARY || bin == SCS_64BIT_BINARY);
1145 /* Normalize a Win32 path.
1146 /'s are converted to \'s in the process.
1147 All duplicate \'s, except for 2 leading \'s, are deleted.
1149 The result is 0 for success, or an errno error value.
1150 FIXME: A lot of this should be mergeable with the POSIX critter. */
1152 normalize_win32_path (const char *src, char *dst, char *&tail)
1154 const char *src_start = src;
1155 bool beg_src_slash = isdirsep (src[0]);
1158 /* Skip long path name prefixes in Win32 or NT syntax. */
1159 if (beg_src_slash && (src[1] == '?' || isdirsep (src[1]))
1160 && src[2] == '?' && isdirsep (src[3]))
1163 if (src[1] != ':') /* native UNC path */
1164 src += 2; /* Fortunately the first char is not copied... */
1166 beg_src_slash = false;
1168 if (beg_src_slash && isdirsep (src[1]))
1170 if (isdirsep (src[2]))
1172 /* More than two slashes are just folded into one. */
1174 while (isdirsep (src[1]))
1179 /* Two slashes start a network or device path. */
1182 if (src[1] == '.' && isdirsep (src[2]))
1193 /* Always convert drive letter to uppercase for case sensitivity. */
1194 *tail++ = cyg_toupper (*src++);
1195 else if (*src != '/')
1198 tail += cygheap->cwd.get_drive (dst);
1199 else if (!cygheap->cwd.get (dst, 0))
1200 return get_errno ();
1203 tail = strchr (tail, '\0');
1204 if (tail[-1] != '\\')
1212 /* Strip duplicate /'s. */
1213 if (isdirsep (src[0]) && isdirsep (src[1]))
1216 else if (src[0] == '.' && isdirsep (src[1])
1217 && (src == src_start || isdirsep (src[-1])))
1220 /* Backup if "..". */
1221 else if (src[0] == '.' && src[1] == '.'
1222 /* dst must be greater than dst_start */
1223 && tail[-1] == '\\')
1225 if (!isdirsep (src[2]) && src[2] != '\0')
1229 /* Back up over /, but not if it's the first one. */
1232 /* Now back up to the next /. */
1233 while (tail > dst + 1 && tail[-1] != '\\' && tail[-2] != ':')
1236 if (isdirsep (*src))
1240 /* Otherwise, add char to result. */
1249 if ((tail - dst) >= NT_MAX_PATH)
1250 return ENAMETOOLONG;
1252 if (tail > dst + 1 && tail[-1] == '.' && tail[-2] == '\\')
1255 debug_printf ("%s = normalize_win32_path (%s)", dst, src_start);
1259 /* Various utilities. */
1261 /* nofinalslash: Remove trailing / and \ from SRC (except for the
1262 first one). It is ok for src == dst. */
1265 nofinalslash (const char *src, char *dst)
1267 int len = strlen (src);
1269 memcpy (dst, src, len + 1);
1270 while (len > 1 && isdirsep (dst[--len]))
1274 /* conv_path_list: Convert a list of path names to/from Win32/POSIX. */
1277 conv_path_list (const char *src, char *dst, size_t size, int to_posix)
1280 char src_delim, dst_delim;
1281 cygwin_conv_path_t conv_fn;
1288 conv_fn = CCP_WIN_A_TO_POSIX | CCP_RELATIVE;
1294 conv_fn = CCP_POSIX_TO_WIN_A | CCP_RELATIVE;
1298 len = strlen (src) + 1;
1299 if (len <= NT_MAX_PATH * sizeof (WCHAR))
1300 srcbuf = (char *) tp.w_get ();
1302 srcbuf = (char *) alloca (len);
1306 bool saw_empty = false;
1309 char *s = strccpy (srcbuf, &src, src_delim);
1310 size_t len = s - srcbuf;
1311 if (len >= NT_MAX_PATH)
1319 err = cygwin_conv_path (conv_fn, srcbuf, d, size - (d - dst));
1324 err = cygwin_conv_path (conv_fn, ".", d, size - (d - dst));
1328 if (to_posix == ENV_CVT)
1334 d = strchr (d, '\0');
1348 /********************** Symbolic Link Support **************************/
1350 /* Create a symlink from FROMPATH to TOPATH. */
1352 /* If TRUE create symlinks as Windows shortcuts, if false create symlinks
1353 as normal files with magic number and system bit set. */
1354 bool allow_winsymlinks = false;
1357 symlink (const char *oldpath, const char *newpath)
1359 return symlink_worker (oldpath, newpath, allow_winsymlinks, false);
1363 symlink_worker (const char *oldpath, const char *newpath, bool use_winsym,
1368 path_conv win32_newpath, win32_oldpath;
1370 SECURITY_ATTRIBUTES sa = sec_none_nih;
1371 security_descriptor sd;
1372 OBJECT_ATTRIBUTES attr;
1378 bool mk_winsym = use_winsym;
1380 /* POSIX says that empty 'newpath' is invalid input while empty
1381 'oldpath' is valid -- it's symlink resolver job to verify if
1382 symlink contents point to existing filesystem object */
1384 if (efault.faulted (EFAULT))
1386 if (!*oldpath || !*newpath)
1392 if (strlen (oldpath) > SYMLINK_MAX)
1394 set_errno (ENAMETOOLONG);
1398 len = strlen (newpath);
1399 /* Trailing dirsep is a no-no. */
1400 if (isdirsep (newpath[len - 1]))
1406 check_opt = PC_SYM_NOFOLLOW | PC_POSIX | (isdevice ? PC_NOWARN : 0);
1407 /* We need the normalized full path below. */
1408 win32_newpath.check (newpath, check_opt, stat_suffixes);
1409 /* MVFS doesn't handle the SYSTEM DOS attribute, but it handles the R/O
1410 attribute. Therefore we create symlinks on MVFS always as shortcuts. */
1411 mk_winsym |= win32_newpath.fs_is_mvfs ();
1413 if (mk_winsym && !win32_newpath.exists ()
1414 && (isdevice || !win32_newpath.fs_is_nfs ()))
1416 char *newplnk = tp.c_get ();
1417 stpcpy (stpcpy (newplnk, newpath), ".lnk");
1418 win32_newpath.check (newplnk, check_opt);
1421 if (win32_newpath.error)
1423 set_errno (win32_newpath.error);
1427 syscall_printf ("symlink (%s, %S)", oldpath,
1428 win32_newpath.get_nt_native_path ());
1430 if ((!isdevice && win32_newpath.exists ())
1431 || win32_newpath.is_auto_device ())
1437 if (!isdevice && win32_newpath.fs_is_nfs ())
1439 /* On NFS, create symlinks by calling NtCreateFile with an EA of type
1440 NfsSymlinkTargetName containing ... the symlink target name. */
1441 PFILE_FULL_EA_INFORMATION pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1442 pffei->NextEntryOffset = 0;
1444 pffei->EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1445 char *EaValue = stpcpy (pffei->EaName, NFS_SYML_TARGET) + 1;
1446 pffei->EaValueLength = sizeof (WCHAR) *
1447 (sys_mbstowcs ((PWCHAR) EaValue, NT_MAX_PATH, oldpath) - 1);
1448 status = NtCreateFile (&fh, FILE_WRITE_DATA | FILE_WRITE_EA | SYNCHRONIZE,
1449 win32_newpath.get_object_attr (attr, sa),
1450 &io, NULL, FILE_ATTRIBUTE_SYSTEM,
1451 FILE_SHARE_VALID_FLAGS, FILE_CREATE,
1452 FILE_SYNCHRONOUS_IO_NONALERT
1453 | FILE_OPEN_FOR_BACKUP_INTENT,
1454 pffei, NT_MAX_PATH * sizeof (WCHAR));
1455 if (!NT_SUCCESS (status))
1457 __seterrno_from_nt_status (status);
1467 ITEMIDLIST *pidl = NULL;
1468 size_t full_len = 0;
1469 unsigned short oldpath_len, desc_len, relpath_len, pidl_len = 0;
1470 char desc[MAX_PATH + 1], *relpath;
1474 /* First create an IDLIST to learn how big our shortcut is
1478 /* The symlink target is relative to the directory in which
1479 the symlink gets created, not relative to the cwd. Therefore
1480 we have to mangle the path quite a bit before calling path_conv. */
1481 if (isabspath (oldpath))
1482 win32_oldpath.check (oldpath,
1487 len = strrchr (win32_newpath.normalized_path, '/')
1488 - win32_newpath.normalized_path + 1;
1489 char *absoldpath = tp.t_get ();
1490 stpcpy (stpncpy (absoldpath, win32_newpath.normalized_path, len),
1492 win32_oldpath.check (absoldpath, PC_SYM_NOFOLLOW, stat_suffixes);
1494 if (SUCCEEDED (SHGetDesktopFolder (&psl)))
1496 WCHAR wc_path[win32_oldpath.get_wide_win32_path_len () + 1];
1497 win32_oldpath.get_wide_win32_path (wc_path);
1498 /* Amazing but true: Even though the ParseDisplayName method
1499 takes a wide char path name, it does not understand the
1500 Win32 prefix for long pathnames! So we have to tack off
1501 the prefix and convert the path to the "normal" syntax
1502 for ParseDisplayName. */
1503 WCHAR *wc = wc_path + 4;
1504 if (wc[1] != L':') /* native UNC path */
1507 if (SUCCEEDED (res = psl->ParseDisplayName (NULL, NULL, wc, NULL,
1512 for (p = pidl; p->mkid.cb > 0;
1513 p = (ITEMIDLIST *)((char *) p + p->mkid.cb))
1515 pidl_len = (char *) p - (char *) pidl + 2;
1520 /* Compute size of shortcut file. */
1521 full_len = sizeof (win_shortcut_hdr);
1523 full_len += sizeof (unsigned short) + pidl_len;
1524 oldpath_len = strlen (oldpath);
1525 /* Unfortunately the length of the description is restricted to a
1526 length of MAX_PATH up to NT4, and to a length of 2000 bytes
1527 since W2K. We don't want to add considerations for the different
1528 lengths and even 2000 bytes is not enough for long path names.
1529 So what we do here is to set the description to the POSIX path
1530 only if the path is not longer than MAX_PATH characters. We
1531 append the full path name after the regular shortcut data
1532 (see below), which works fine with Windows Explorer as well
1533 as older Cygwin versions (as long as the whole file isn't bigger
1534 than 8K). The description field is only used for backward
1535 compatibility to older Cygwin versions and those versions are
1536 not capable of handling long path names anyway. */
1537 desc_len = stpcpy (desc, oldpath_len > MAX_PATH
1538 ? "[path too long]" : oldpath) - desc;
1539 full_len += sizeof (unsigned short) + desc_len;
1540 /* Devices get the oldpath string unchanged as relative path. */
1543 relpath_len = oldpath_len;
1544 stpcpy (relpath = tp.c_get (), oldpath);
1548 relpath_len = strlen (win32_oldpath.get_win32 ());
1549 stpcpy (relpath = tp.c_get (), win32_oldpath.get_win32 ());
1551 full_len += sizeof (unsigned short) + relpath_len;
1552 full_len += sizeof (unsigned short) + oldpath_len;
1553 /* 1 byte more for trailing 0 written by stpcpy. */
1554 if (full_len < NT_MAX_PATH * sizeof (WCHAR))
1555 buf = (char *) tp.w_get ();
1557 buf = (char *) alloca (full_len + 1);
1559 /* Create shortcut header */
1560 win_shortcut_hdr *shortcut_header = (win_shortcut_hdr *) buf;
1561 memset (shortcut_header, 0, sizeof *shortcut_header);
1562 shortcut_header->size = sizeof *shortcut_header;
1563 shortcut_header->magic = GUID_shortcut;
1564 shortcut_header->flags = (WSH_FLAG_DESC | WSH_FLAG_RELPATH);
1566 shortcut_header->flags |= WSH_FLAG_IDLIST;
1567 shortcut_header->run = SW_NORMAL;
1568 cp = buf + sizeof (win_shortcut_hdr);
1573 *(unsigned short *)cp = pidl_len;
1574 memcpy (cp += 2, pidl, pidl_len);
1576 CoTaskMemFree (pidl);
1579 /* Create description */
1580 *(unsigned short *)cp = desc_len;
1581 cp = stpcpy (cp += 2, desc);
1583 /* Create relpath */
1584 *(unsigned short *)cp = relpath_len;
1585 cp = stpcpy (cp += 2, relpath);
1587 /* Append the POSIX path after the regular shortcut data for
1588 the long path support. */
1589 unsigned short *plen = (unsigned short *) cp;
1591 *(PWCHAR) cp = 0xfeff; /* BOM */
1593 *plen = sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1598 /* Default technique creating a symlink. */
1599 buf = (char *) tp.w_get ();
1600 cp = stpcpy (buf, SYMLINK_COOKIE);
1601 *(PWCHAR) cp = 0xfeff; /* BOM */
1603 /* Note that the terminating nul is written. */
1604 cp += sys_mbstowcs ((PWCHAR) cp, NT_MAX_PATH, oldpath) * sizeof (WCHAR);
1607 if (isdevice && win32_newpath.exists ())
1609 status = NtOpenFile (&fh, FILE_WRITE_ATTRIBUTES,
1610 win32_newpath.get_object_attr (attr, sa),
1611 &io, 0, FILE_OPEN_FOR_BACKUP_INTENT);
1612 if (!NT_SUCCESS (status))
1614 __seterrno_from_nt_status (status);
1617 status = NtSetAttributesFile (fh, FILE_ATTRIBUTE_NORMAL);
1619 if (!NT_SUCCESS (status))
1621 __seterrno_from_nt_status (status);
1625 /* See comments in fhander_base::open () for an explanation why we defer
1626 setting security attributes on remote files. */
1627 if (win32_newpath.has_acls () && !win32_newpath.isremote ())
1628 set_security_attribute (win32_newpath, S_IFLNK | STD_RBITS | STD_WBITS,
1630 status = NtCreateFile (&fh, DELETE | FILE_GENERIC_WRITE,
1631 win32_newpath.get_object_attr (attr, sa),
1632 &io, NULL, FILE_ATTRIBUTE_NORMAL,
1633 FILE_SHARE_VALID_FLAGS,
1634 isdevice ? FILE_OVERWRITE_IF : FILE_CREATE,
1635 FILE_SYNCHRONOUS_IO_NONALERT
1636 | FILE_NON_DIRECTORY_FILE
1637 | FILE_OPEN_FOR_BACKUP_INTENT,
1639 if (!NT_SUCCESS (status))
1641 __seterrno_from_nt_status (status);
1644 if (win32_newpath.has_acls () && win32_newpath.isremote ())
1645 set_file_attribute (fh, win32_newpath, ILLEGAL_UID, ILLEGAL_GID,
1646 S_IFLNK | STD_RBITS | STD_WBITS);
1647 status = NtWriteFile (fh, NULL, NULL, NULL, &io, buf, cp - buf, NULL, NULL);
1648 if (NT_SUCCESS (status) && io.Information == (ULONG) (cp - buf))
1650 status = NtSetAttributesFile (fh, mk_winsym ? FILE_ATTRIBUTE_READONLY
1651 : FILE_ATTRIBUTE_SYSTEM);
1652 if (!NT_SUCCESS (status))
1653 debug_printf ("Setting attributes failed, status = %p", status);
1658 __seterrno_from_nt_status (status);
1659 FILE_DISPOSITION_INFORMATION fdi = { TRUE };
1660 status = NtSetInformationFile (fh, &io, &fdi, sizeof fdi,
1661 FileDispositionInformation);
1662 if (!NT_SUCCESS (status))
1663 debug_printf ("Setting delete dispostion failed, status = %p", status);
1668 syscall_printf ("%d = symlink_worker (%s, %s, %d, %d)", res, oldpath,
1669 newpath, mk_winsym, isdevice);
1674 cmp_shortcut_header (win_shortcut_hdr *file_header)
1676 /* A Cygwin or U/Win shortcut only contains a description and a relpath.
1677 Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
1678 always set to SW_NORMAL. */
1679 return file_header->size == sizeof (win_shortcut_hdr)
1680 && !memcmp (&file_header->magic, &GUID_shortcut, sizeof GUID_shortcut)
1681 && (file_header->flags & ~WSH_FLAG_IDLIST)
1682 == (WSH_FLAG_DESC | WSH_FLAG_RELPATH)
1683 && file_header->run == SW_NORMAL;
1687 symlink_info::check_shortcut (HANDLE in_h)
1690 win_shortcut_hdr *file_header;
1694 UNICODE_STRING same = { 0, 0, (PWCHAR) L"" };
1695 OBJECT_ATTRIBUTES attr;
1699 FILE_STANDARD_INFORMATION fsi;
1701 InitializeObjectAttributes (&attr, &same, 0, in_h, NULL);
1702 status = NtOpenFile (&h, FILE_READ_DATA | SYNCHRONIZE,
1703 &attr, &io, FILE_SHARE_VALID_FLAGS,
1704 FILE_OPEN_FOR_BACKUP_INTENT
1705 | FILE_SYNCHRONOUS_IO_NONALERT);
1706 if (!NT_SUCCESS (status))
1708 status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi,
1709 FileStandardInformation);
1710 if (!NT_SUCCESS (status))
1715 if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr)
1716 || fsi.EndOfFile.QuadPart > 4 * 65536)
1718 if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR))
1719 buf = (char *) tp.w_get ();
1721 buf = (char *) alloca (fsi.EndOfFile.LowPart + 1);
1722 if (!NT_SUCCESS (NtReadFile (h, NULL, NULL, NULL,
1723 &io, buf, fsi.EndOfFile.LowPart, NULL, NULL)))
1728 file_header = (win_shortcut_hdr *) buf;
1729 if (io.Information != fsi.EndOfFile.LowPart
1730 || !cmp_shortcut_header (file_header))
1732 cp = buf + sizeof (win_shortcut_hdr);
1733 if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */
1734 cp += *(unsigned short *) cp + 2;
1735 if (!(len = *(unsigned short *) cp))
1738 /* Check if this is a device file - these start with the sequence :\\ */
1739 if (strncmp (cp, ":\\", 2) == 0)
1740 res = strlen (strcpy (contents, cp)); /* Don't mess with device files */
1743 /* Has appended full path? If so, use it instead of description. */
1744 unsigned short relpath_len = *(unsigned short *) (cp + len);
1745 if (cp + len + 2 + relpath_len < buf + fsi.EndOfFile.LowPart)
1747 cp += len + 2 + relpath_len;
1748 len = *(unsigned short *) cp;
1751 if (*(PWCHAR) cp == 0xfeff) /* BOM */
1753 char *tmpbuf = tp.c_get ();
1754 if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2))
1757 res = posixify (tmpbuf);
1759 else if (len > SYMLINK_MAX)
1764 res = posixify (cp);
1767 if (res) /* It's a symlink. */
1768 pflags = PATH_SYMLINK | PATH_LNK;
1776 symlink_info::check_sysfile (HANDLE in_h)
1779 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
1780 char *srcbuf = tp.c_get ();
1782 UNICODE_STRING same = { 0, 0, (PWCHAR) L"" };
1783 OBJECT_ATTRIBUTES attr;
1788 InitializeObjectAttributes (&attr, &same, 0, in_h, NULL);
1789 status = NtOpenFile (&h, FILE_READ_DATA | SYNCHRONIZE,
1790 &attr, &io, FILE_SHARE_VALID_FLAGS,
1791 FILE_OPEN_FOR_BACKUP_INTENT
1792 | FILE_SYNCHRONOUS_IO_NONALERT);
1793 if (!NT_SUCCESS (status))
1795 else if (!NT_SUCCESS (status = NtReadFile (h, NULL, NULL, NULL, &io,
1796 cookie_buf, sizeof (cookie_buf),
1799 debug_printf ("ReadFile1 failed");
1800 if (status != STATUS_END_OF_FILE)
1803 else if (io.Information == sizeof (cookie_buf)
1804 && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
1806 /* It's a symlink. */
1807 pflags = PATH_SYMLINK;
1809 status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf,
1810 NT_MAX_PATH, NULL, NULL);
1811 if (!NT_SUCCESS (status))
1813 debug_printf ("ReadFile2 failed");
1814 if (status != STATUS_END_OF_FILE)
1817 else if (*(PWCHAR) srcbuf == 0xfeff) /* BOM */
1819 char *tmpbuf = tp.c_get ();
1820 if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (srcbuf + 2))
1822 debug_printf ("symlink string too long");
1824 res = posixify (tmpbuf);
1826 else if (io.Information > SYMLINK_MAX + 1)
1827 debug_printf ("symlink string too long");
1829 res = posixify (srcbuf);
1831 else if (io.Information == sizeof (cookie_buf)
1832 && memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
1833 pflags |= PATH_SOCKET;
1839 symlink_info::check_reparse_point (HANDLE h)
1844 PREPARSE_DATA_BUFFER rp = (PREPARSE_DATA_BUFFER) tp.c_get ();
1845 char srcbuf[SYMLINK_MAX + 7];
1847 status = NtFsControlFile (h, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT,
1848 NULL, 0, (LPVOID) rp,
1849 MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1850 if (!NT_SUCCESS (status))
1852 debug_printf ("NtFsControlFile(FSCTL_GET_REPARSE_POINT) failed, %p",
1857 if (rp->ReparseTag == IO_REPARSE_TAG_SYMLINK)
1859 sys_wcstombs (srcbuf, SYMLINK_MAX + 1,
1860 (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer
1861 + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset),
1862 rp->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof (WCHAR));
1863 pflags = PATH_SYMLINK | PATH_REP;
1864 fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
1866 else if (rp->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
1868 if (rp->SymbolicLinkReparseBuffer.PrintNameLength == 0)
1870 /* Likely a volume mount point. Not treated as symlink. */
1873 sys_wcstombs (srcbuf, SYMLINK_MAX + 1,
1874 (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer
1875 + rp->MountPointReparseBuffer.SubstituteNameOffset),
1876 rp->MountPointReparseBuffer.SubstituteNameLength / sizeof (WCHAR));
1877 pflags = PATH_SYMLINK | PATH_REP;
1878 fileattr &= ~FILE_ATTRIBUTE_DIRECTORY;
1880 return posixify (srcbuf);
1884 symlink_info::check_nfs_symlink (HANDLE h)
1890 FILE_GET_EA_INFORMATION fgei;
1891 char buf[sizeof (NFS_SYML_TARGET)];
1893 PFILE_FULL_EA_INFORMATION pffei;
1896 /* To find out if the file is a symlink and to get the symlink target,
1897 try to fetch the NfsSymlinkTargetName EA. */
1898 fgei_buf.fgei.NextEntryOffset = 0;
1899 fgei_buf.fgei.EaNameLength = sizeof (NFS_SYML_TARGET) - 1;
1900 stpcpy (fgei_buf.fgei.EaName, NFS_SYML_TARGET);
1901 pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get ();
1902 status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE,
1903 &fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE);
1904 if (NT_SUCCESS (status) && pffei->EaValueLength > 0)
1906 PWCHAR spath = (PWCHAR)
1907 (pffei->EaName + pffei->EaNameLength + 1);
1908 res = sys_wcstombs (contents, SYMLINK_MAX + 1,
1909 spath, pffei->EaValueLength);
1910 pflags = PATH_SYMLINK;
1916 symlink_info::posixify (char *srcbuf)
1918 /* The definition for a path in a native symlink is a bit weird. The Flags
1919 value seem to contain 0 for absolute paths (stored as NT native path)
1920 and 1 for relative paths. Relative paths are paths not starting with a
1921 drive letter. These are not converted to NT native, but stored as
1922 given. A path starting with a single backslash is relative to the
1923 current drive thus a "relative" value (Flags == 1).
1924 Funny enough it's possible to store paths with slashes instead of
1925 backslashes, but they are evaluated incorrectly by subsequent Windows
1926 calls like CreateFile (ERROR_INVALID_NAME). So, what we do here is to
1927 take paths starting with slashes at face value, evaluating them as
1928 Cygwin specific POSIX paths.
1929 A path starting with two slashes(!) or backslashes is converted into an
1930 NT UNC path. Unfortunately, in contrast to POSIX rules, paths starting
1931 with three or more (back)slashes are also converted into UNC paths,
1932 just incorrectly sticking to one redundant leading backslashe. We go
1933 along with this behaviour to avoid scenarios in which native tools access
1934 other files than Cygwin.
1935 The above rules are used exactly the same way on Cygwin specific symlinks
1936 (sysfiles and shortcuts) to eliminate non-POSIX paths in the output. */
1938 /* Eliminate native NT prefixes. */
1939 if (srcbuf[0] == '\\' && !strncmp (srcbuf + 1, "??\\", 3))
1942 if (srcbuf[1] != ':') /* native UNC path */
1943 *(srcbuf += 2) = '\\';
1945 if (isdrive (srcbuf))
1946 mount_table->conv_to_posix_path (srcbuf, contents, 0);
1947 else if (srcbuf[0] == '\\')
1949 if (srcbuf[1] == '\\') /* UNC path */
1950 slashify (srcbuf, contents, 0);
1951 else /* Paths starting with \ are current drive relative. */
1953 char cvtbuf[SYMLINK_MAX + 1];
1955 stpcpy (cvtbuf + cygheap->cwd.get_drive (cvtbuf), srcbuf);
1956 mount_table->conv_to_posix_path (cvtbuf, contents, 0);
1959 else /* Everything else is taken as is. */
1960 slashify (srcbuf, contents, 0);
1961 return strlen (contents);
1970 SCAN_JUSTCHECKTHIS, /* Never try to append a suffix. */
1978 const suffix_info *suffixes, *suffixes_start;
1983 char *has (const char *, const suffix_info *);
1985 int lnk_match () {return nextstate >= SCAN_APPENDLNK;}
1989 suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
1991 nextstate = SCAN_BEG;
1992 suffixes = suffixes_start = in_suffixes;
1994 const char *fname = strrchr (in_path, '\\');
1995 fname = fname ? fname + 1 : in_path;
1996 char *ext_here = strrchr (fname, '.');
1998 eopath = strchr (path, '\0');
2005 /* Check if the extension matches a known extension */
2006 for (const suffix_info *ex = in_suffixes; ex->name != NULL; ex++)
2007 if (ascii_strcasematch (ext_here, ex->name))
2009 nextstate = SCAN_JUSTCHECK;
2010 suffixes = NULL; /* Has an extension so don't scan for one. */
2015 /* Didn't match. Use last resort -- .lnk. */
2016 if (ascii_strcasematch (ext_here, ".lnk"))
2018 nextstate = SCAN_HASLNK;
2026 /* Avoid attaching suffixes if the resulting filename would be invalid. */
2027 if (eopath - fname > NAME_MAX - 4)
2029 nextstate = SCAN_JUSTCHECKTHIS;
2036 suffix_scan::next ()
2044 suffixes = suffixes_start;
2047 nextstate = SCAN_LNK;
2050 nextstate = SCAN_EXTRALNK;
2051 /* fall through to suffix checking below */
2054 nextstate = SCAN_APPENDLNK; /* Skip SCAN_BEG */
2057 nextstate = SCAN_DONE;
2060 case SCAN_JUSTCHECK:
2061 nextstate = SCAN_LNK;
2063 case SCAN_JUSTCHECKTHIS:
2064 nextstate = SCAN_DONE;
2067 case SCAN_APPENDLNK:
2068 strcat (eopath, ".lnk");
2069 nextstate = SCAN_DONE;
2076 while (suffixes && suffixes->name)
2077 if (nextstate == SCAN_EXTRALNK && !suffixes->addon)
2081 strcpy (eopath, suffixes->name);
2082 if (nextstate == SCAN_EXTRALNK)
2083 strcat (eopath, ".lnk");
2092 symlink_info::set_error (int in_errno)
2095 if (!(pflags & PATH_NO_ACCESS_CHECK) || in_errno == ENAMETOOLONG || in_errno == EIO)
2100 else if (in_errno == ENOENT)
2104 fileattr = FILE_ATTRIBUTE_NORMAL;
2111 symlink_info::parse_device (const char *contents)
2118 mymajor = strtol (contents += 2, &endptr, 16);
2119 if (endptr == contents)
2120 return isdevice = false;
2123 myminor = strtol (++contents, &endptr, 16);
2124 if (endptr == contents)
2125 return isdevice = false;
2128 mymode = strtol (++contents, &endptr, 16);
2129 if (endptr == contents)
2130 return isdevice = false;
2132 if ((mymode & S_IFMT) == S_IFIFO)
2134 mymajor = _major (FH_FIFO);
2135 myminor = _minor (FH_FIFO);
2141 return isdevice = true;
2144 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2146 If PATH is a symlink, put the value of the symlink--the file to
2147 which it points--into BUF. The value stored in BUF is not
2148 necessarily null terminated. BUFLEN is the length of BUF; only up
2149 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2150 which case nothing will be stored.
2152 Set *SYML if PATH is a symlink.
2154 Set *EXEC if PATH appears to be executable. This is an efficiency
2155 hack because we sometimes have to open the file anyhow. *EXEC will
2156 not be set for every executable file.
2158 Return -1 on error, 0 if PATH is not a symlink, or the length
2159 stored into BUF if PATH is a symlink. */
2162 symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt,
2172 ext_here = suffix.has (path, suffixes);
2173 extn = ext_here - path;
2177 pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
2178 ULONG ci_flag = cygwin_shared->obcaseinsensitive || (pflags & PATH_NOPOSIX)
2179 ? OBJ_CASE_INSENSITIVE : 0;
2181 /* TODO: Temporarily do all char->UNICODE conversion here. This should
2182 already be slightly faster than using Ascii functions. */
2184 UNICODE_STRING upath;
2185 OBJECT_ATTRIBUTES attr;
2187 InitializeObjectAttributes (&attr, &upath, ci_flag, NULL, NULL);
2189 PVOID eabuf = &nfs_aol_ffei;
2190 ULONG easize = sizeof nfs_aol_ffei;
2192 while (suffix.next ())
2194 FILE_BASIC_INFORMATION fbi;
2198 bool fs_update_called = false;
2201 get_nt_native_path (suffix.path, upath);
2207 /* The EA given to NtCreateFile allows to get a handle to a symlink on
2208 an NFS share, rather than getting a handle to the target of the
2209 symlink (which would spoil the task of this method quite a bit).
2210 Fortunately it's ignored on most other file systems so we don't have
2211 to special case NFS too much. */
2212 status = NtCreateFile (&h,
2213 READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_EA,
2214 &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS,
2216 FILE_OPEN_REPARSE_POINT
2217 | FILE_OPEN_FOR_BACKUP_INTENT,
2219 /* No right to access EAs or EAs not supported? */
2220 if (status == STATUS_ACCESS_DENIED || status == STATUS_EAS_NOT_SUPPORTED
2221 || status == STATUS_NOT_SUPPORTED
2222 /* Or a bug in Samba 3.2.x (x <= 7) when accessing a share's root dir
2223 which has EAs enabled? */
2224 || status == STATUS_INVALID_PARAMETER)
2227 /* If EAs are not supported, there's no sense to check them again
2228 with suffixes attached. So we set eabuf/easize to 0 here once. */
2229 if (status == STATUS_EAS_NOT_SUPPORTED
2230 || status == STATUS_NOT_SUPPORTED)
2235 status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2236 &attr, &io, FILE_SHARE_VALID_FLAGS,
2237 FILE_OPEN_REPARSE_POINT
2238 | FILE_OPEN_FOR_BACKUP_INTENT);
2240 if (status == STATUS_OBJECT_NAME_NOT_FOUND && ci_flag == 0
2241 && wincap.has_broken_udf ())
2243 /* On NT 5.x UDF is broken (at least) in terms of case sensitivity.
2244 When trying to open a file case sensitive, the file appears to be
2245 non-existant. Another bug is described in fs_info::update. */
2246 attr.Attributes = OBJ_CASE_INSENSITIVE;
2247 status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
2248 &attr, &io, FILE_SHARE_VALID_FLAGS,
2249 FILE_OPEN_REPARSE_POINT
2250 | FILE_OPEN_FOR_BACKUP_INTENT);
2251 attr.Attributes = 0;
2252 if (NT_SUCCESS (status))
2254 fs.update (&upath, h);
2256 fs_update_called = true;
2260 status = STATUS_OBJECT_NAME_NOT_FOUND;
2264 if (NT_SUCCESS (status)
2265 && NT_SUCCESS (status
2266 = NtQueryInformationFile (h, &io, &fbi, sizeof fbi,
2267 FileBasicInformation)))
2268 fileattr = fbi.FileAttributes;
2271 debug_printf ("%p = NtQueryInformationFile (%S)", status, &upath);
2273 fileattr = INVALID_FILE_ATTRIBUTES;
2275 /* One of the inner path components is invalid, or the path contains
2276 invalid characters. Bail out with ENOENT.
2278 Note that additional STATUS_OBJECT_PATH_INVALID and
2279 STATUS_OBJECT_PATH_SYNTAX_BAD status codes exist. The first one
2280 is seemingly not generated by NtQueryAttributesFile, the latter
2281 is only generated if the path is no absolute path within the
2282 NT name space, which should not happen and would point to an
2283 error in get_nt_native_path. Both status codes are deliberately
2284 not tested here unless proved necessary. */
2285 if (status == STATUS_OBJECT_PATH_NOT_FOUND
2286 || status == STATUS_OBJECT_NAME_INVALID
2287 || status == STATUS_NO_MEDIA_IN_DEVICE)
2290 goto file_not_symlink;
2292 if (status != STATUS_OBJECT_NAME_NOT_FOUND
2293 && status != STATUS_NO_SUCH_FILE) /* ENOENT on NFS or 9x share */
2295 /* The file exists, but the user can't access it for one reason
2296 or the other. To get the file attributes we try to access the
2297 information by opening the parent directory and getting the
2298 file attributes using a matching NtQueryDirectoryFile call. */
2299 UNICODE_STRING dirname, basename;
2300 OBJECT_ATTRIBUTES dattr;
2303 FILE_DIRECTORY_INFORMATION fdi;
2304 WCHAR dummy_buf[NAME_MAX + 1];
2307 RtlSplitUnicodePath (&upath, &dirname, &basename);
2308 InitializeObjectAttributes (&dattr, &dirname, ci_flag,
2310 status = NtOpenFile (&dir, SYNCHRONIZE | FILE_LIST_DIRECTORY,
2311 &dattr, &io, FILE_SHARE_VALID_FLAGS,
2312 FILE_SYNCHRONOUS_IO_NONALERT
2313 | FILE_OPEN_FOR_BACKUP_INTENT
2314 | FILE_DIRECTORY_FILE);
2315 if (!NT_SUCCESS (status))
2317 debug_printf ("%p = NtOpenFile(%S)", status, &dirname);
2322 status = NtQueryDirectoryFile (dir, NULL, NULL, NULL, &io,
2323 &fdi_buf, sizeof fdi_buf,
2324 FileDirectoryInformation,
2325 TRUE, &basename, TRUE);
2326 /* Take the opportunity to check file system while we're
2327 having the handle to the parent dir. */
2328 fs.update (&upath, h);
2330 if (!NT_SUCCESS (status))
2332 debug_printf ("%p = NtQueryDirectoryFile(%S)",
2334 if (status == STATUS_NO_SUCH_FILE)
2336 /* This can happen when trying to access files
2337 which match DOS device names on SMB shares.
2338 NtOpenFile failed with STATUS_ACCESS_DENIED,
2339 but the NtQueryDirectoryFile tells us the
2340 file doesn't exist. We're suspicious in this
2341 case and retry with the next suffix instead of
2349 fileattr = fdi_buf.fdi.FileAttributes;
2351 ext_tacked_on = !!*ext_here;
2352 goto file_not_symlink;
2358 /* Check file system while we're having the file open anyway.
2359 This speeds up path_conv noticably (~10%). */
2360 if (!fs_update_called)
2361 fs.update (&upath, h);
2363 ext_tacked_on = !!*ext_here;
2367 /* Windows shortcuts are potentially treated as symlinks. Valid Cygwin
2368 & U/WIN shortcuts are R/O, but definitely not directories. */
2369 if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY))
2370 == FILE_ATTRIBUTE_READONLY && suffix.lnk_match ())
2372 res = check_shortcut (h);
2375 /* If searching for `foo' and then finding a `foo.lnk' which is
2376 no shortcut, return the same as if file not found. */
2379 fileattr = INVALID_FILE_ATTRIBUTES;
2384 else if (contents[0] != ':' || contents[1] != '\\'
2385 || !parse_device (contents))
2389 /* If searching for `foo' and then finding a `foo.lnk' which is
2390 no shortcut, return the same as if file not found. */
2391 else if (suffix.lnk_match () && ext_tacked_on)
2393 fileattr = INVALID_FILE_ATTRIBUTES;
2398 /* Reparse points are potentially symlinks. This check must be
2399 performed before checking the SYSTEM attribute for sysfile
2400 symlinks, since reparse points can have this flag set, too.
2401 For instance, Vista starts to create a couple of reparse points
2402 with SYSTEM and HIDDEN flags set. */
2403 else if (fileattr & FILE_ATTRIBUTE_REPARSE_POINT)
2405 res = check_reparse_point (h);
2410 /* This is the old Cygwin method creating symlinks. A symlink will
2411 have the `system' file attribute. Only files can be symlinks
2412 (which can be symlinks to directories). */
2413 else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY))
2414 == FILE_ATTRIBUTE_SYSTEM)
2416 res = check_sysfile (h);
2421 /* If the file could be opened with FILE_READ_EA, and if it's on a
2422 NFS share, check if it's a symlink. Only files can be symlinks
2423 (which can be symlinks to directories). */
2424 else if (fs.is_nfs () && !no_ea && !(fileattr & FILE_ATTRIBUTE_DIRECTORY))
2426 res = check_nfs_symlink (h);
2434 syscall_printf ("%s", isdevice ? "is a device" : "not a symlink");
2442 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2443 res, suffix.path, contents, pflags);
2447 /* "path" is the path in a virtual symlink. Set a symlink_info struct from
2448 that and proceed with further path checking afterwards. */
2450 symlink_info::set (char *path)
2452 strcpy (contents, path);
2453 pflags = PATH_SYMLINK;
2454 fileattr = FILE_ATTRIBUTE_NORMAL;
2458 ext_tacked_on = false;
2460 extn = major = minor = mode = 0;
2461 return strlen (path);
2464 /* readlink system call */
2467 readlink (const char *path, char *buf, size_t buflen)
2471 set_errno (ENAMETOOLONG);
2475 path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2479 set_errno (pathbuf.error);
2480 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2484 if (!pathbuf.exists ())
2490 if (!pathbuf.issymlink ())
2492 if (pathbuf.exists ())
2497 ssize_t len = min (buflen, strlen (pathbuf.get_win32 ()));
2498 memcpy (buf, pathbuf.get_win32 (), len);
2500 /* errno set by symlink.check if error */
2504 /* Some programs rely on st_dev/st_ino being unique for each file.
2505 Hash the path name and hope for the best. The hash arg is not
2506 always initialized to zero since readdir needs to compute the
2507 dirent ino_t based on a combination of the hash of the directory
2508 done during the opendir call and the hash or the filename within
2509 the directory. FIXME: Not bullet-proof. */
2510 /* Cygwin internal */
2512 hash_path_name (__ino64_t hash, PUNICODE_STRING name)
2514 if (name->Length == 0)
2517 /* Build up hash. Name is already normalized */
2518 USHORT len = name->Length / sizeof (WCHAR);
2519 for (USHORT idx = 0; idx < len; ++idx)
2520 hash = RtlUpcaseUnicodeChar (name->Buffer[idx])
2521 + (hash << 6) + (hash << 16) - hash;
2526 hash_path_name (__ino64_t hash, PCWSTR name)
2528 UNICODE_STRING uname;
2529 RtlInitUnicodeString (&uname, name);
2530 return hash_path_name (hash, &uname);
2534 hash_path_name (__ino64_t hash, const char *name)
2536 UNICODE_STRING uname;
2537 RtlCreateUnicodeStringFromAsciiz (&uname, name);
2538 __ino64_t ret = hash_path_name (hash, &uname);
2539 RtlFreeUnicodeString (&uname);
2544 getcwd (char *buf, size_t ulen)
2548 if (efault.faulted (EFAULT))
2550 else if (ulen == 0 && buf)
2553 res = cygheap->cwd.get (buf, 1, 1, ulen);
2557 /* getwd: Legacy. */
2561 return getcwd (buf, PATH_MAX + 1); /*Per SuSv3!*/
2564 /* chdir: POSIX 5.2.1.1 */
2566 chdir (const char *in_dir)
2569 if (efault.faulted (EFAULT))
2577 syscall_printf ("dir '%s'", in_dir);
2579 /* Convert path. First argument ensures that we don't check for NULL/empty/invalid
2581 path_conv path (PC_NONULLEMPTY, in_dir, PC_SYM_FOLLOW | PC_POSIX);
2584 set_errno (path.error);
2585 syscall_printf ("-1 = chdir (%s)", in_dir);
2591 const char *posix_cwd = NULL;
2592 int devn = path.get_devn ();
2593 if (!path.exists ())
2595 else if (!path.isdir ())
2596 set_errno (ENOTDIR);
2597 else if (!isvirtual_dev (devn))
2599 /* The sequence chdir("xx"); chdir(".."); must be a noop if xx
2600 is not a symlink. This is exploited by find.exe.
2601 The posix_cwd is just path.normalized_path.
2602 In other cases we let cwd.set obtain the Posix path through
2604 if (!isdrive(path.normalized_path))
2605 posix_cwd = path.normalized_path;
2611 posix_cwd = path.normalized_path;
2616 res = cygheap->cwd.set (path.get_nt_native_path (), posix_cwd, doit);
2618 /* Note that we're accessing cwd.posix without a lock here. I didn't think
2619 it was worth locking just for strace. */
2620 syscall_printf ("%d = chdir() cygheap->cwd.posix '%s' native '%S'", res,
2621 cygheap->cwd.get_posix (), path.get_nt_native_path ());
2630 cygheap_fdget cfd (fd);
2632 res = chdir (cfd->get_name ());
2636 syscall_printf ("%d = fchdir (%d)", res, fd);
2640 /******************** Exported Path Routines *********************/
2642 /* Cover functions to the path conversion routines.
2643 These are exported to the world as cygwin_foo by cygwin.din. */
2645 #define return_with_errno(x) \
2655 cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to,
2660 if (efault.faulted (EFAULT))
2667 bool relative = !!(what & CCP_RELATIVE);
2668 what &= ~CCP_RELATIVE;
2672 case CCP_POSIX_TO_WIN_A:
2674 p.check ((const char *) from,
2675 PC_POSIX | PC_SYM_FOLLOW | PC_NO_ACCESS_CHECK | PC_NOWARN
2676 | (relative ? PC_NOFULL : 0));
2678 return_with_errno (p.error);
2679 PUNICODE_STRING up = p.get_nt_native_path ();
2681 sys_wcstombs (buf, NT_MAX_PATH, up->Buffer, up->Length / sizeof (WCHAR));
2682 /* Convert native path to standard DOS path. */
2683 if (!strncmp (buf, "\\??\\", 4))
2686 if (buf[1] != ':') /* native UNC path */
2689 lsiz = strlen (buf) + 1;
2692 case CCP_POSIX_TO_WIN_W:
2693 p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW
2694 | PC_NO_ACCESS_CHECK | PC_NOWARN
2695 | (relative ? PC_NOFULL : 0));
2697 return_with_errno (p.error);
2698 /* Relative Windows paths are always restricted to MAX_PATH chars. */
2699 if (relative && !isabspath (p.get_win32 ())
2700 && sys_mbstowcs (NULL, 0, p.get_win32 ()) > MAX_PATH)
2702 /* Recreate as absolute path. */
2703 p.check ((const char *) from, PC_POSIX | PC_SYM_FOLLOW
2704 | PC_NO_ACCESS_CHECK | PC_NOWARN);
2706 return_with_errno (p.error);
2708 lsiz = (p.get_wide_win32_path_len () + 1) * sizeof (WCHAR);
2710 case CCP_WIN_A_TO_POSIX:
2712 error = mount_table->conv_to_posix_path ((const char *) from, buf,
2715 return_with_errno (error);
2716 lsiz = strlen (buf) + 1;
2718 case CCP_WIN_W_TO_POSIX:
2720 error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf,
2723 return_with_errno (error);
2724 lsiz = strlen (buf) + 1;
2739 case CCP_POSIX_TO_WIN_A:
2740 case CCP_WIN_A_TO_POSIX:
2741 case CCP_WIN_W_TO_POSIX:
2742 strcpy ((char *) to, buf);
2744 case CCP_POSIX_TO_WIN_W:
2745 p.get_wide_win32_path ((PWCHAR) to);
2752 cygwin_create_path (cygwin_conv_path_t what, const void *from)
2755 ssize_t size = cygwin_conv_path (what, from, NULL, 0);
2758 if (!(to = malloc (size)))
2760 if (cygwin_conv_path (what, from, to, size) == -1)
2767 cygwin_conv_to_win32_path (const char *path, char *win32_path)
2769 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, path, win32_path,
2774 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
2776 return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path, win32_path,
2780 /* This is exported to the world as cygwin_foo by cygwin.din. */
2783 cygwin_conv_to_posix_path (const char *path, char *posix_path)
2785 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, path, posix_path,
2790 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
2792 return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, path, posix_path,
2796 /* The realpath function is supported on some UNIX systems. */
2799 realpath (const char *path, char *resolved)
2801 /* Make sure the right errno is returned if path is NULL. */
2808 /* Guard reading from a potentially invalid path and writing to a
2809 potentially invalid resolved. */
2812 if (efault.faulted (EFAULT))
2818 tpath = tp.c_get ();
2819 mount_table->cygdrive_posix_path (path, tpath, 0);
2822 tpath = (char *) path;
2824 path_conv real_path (tpath, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes);
2827 /* Linux has this funny non-standard extension. If "resolved" is NULL,
2828 realpath mallocs the space by itself and returns it to the application.
2829 The application is responsible for calling free() then. This extension
2830 is backed by POSIX, which allows implementation-defined behaviour if
2831 "resolved" is NULL. That's good enough for us to do the same here. */
2833 if (!real_path.error && real_path.exists ())
2837 resolved = (char *) malloc (strlen (real_path.normalized_path) + 1);
2841 strcpy (resolved, real_path.normalized_path);
2845 /* FIXME: on error, we are supposed to put the name of the path
2846 component which could not be resolved into RESOLVED. */
2849 set_errno (real_path.error ?: ENOENT);
2853 /* Return non-zero if path is a POSIX path list.
2854 This is exported to the world as cygwin_foo by cygwin.din.
2857 <sect1 id="add-func-cygwin-posix-path-list-p">
2858 <para>Rather than use a mode to say what the "proper" path list
2859 format is, we allow any, and give apps the tools they need to
2860 convert between the two. If a ';' is present in the path list it's
2861 a Win32 path list. Otherwise, if the first path begins with
2862 [letter]: (in which case it can be the only element since if it
2863 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
2864 it's a POSIX path list.</para>
2870 cygwin_posix_path_list_p (const char *path)
2872 int posix_p = !(strchr (path, ';') || isdrive (path));
2876 /* These are used for apps that need to convert env vars like PATH back and
2877 forth. The conversion is a two step process. First, an upper bound on the
2878 size of the buffer needed is computed. Then the conversion is done. This
2879 allows the caller to use alloca if it wants. */
2882 conv_path_list_buf_size (const char *path_list, bool to_posix)
2884 int i, num_elms, max_mount_path_len, size;
2887 path_conv pc(".", PC_POSIX);
2888 /* The theory is that an upper bound is
2889 current_size + (num_elms * max_mount_path_len) */
2890 /* FIXME: This method is questionable in the long run. */
2893 char delim = to_posix ? ';' : ':';
2894 for (p = path_list, num_elms = nrel = 0; p; num_elms++)
2898 p = strchr (++p, delim);
2901 /* 7: strlen ("//c") + slop, a conservative initial value */
2902 for (max_mount_path_len = sizeof ("/cygdrive/X"), i = 0;
2903 i < mount_table->nmounts; i++)
2905 int mount_len = (to_posix
2906 ? mount_table->mount[i].posix_pathlen
2907 : mount_table->mount[i].native_pathlen);
2908 if (max_mount_path_len < mount_len)
2909 max_mount_path_len = mount_len;
2913 size = strlen (path_list)
2914 + (num_elms * max_mount_path_len)
2915 + (nrel * strlen (to_posix ? pc.normalized_path : pc.get_win32 ()))
2923 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
2925 return conv_path_list_buf_size (path_list, true);
2929 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
2931 return conv_path_list_buf_size (path_list, false);
2935 env_PATH_to_posix (const void *win32, void *posix, size_t size)
2937 return_with_errno (conv_path_list ((const char *) win32, (char *) posix,
2942 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
2944 return_with_errno (conv_path_list (win32, posix, MAX_PATH, 1));
2948 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
2950 return_with_errno (conv_path_list (posix, win32, MAX_PATH, 0));
2954 cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to,
2957 /* FIXME: Path lists are (so far) always retaining relative paths. */
2958 what &= ~CCP_RELATIVE;
2961 case CCP_WIN_W_TO_POSIX:
2962 case CCP_POSIX_TO_WIN_W:
2964 api_fatal ("wide char path lists not yet supported");
2966 case CCP_WIN_A_TO_POSIX:
2967 case CCP_POSIX_TO_WIN_A:
2969 return conv_path_list_buf_size ((const char *) from,
2970 what == CCP_WIN_A_TO_POSIX);
2971 return_with_errno (conv_path_list ((const char *) from, (char *) to,
2972 size, what == CCP_WIN_A_TO_POSIX));
2981 /* cygwin_split_path: Split a path into directory and file name parts.
2982 Buffers DIR and FILE are assumed to be big enough.
2984 Examples (path -> `dir' / `file'):
2987 . -> `.' / `.' (FIXME: should this be `.' / `'?)
2988 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
2990 foo/bar -> `foo' / `bar'
2991 foo/bar/ -> `foo' / `bar'
2993 /foo/bar -> `/foo' / `bar'
2996 c:foo -> `c:/' / `foo'
2997 c:/foo -> `c:/' / `foo'
3001 cygwin_split_path (const char *path, char *dir, char *file)
3003 int dir_started_p = 0;
3005 /* Deal with drives.
3006 Remember that c:foo <==> c:/foo. */
3018 if (isdirsep (*path))
3023 /* Determine if there are trailing slashes and "delete" them if present.
3024 We pretend as if they don't exist. */
3025 const char *end = path + strlen (path);
3026 /* path + 1: keep leading slash. */
3027 while (end > path + 1 && isdirsep (end[-1]))
3030 /* At this point, END points to one beyond the last character
3031 (with trailing slashes "deleted"). */
3033 /* Point LAST_SLASH at the last slash (duh...). */
3034 const char *last_slash;
3035 for (last_slash = end - 1; last_slash >= path; --last_slash)
3036 if (isdirsep (*last_slash))
3039 if (last_slash == path)
3044 else if (last_slash > path)
3046 memcpy (dir, path, last_slash - path);
3047 dir[last_slash - path] = 0;
3052 ; /* nothing to do */
3058 memcpy (file, last_slash + 1, end - last_slash - 1);
3059 file[end - last_slash - 1] = 0;
3062 /*****************************************************************************/
3064 static inline PRTL_USER_PROCESS_PARAMETERS
3065 get_user_proc_parms ()
3067 return NtCurrentTeb ()->Peb->ProcessParameters;
3070 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
3074 cwd_lock.init ("cwd_lock");
3075 /* Initially re-open the cwd to allow POSIX semantics. */
3076 set (NULL, NULL, true);
3079 /* Chdir and fill out the elements of a cwdstuff struct. */
3081 cwdstuff::set (PUNICODE_STRING nat_cwd, const char *posix_cwd, bool doit)
3084 UNICODE_STRING upath;
3087 cwd_lock.acquire ();
3092 if (upath.Buffer[0] == L'/') /* Virtual path. Never use in PEB. */
3096 len = upath.Length / sizeof (WCHAR) - 4;
3097 if (RtlEqualUnicodePathPrefix (&upath, &ro_u_uncp, TRUE))
3104 /* We utilize the user parameter block. The directory is
3105 stored manually there. Why the hassle?
3107 - SetCurrentDirectory fails for directories with strict
3108 permissions even for processes with the SE_BACKUP_NAME
3109 privilege enabled. The reason is apparently that
3110 SetCurrentDirectory calls NtOpenFile without the
3111 FILE_OPEN_FOR_BACKUP_INTENT flag set.
3113 - Unlinking a cwd fails because SetCurrentDirectory seems to
3114 open directories so that deleting the directory is disallowed.
3115 The below code opens with *all* sharing flags set. */
3119 OBJECT_ATTRIBUTES attr;
3122 RtlAcquirePebLock ();
3123 phdl = &get_user_proc_parms ()->CurrentDirectoryHandle;
3124 if (!nat_cwd) /* On init, just reopen CWD with desired access flags. */
3125 RtlInitUnicodeString (&upath, L"");
3126 /* This is for Win32 apps only. No case sensitivity here... */
3127 InitializeObjectAttributes (&attr, &upath,
3128 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
3129 nat_cwd ? NULL : *phdl, NULL);
3130 status = NtOpenFile (&h, SYNCHRONIZE | FILE_TRAVERSE, &attr, &io,
3131 FILE_SHARE_VALID_FLAGS,
3133 | FILE_SYNCHRONOUS_IO_NONALERT
3134 | FILE_OPEN_FOR_BACKUP_INTENT);
3135 if (!NT_SUCCESS (status))
3137 RtlReleasePebLock ();
3138 __seterrno_from_nt_status (status);
3142 /* Workaround a problem in Vista/Longhorn which fails in subsequent
3143 calls to CreateFile with ERROR_INVALID_HANDLE if the handle in
3144 CurrentDirectoryHandle changes without calling SetCurrentDirectory,
3145 and the filename given to CreateFile is a relative path. It looks
3146 like Vista stores a copy of the CWD handle in some other undocumented
3147 place. The NtClose/DuplicateHandle reuses the original handle for
3148 the copy of the new handle and the next CreateFile works.
3149 Note that this is not thread-safe (yet?) */
3151 if (DuplicateHandle (GetCurrentProcess (), h, GetCurrentProcess (), phdl,
3152 0, TRUE, DUPLICATE_SAME_ACCESS))
3158 /* No need to set path on init. */
3161 Check the length of the new CWD. Windows can only handle
3162 CWDs of up to MAX_PATH length, including a trailing backslash.
3163 If the path is longer, it's not an error condition for Cygwin,
3164 so we don't fail. Windows on the other hand has a problem now.
3165 For now, we just don't store the path in the PEB and proceed as
3167 && len <= MAX_PATH - (nat_cwd->Buffer[len - 1] == L'\\' ? 1 : 2))
3169 /* Convert to a Win32 path. */
3170 upath.Buffer += upath.Length / sizeof (WCHAR) - len;
3171 if (upath.Buffer[1] == L'\\') /* UNC path */
3172 upath.Buffer[0] = L'\\';
3173 upath.Length = len * sizeof (WCHAR);
3174 /* Append backslash if necessary. */
3175 if (upath.Buffer[len - 1] != L'\\')
3177 upath.Buffer[len] = L'\\';
3178 upath.Length += sizeof (WCHAR);
3180 RtlCopyUnicodeString (&get_user_proc_parms ()->CurrentDirectoryName,
3184 RtlReleasePebLock ();
3187 if (nat_cwd || !win32.Buffer)
3189 /* If there is no win32 path */
3192 PUNICODE_STRING pdir;
3194 RtlAcquirePebLock ();
3195 pdir = &get_user_proc_parms ()->CurrentDirectoryName;
3196 RtlInitEmptyUnicodeString (&win32,
3197 (PWCHAR) crealloc_abort (win32.Buffer,
3200 RtlCopyUnicodeString (&win32, pdir);
3201 RtlReleasePebLock ();
3203 PWSTR eoBuffer = win32.Buffer + (win32.Length / sizeof (WCHAR));
3204 /* Remove trailing slash if one exists. FIXME: Is there a better way to
3206 if ((eoBuffer - win32.Buffer) > 3 && eoBuffer[-1] == L'\\')
3207 win32.Length -= sizeof (WCHAR);
3215 if (upath.Buffer[0] == L'/') /* Virtual path, don't mangle. */
3219 /* Convert to a Win32 path. */
3220 upath.Buffer += upath.Length / sizeof (WCHAR) - len;
3221 if (upath.Buffer[1] == L'\\') /* UNC path */
3223 upath.Length = len * sizeof (WCHAR);
3227 PWSTR eoBuffer = upath.Buffer + (upath.Length / sizeof (WCHAR));
3228 /* Remove trailing slash if one exists. FIXME: Is there a better way to
3230 if ((eoBuffer - upath.Buffer) > 3 && eoBuffer[-1] == L'\\')
3231 upath.Length -= sizeof (WCHAR);
3233 RtlInitEmptyUnicodeString (&win32,
3234 (PWCHAR) crealloc_abort (win32.Buffer,
3237 RtlCopyUnicodeString (&win32, &upath);
3239 win32.Buffer[0] = L'\\';
3241 /* Make sure it's NUL-terminated. */
3242 win32.Buffer[win32.Length / sizeof (WCHAR)] = L'\0';
3243 if (!doit) /* Virtual path */
3245 else if (win32.Buffer[1] == L':') /* X: */
3247 else if (win32.Buffer[1] == L'\\') /* UNC path */
3249 PWCHAR ptr = wcschr (win32.Buffer + 2, L'\\');
3251 ptr = wcschr (ptr + 1, L'\\');
3253 drive_length = ptr - win32.Buffer;
3255 drive_length = win32.Length / sizeof (WCHAR);
3257 else /* Shouldn't happen */
3263 posix_cwd = (const char *) tp.c_get ();
3264 mount_table->conv_to_posix_path (win32.Buffer, (char *) posix_cwd, 0);
3271 cwd_lock.release ();
3275 /* Copy the value for either the posix or the win32 cwd into a buffer. */
3277 cwdstuff::get_posix ()
3279 if (!posix || !*posix)
3283 char *tocopy = tp.c_get ();
3284 mount_table->conv_to_posix_path (win32.Buffer, tocopy, 0);
3285 posix = (char *) crealloc_abort (posix, strlen (tocopy) + 1);
3286 stpcpy (posix, tocopy);
3292 cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
3299 else if (buf == NULL)
3300 ulen = (unsigned) -1;
3307 cwd_lock.acquire ();
3312 tocopy = tp.c_get ();
3313 sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer,
3314 win32.Length / sizeof (WCHAR));
3316 else if (!posix || !*posix)
3318 tocopy = tp.c_get ();
3319 mount_table->conv_to_posix_path (win32.Buffer, tocopy, 0);
3320 posix = (char *) crealloc_abort (posix, strlen (tocopy) + 1);
3321 stpcpy (posix, tocopy);
3326 debug_printf ("posix %s", posix);
3327 if (strlen (tocopy) >= ulen)
3335 buf = (char *) malloc (strlen (tocopy) + 1);
3336 strcpy (buf, tocopy);
3337 if (!buf[0]) /* Should only happen when chroot */
3341 cwd_lock.release ();
3344 syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
3345 buf, buf, ulen, need_posix, with_chroot, errno);
3350 int etc::curr_ix = 0;
3351 /* Note that the first elements of the below arrays are unused */
3352 bool etc::change_possible[MAX_ETC_FILES + 1];
3353 OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1];
3354 LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1];
3357 etc::init (int n, POBJECT_ATTRIBUTES attr)
3361 else if (++curr_ix <= MAX_ETC_FILES)
3364 api_fatal ("internal error");
3367 change_possible[n] = false;
3368 test_file_change (n);
3369 paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix);
3374 etc::test_file_change (int n)
3377 FILE_NETWORK_OPEN_INFORMATION fnoi;
3380 status = NtQueryFullAttributesFile (&fn[n], &fnoi);
3381 if (!NT_SUCCESS (status))
3384 memset (last_modified + n, 0, sizeof (last_modified[n]));
3385 debug_printf ("NtQueryFullAttributesFile (%S) failed, %p",
3386 fn[n].ObjectName, status);
3390 res = CompareFileTime ((FILETIME *) &fnoi.LastWriteTime,
3391 (FILETIME *) last_modified + n) > 0;
3392 last_modified[n].QuadPart = fnoi.LastWriteTime.QuadPart;
3395 paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
3400 etc::dir_changed (int n)
3402 if (!change_possible[n])
3404 static HANDLE changed_h NO_COPY;
3410 OBJECT_ATTRIBUTES attr;
3412 path_conv dir ("/etc");
3413 status = NtOpenFile (&changed_h, SYNCHRONIZE | FILE_LIST_DIRECTORY,
3414 dir.get_object_attr (attr, sec_none_nih), &io,
3415 FILE_SHARE_VALID_FLAGS, FILE_DIRECTORY_FILE);
3416 if (!NT_SUCCESS (status))
3419 system_printf ("NtOpenFile (%S) failed, %p",
3420 dir.get_nt_native_path (), status);
3422 changed_h = INVALID_HANDLE_VALUE;
3426 status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
3428 FILE_NOTIFY_CHANGE_LAST_WRITE
3429 | FILE_NOTIFY_CHANGE_FILE_NAME,
3431 if (!NT_SUCCESS (status))
3434 system_printf ("NtNotifyChangeDirectoryFile (1) failed, %p",
3437 NtClose (changed_h);
3438 changed_h = INVALID_HANDLE_VALUE;
3441 memset (change_possible, true, sizeof (change_possible));
3444 if (changed_h == INVALID_HANDLE_VALUE)
3445 change_possible[n] = true;
3446 else if (WaitForSingleObject (changed_h, 0) == WAIT_OBJECT_0)
3448 status = NtNotifyChangeDirectoryFile (changed_h, NULL, NULL,
3450 FILE_NOTIFY_CHANGE_LAST_WRITE
3451 | FILE_NOTIFY_CHANGE_FILE_NAME,
3453 if (!NT_SUCCESS (status))
3456 system_printf ("NtNotifyChangeDirectoryFile (2) failed, %p",
3459 NtClose (changed_h);
3460 changed_h = INVALID_HANDLE_VALUE;
3462 memset (change_possible, true, sizeof change_possible);
3466 paranoid_printf ("fn[%d] %S change_possible %d",
3467 n, fn[n].ObjectName, change_possible[n]);
3468 return change_possible[n];
3472 etc::file_changed (int n)
3475 if (dir_changed (n) && test_file_change (n))
3477 change_possible[n] = false; /* Change is no longer possible */
3478 paranoid_printf ("fn[%d] %S res %d", n, fn[n].ObjectName, res);
3482 /* No need to be reentrant or thread-safe according to SUSv3.
3483 / and \\ are treated equally. Leading drive specifiers are
3484 kept intact as far as it makes sense. Everything else is
3485 POSIX compatible. */
3487 basename (char *path)
3490 char *c, *d, *bs = path;
3492 if (!path || !*path)
3493 return strcpy (buf, ".");
3494 if (isalpha (path[0]) && path[1] == ':')
3496 else if (strspn (path, "/\\") > 1)
3498 c = strrchr (bs, '/');
3499 if ((d = strrchr (c ?: bs, '\\')) > c)
3503 /* Trailing (back)slashes are eliminated. */
3504 while (c && c > bs && c[1] == '\0')
3507 c = strrchr (bs, '/');
3508 if ((d = strrchr (c ?: bs, '\\')) > c)
3511 if (c && (c > bs || c[1]))
3516 stpncpy (buf, path, bs - path);
3517 stpcpy (buf + (bs - path), ".");
3523 /* No need to be reentrant or thread-safe according to SUSv3.
3524 / and \\ are treated equally. Leading drive specifiers and
3525 leading double (back)slashes are kept intact as far as it
3526 makes sense. Everything else is POSIX compatible. */
3528 dirname (char *path)
3531 char *c, *d, *bs = path;
3533 if (!path || !*path)
3534 return strcpy (buf, ".");
3535 if (isalpha (path[0]) && path[1] == ':')
3537 else if (strspn (path, "/\\") > 1)
3539 c = strrchr (bs, '/');
3540 if ((d = strrchr (c ?: bs, '\\')) > c)
3544 /* Trailing (back)slashes are eliminated. */
3545 while (c && c > bs && c[1] == '\0')
3548 c = strrchr (bs, '/');
3549 if ((d = strrchr (c ?: bs, '\\')) > c)
3556 /* More trailing (back)slashes are eliminated. */
3557 while (c > bs && (*c == '/' || *c == '\\'))
3565 stpncpy (buf, path, bs - path);
3566 stpcpy (buf + (bs - path), ".");