1 /* path.cc: path support.
3 Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 /* This module's job is to
12 - convert between POSIX and Win32 style filenames,
13 - support the `mount' functionality,
14 - support symlinks for files and directories
16 Pathnames are handled as follows:
18 - / is equivalent to \
19 - Paths beginning with // (or \\) are not translated (i.e. looked
20 up in the mount table) and are assumed to be UNC path names.
21 - Paths containing a : are not translated (paths like
22 /foo/bar/baz:qux: don't make much sense but having the rule written
23 this way allows one to use strchr).
25 The goal in the above set of rules is to allow both POSIX and Win32
26 flavors of pathnames without either interfering. The rules are
27 intended to be as close to a superset of both as possible.
29 A possible future enhancement would be to allow people to
30 disable/enable the mount table handling to support pure Win32
31 pathnames. Hopefully this won't be needed. The suggested way to
32 do this would be an environment variable because
33 a) we need something that is inherited from parent to child,
34 b) environment variables can be passed from the DOS shell to a
36 c) it allows disabling the feature on an app by app basis within
37 the same session (whereas playing about with the registry wouldn't
38 -- without getting too complicated). Example:
39 CYGWIN=pathrules[=@]{win32,posix}. If CYGWIN=pathrules=win32,
40 mount table handling is disabled. [The intent is to have CYGWIN be
41 a catchall for tweaking various cygwin.dll features].
43 Note that you can have more than one path to a file. The mount
44 table is always prefered when translating Win32 paths to POSIX
45 paths. Win32 paths in mount table entries may be UNC paths or
46 standard Win32 paths starting with <drive-letter>:
48 In converting from a Win32 to a POSIX pathname, if there is no
49 mount point that will allow the conversion to take place, a user
50 mount point will be automatically created under
51 cygdrive/<drive> and the translation will be redone, this
54 Text vs Binary issues are not considered here in path style
57 / and \ are treated as equivalent. One or the other is prefered in
58 certain situations (e.g. / is preferred in result of getcwd, \ is
59 preferred in arguments to Win32 api calls), but this code will
60 translate as necessary.
62 Apps wishing to translate to/from pure Win32 and POSIX-like
63 pathnames can use cygwin_foo.
65 Removing mounted filesystem support would simplify things greatly,
66 but having it gives us a mechanism of treating disk that lives on a
67 UNIX machine as having UNIX semantics [it allows one to edit a text
68 file on that disk and not have cr's magically appear and perhaps
69 break apps running on UNIX boxes]. It also useful to be able to
70 layout a hierarchy without changing the underlying directories.
72 The semantics of mounting file systems is not intended to precisely
73 follow normal UNIX systems.
75 Each DOS drive is defined to have a current directory. Supporting
76 this would complicate things so for now things are defined so that
82 #include <sys/mount.h>
90 static int normalize_win32_path (const char *cwd, const char *src, char *dst);
91 static char *getcwd_inner (char *buf, size_t ulen, int posix_p);
92 static void slashify (const char *src, char *dst, int trailing_slash_p);
93 static void backslashify (const char *src, char *dst, int trailing_slash_p);
94 static int path_prefix_p_ (const char *path1, const char *path2, int len1);
95 static int get_current_directory_name ();
97 static NO_COPY const char escape_char = '^';
101 char buf[3 + MAX_PATH * 3];
108 symlink_info (): known_suffix (NULL), contents (buf + MAX_PATH + 1) {}
109 int check (const char *path, const suffix_info *suffixes);
112 /********************** Path Helper Functions *************************/
114 #define path_prefix_p(p1, p2, l1) \
115 ((tolower(*(p1))==tolower(*(p2))) && \
116 path_prefix_p_(p1, p2, l1))
118 #define SYMLINKATTR(x) \
119 (((x) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) == \
120 FILE_ATTRIBUTE_SYSTEM)
122 /* Return non-zero if PATH1 is a prefix of PATH2.
123 Both are assumed to be of the same path style and / vs \ usage.
125 LEN1 = strlen (PATH1). It's passed because often it's already known.
128 /foo/ is a prefix of /foo <-- may seem odd, but desired
129 /foo is a prefix of /foo/
130 / is a prefix of /foo/bar
131 / is not a prefix of foo/bar
132 foo/ is a prefix foo/bar
133 /foo is not a prefix of /foobar
136 /* Determine if path prefix matches current cygdrive */
137 #define iscygdrive(path) \
138 (path_prefix_p (cygwin_shared->mount.cygdrive, (path), cygwin_shared->mount.cygdrive_len))
140 #define iscygdrive_device(path) \
141 (iscygdrive(path) && isalpha(path[cygwin_shared->mount.cygdrive_len]) && \
142 (isdirsep(path[cygwin_shared->mount.cygdrive_len + 1]) || \
143 !path[cygwin_shared->mount.cygdrive_len + 1]))
145 /******************** Directory-related Support **************************/
147 /* Cache getcwd value. FIXME: We need a lock for these in order to
148 support multiple threads. */
151 #define current_directory_name _reent_winsup()->_current_directory_name
152 #define current_directory_posix_name _reent_winsup()->_current_directory_posix_name
153 #define current_directory_hash _reent_winsup()->_current_directory_hash
155 static char *current_directory_name;
156 static char *current_directory_posix_name;
157 static unsigned long current_directory_hash;
161 path_prefix_p_ (const char *path1, const char *path2, int len1)
163 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
164 if (len1 > 0 && SLASH_P (path1[len1 - 1]))
168 return SLASH_P (path2[0]) && !SLASH_P (path2[1]);
170 if (!strncasematch (path1, path2, len1))
173 return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
176 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
177 passing to Win32 API routines.
179 If an error occurs, `error' is set to the errno value.
180 Otherwise it is set to 0.
183 SYMLINK_FOLLOW - convert to PATH symlink points to
184 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
185 SYMLINK_IGNORE - do not check PATH for symlinks
186 SYMLINK_CONTENTS - just return symlink contents
189 path_conv::path_conv (const char *src, symlink_follow follow_mode,
190 int use_full_path, const suffix_info *suffixes)
192 /* This array is used when expanding symlinks. It is MAX_PATH * 2
193 in length so that we can hold the expanded symlink plus a
195 char path_buf[MAX_PATH];
196 char path_copy[MAX_PATH];
199 char *rel_path, *full_path;
201 if ((error = check_null_empty_path (src)))
205 rel_path = path_buf, full_path = this->path;
207 rel_path = this->path, full_path = path_buf;
209 /* This loop handles symlink expansion. */
213 fileattr = (DWORD) -1;
217 /* Must look up path in mount table, etc. */
218 error = cygwin_shared->mount.conv_to_win32_path (src, rel_path,
220 devn, unit, &path_flags);
230 /* Eat trailing slashes */
231 char *tail = strchr (full_path, '\0');
232 /* If path is only a drivename, Windows interprets it as
233 the current working directory on this drive instead of
234 the root dir which is what we want. So we need
235 the trailing backslash in this case. */
236 while (tail > full_path + 3 && (*--tail == '\\'))
238 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
239 strcat (full_path, "\\");
241 if (follow_mode == SYMLINK_IGNORE)
243 fileattr = GetFileAttributesA (path);
247 /* Make a copy of the path that we can munge up */
248 strcpy (path_copy, full_path);
250 tail = path_copy + 1 + (tail - full_path); // Point to end of copy
252 /* Scan path_copy from right to left looking either for a symlink
253 or an actual existing file. If an existing file is found, just
254 return. If a symlink is found exit the for loop.
255 Also: be careful to preserve the errno returned from
256 symlink.check as the caller may need it. */
257 /* FIXME: Do we have to worry about multiple \'s here? */
258 int component = 0; // Number of translated components
259 sym.contents[0] = '\0';
264 const suffix_info *suff;
266 /* Don't allow symlink.check to set anything in the path_conv
267 class if we're working on an inner component of the path */
276 sym.pflags = path_flags;
279 int len = sym.check (path_copy, suff);
282 path_flags = sym.pflags;
284 /* If symlink.check found an existing non-symlink file, then
285 it returns a length of 0 and sets errno to EINVAL. It also sets
286 any suffix found into `ext_here'. */
287 if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
291 fileattr = sym.fileattr;
294 goto out; // file found
296 /* Found a symlink if len > 0. If component == 0, then the
297 src path itself was a symlink. If !follow_mode then
298 we're done. Otherwise we have to insert the path found
299 into the full path that we are building and perform all of
300 these operations again on the newly derived path. */
303 if (component == 0 && follow_mode != SYMLINK_FOLLOW)
305 set_symlink (); // last component of path is a symlink.
306 fileattr = sym.fileattr;
307 if (follow_mode == SYMLINK_CONTENTS)
308 strcpy (path, sym.contents);
314 /* No existing file found. */
315 s.reset (); // remember errno from symlink.check
317 if (!(tail = strrchr (path_copy, '\\')) ||
318 (tail > path_copy && tail[-1] == ':'))
319 goto out; // all done
321 /* Haven't found a valid pathname component yet.
322 Pinch off the tail and try again. */
327 /* Arrive here if above loop detected a symlink. */
328 if (++loop > MAX_LINK_DEPTH)
330 error = ELOOP; // Eep.
335 tail = full_path + (tail - path_copy);
336 int taillen = strlen (tail);
337 int buflen = strlen (sym.contents);
338 if (buflen + taillen > MAX_PATH)
340 error = ENAMETOOLONG;
341 strcpy (path, "::ENAMETOOLONG::");
345 /* Copy tail of full_path to discovered symlink. */
347 for (p = sym.contents + buflen; *tail; tail++)
348 *p++ = *tail == '\\' ? '/' : *tail;
351 /* If symlink referred to an absolute path, then we
352 just use sym.contents and loop. Otherwise tack the head of
353 path_copy before sym.contents and translate it back from a
354 Win32-style path to a POSIX-style one. */
355 if (isabspath (sym.contents))
357 else if (!(tail = strrchr (path_copy, '\\')))
358 system_printf ("problem parsing %s - '%s'", src, full_path);
361 char tmp_buf[MAX_PATH];
362 int headlen = 1 + tail - path_copy;
363 p = sym.contents - headlen;
364 memcpy (p, path_copy, headlen);
366 error = cygwin_shared->mount.conv_to_posix_path (p, tmp_buf, 1);
375 if (sym.known_suffix)
376 known_suffix = this->path + (sym.known_suffix - path_copy);
377 else if (sym.ext_here && follow_mode != SYMLINK_CONTENTS)
379 known_suffix = strchr (this->path, '\0');
380 strcpy (known_suffix, sym.ext_here);
384 DWORD serial, volflags;
386 char root[strlen(full_path) + 10];
387 strcpy (root, full_path);
388 if (!rootdir (root) ||
389 !GetVolumeInformation (root, NULL, 0, &serial, NULL, &volflags, NULL, 0))
391 debug_printf ("GetVolumeInformation(%s) = ERR, full_path(%s), set_has_acls(FALSE)",
392 root, full_path, GetLastError ());
393 set_has_acls (FALSE);
397 debug_printf ("GetVolumeInformation(%s) = OK, full_path(%s), set_has_acls(%d)",
398 root, full_path, volflags & FS_PERSISTENT_ACLS);
399 set_has_acls (volflags & FS_PERSISTENT_ACLS);
403 #define deveq(s) (strcasematch (name, (s)))
404 #define deveqn(s, n) (strncasematch (name, (s), (n)))
407 digits (const char *name)
410 int n = strtol(name, &p, 10);
412 return p > name && !*p ? n : -1;
415 const char *windows_device_names[] =
441 get_raw_device_number (const char *uxname, const char *w32path, int &unit)
445 if (strncasecmp (w32path, "\\\\.\\tape", 8) == 0)
448 unit = digits (w32path + 8);
449 // norewind tape devices have leading n in name
450 if (! strncasecmp (uxname, "/dev/n", 6))
453 else if (isalpha (w32path[4]) && w32path[5] == ':')
456 unit = tolower (w32path[4]) - 'a';
458 else if (strncasecmp (w32path, "\\\\.\\physicaldrive", 17) == 0)
461 unit = digits (w32path + 17) + 128;
467 get_device_number (const char *name, int &unit, BOOL from_conv)
472 if ((*name == '/' && deveqn ("/dev/", 5)) ||
473 (*name == '\\' && deveqn ("\\dev\\", 5)))
478 if (tty_attached (myself))
483 else if (myself->ctty > 0)
486 else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
488 else if (deveq ("ttym"))
490 else if (deveq ("ptmx"))
492 else if (deveq ("windows"))
494 else if (deveq ("conin"))
496 else if (deveq ("conout"))
498 else if (deveq ("null"))
500 else if (deveq ("zero"))
502 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
504 else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew"))
506 else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket")
507 || deveq ("dgsocket"))
509 else if (! from_conv)
510 devn = get_raw_device_number (name - 5,
512 SYMLINK_IGNORE).get_win32 (),
515 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
521 /* Return TRUE if src_path is a Win32 device name, filling out the device
522 name in win32_path */
525 win32_device_name (const char *src_path, char *win32_path,
526 DWORD &devn, int &unit)
530 devn = get_device_number (src_path, unit, TRUE);
535 if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL)
537 __small_sprintf (win32_path, devfmt, unit);
541 /* Normalize a POSIX path.
542 \'s are converted to /'s in the process.
543 All duplicate /'s, except for 2 leading /'s, are deleted.
544 The result is 0 for success, or an errno error value. */
546 #define isslash(c) ((c) == '/')
549 normalize_posix_path (const char *cwd, const char *src, char *dst)
551 const char *src_start = src;
552 char *dst_start = dst;
554 if (!isslash (src[0]))
556 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
558 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
562 dst = strchr (dst, '\0');
565 if (dst == dst_start + 1)
569 if (dst > dst_start && !isslash (dst[-1]))
572 /* Two leading /'s? If so, preserve them. */
573 else if (isslash (src[1]))
579 { /* Starts with three or more slashes - reset. */
588 /* Strip runs of /'s. */
595 while (isslash (*src))
604 if ((src[1] && !isslash (src[1])))
609 if (src[2] && !isslash (src[2]))
611 while (dst > dst_start && !isslash (*--dst))
622 if (--dst > dst_start && isslash (*dst))
625 debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start);
629 /* Normalize a Win32 path.
630 /'s are converted to \'s in the process.
631 All duplicate \'s, except for 2 leading \'s, are deleted.
633 The result is 0 for success, or an errno error value.
634 FIXME: A lot of this should be mergeable with the POSIX critter. */
637 normalize_win32_path (const char *cwd, const char *src, char *dst)
639 const char *src_start = src;
640 char *dst_start = dst;
642 if (!SLASH_P (src[0])
643 && strchr (src, ':') == NULL)
645 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
647 debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
654 /* Two leading \'s? If so, preserve them. */
655 else if (SLASH_P (src[0]) && SLASH_P (src[1]))
663 /* Strip duplicate /'s. */
664 if (SLASH_P (src[0]) && SLASH_P (src[1]))
667 else if (src[0] == '.' && SLASH_P (src[1])
668 && (src == src_start || SLASH_P (src[-1])))
673 /* Backup if "..". */
674 else if (src[0] == '.' && src[1] == '.'
675 /* dst must be greater than dst_start */
677 && (SLASH_P (src[2]) || src[2] == 0))
679 /* Back up over /, but not if it's the first one. */
680 if (dst > dst_start + 1)
682 /* Now back up to the next /. */
683 while (dst > dst_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
689 /* Otherwise, add char to result. */
700 debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
705 /* Various utilities. */
707 /* slashify: Convert all back slashes in src path to forward slashes
708 in dst path. Add a trailing slash to dst when trailing_slash_p arg
712 slashify (const char *src, char *dst, int trailing_slash_p)
714 const char *start = src;
726 && !isdirsep (src[-1]))
731 /* backslashify: Convert all forward slashes in src path to back slashes
732 in dst path. Add a trailing slash to dst when trailing_slash_p arg
736 backslashify (const char *src, char *dst, int trailing_slash_p)
738 const char *start = src;
750 && !isdirsep (src[-1]))
755 /* nofinalslash: Remove trailing / and \ from SRC (except for the
756 first one). It is ok for src == dst. */
759 nofinalslash (const char *src, char *dst)
761 int len = strlen (src);
763 memcpy (dst, src, len + 1);
764 while (len > 1 && SLASH_P (dst[--len]))
768 /* slash_drive_prefix_p: Return non-zero if PATH begins with
772 slash_drive_prefix_p (const char *path)
774 return (isdirsep(path[0])
777 && (path[3] == 0 || path[3] == '/'));
780 /* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
783 slash_unc_prefix_p (const char *path)
786 int ret = (isdirsep (path[0])
787 && isdirsep (path[1])
790 && !isdirsep (path[3])
791 && ((p = strchr(&path[3], '/')) != NULL));
792 if (!ret || p == NULL)
794 return ret && isalnum (p[1]);
797 /* conv_path_list: Convert a list of path names to/from Win32/POSIX.
799 SRC is not a const char * because we temporarily modify it to ease
802 I believe Win32 always has '.' in $PATH. POSIX obviously doesn't.
803 We certainly don't want to handle that here, but it is something for
804 the caller to think about. */
807 conv_path_list (const char *src, char *dst, int to_posix_p)
811 char src_delim = to_posix_p ? ';' : ':';
812 char dst_delim = to_posix_p ? ':' : ';';
813 int (*conv_fn) (const char *, char *) = (to_posix_p
814 ? cygwin_conv_to_posix_path
815 : cygwin_conv_to_win32_path);
819 s = strchr (src, src_delim);
823 (*conv_fn) (src[0] != 0 ? src : ".", d);
832 (*conv_fn) (src[0] != 0 ? src : ".", d);
838 /************************* mount_info class ****************************/
840 /* init: Initialize the mount table. */
848 had_to_create_mount_areas = 0;
850 /* Fetch the mount table and cygdrive-related information from
854 /* If slash isn't already mounted, mount system directory as slash. */
856 for (int i = 0; i < nmounts; i++)
858 if (strcmp (mount[i].posix_path, "/") == 0)
869 /* mount_slash: mount the system partition as slash. */
872 mount_info::mount_slash ()
874 char drivestring[MAX_PATH];
875 GetSystemDirectory (drivestring, MAX_PATH);
876 drivestring[2] = 0; /* truncate path to "<drive>:" */
878 if (add_reg_mount (drivestring, "/", 0) == 0)
879 add_item (drivestring, "/", 0);
882 /* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
883 the result in win32_path.
885 If win32_path != NULL, the relative path, if possible to keep, is
886 stored in win32_path. If the relative path isn't possible to keep,
887 the full path is stored.
889 If full_win32_path != NULL, the full path is stored there.
891 The result is zero for success, or an errno value.
893 {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */
896 mount_info::conv_to_win32_path (const char *src_path, char *win32_path,
897 char *full_win32_path, DWORD &devn, int &unit,
900 int src_path_len = strlen (src_path);
901 int trailing_slash_p = (src_path_len > 0
902 && SLASH_P (src_path[src_path_len - 1]));
905 unsigned dummy_flags;
911 flags = &dummy_flags;
914 debug_printf ("conv_to_win32_path (%s)", src_path);
916 if (src_path_len >= MAX_PATH)
918 debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path);
924 mount_item *mi = NULL; /* initialized to avoid compiler warning */
925 char pathbuf[MAX_PATH];
927 /* The rule is :'s can't appear in [our] POSIX path names so this is a safe
928 test; if ':' is present it already be in Win32 form. */
929 /* Additional test: If the path has \'s in it, we assume that it's a Win32
931 if (strchr (src_path, ':') != NULL
932 || (strchr (src_path, '\\')/* && !strchr (src_path, '/')*/))
934 debug_printf ("%s already win32", src_path);
935 rc = normalize_win32_path ("", src_path, pathbuf);
938 /* FIXME: Do we have to worry about trailing_slash_p here? */
939 if (win32_path != NULL)
941 /* If src_path is a relativ win32 path, normalize_win32_path
942 adds a leading slash, nevertheless. So we have to test
944 strcpy (win32_path, strchr("/\\", src_path[0]) || src_path[1] == ':'
945 ? pathbuf : pathbuf + 1);
947 if (full_win32_path != NULL)
949 *full_win32_path = '\0';
950 /* Add drive if it's a local relative Win32 path */
951 if (! strchr(src_path, ':') && strncmp (src_path, "\\\\", 2))
953 GetCurrentDirectory (MAX_PATH, full_win32_path);
954 if (src_path[0] == '\\') // drive relative absolute path
955 full_win32_path[2] = '\0';
957 strcat (full_win32_path, pathbuf);
959 *flags = set_flags_from_win32_path (pathbuf);
963 /* Normalize the path, taking out ../../ stuff, we need to do this
964 so that we can move from one mounted directory to another with relative
967 eg mounting c:/foo /foo
973 should look in c:/foo, not d:/foo.
975 We do this by first getting an absolute UNIX-style path and then
976 converting it to a DOS-style path, looking up the appropriate drive
977 in the mount table. */
981 /* No need to fetch cwd if path is absolute. */
982 if ((isrelpath = !isslash (*src_path)))
983 getcwd_inner (cwd, MAX_PATH, TRUE); /* FIXME: check rc */
985 strcpy (cwd, "/"); /* some innocuous value */
987 rc = normalize_posix_path (cwd, src_path, pathbuf);
991 debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
996 /* Determine where the destination should be placed. */
997 if (full_win32_path != NULL)
998 dst = full_win32_path;
999 else if (win32_path != NULL)
1003 goto out; /* Sanity check. */
1005 /* See if this is a cygwin "device" */
1006 if (win32_device_name (pathbuf, dst, devn, unit))
1008 *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */
1012 /* Check if the cygdrive prefix was specified. If so, just strip
1013 off the prefix and transform it into an MS-DOS path. */
1015 if (iscygdrive_device (pathbuf))
1017 if (!cygdrive_win32_path (pathbuf, dst, trailing_slash_p))
1019 *flags = cygdrive_flags;
1023 /* Check the mount table for prefix matches. */
1024 for (i = 0; i < nmounts; i++)
1026 mi = mount + posix_sorted[i];
1027 if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen))
1033 if (slash_drive_prefix_p (pathbuf))
1034 slash_drive_to_win32_path (pathbuf, dst, trailing_slash_p);
1036 backslashify (pathbuf, dst, trailing_slash_p); /* just convert */
1041 int n = mi->native_pathlen;
1042 memcpy (dst, mi->native_path, n);
1043 char *p = pathbuf + mi->posix_pathlen;
1044 if (!trailing_slash_p && !*p)
1048 /* Do not add trailing \ to UNC device names like \\.\a: */
1049 if (*p != '/' && /* FIXME: this test seems wrong. */
1050 (strncmp (mi->native_path, "\\\\.\\", 4) != 0 ||
1051 strncmp (mi->native_path + 4, "UNC\\", 4) == 0))
1053 strcpy (dst + n, p);
1055 backslashify (dst, dst, trailing_slash_p);
1060 /* Compute relative path if asked to and able to. */
1062 cwdlen = 0; /* avoid a (hopefully) bogus compiler warning */
1063 if (win32_path == NULL)
1064 /* nothing to do */;
1065 else if (isrelpath &&
1066 path_prefix_p (current_directory_name, dst,
1067 cwdlen = strlen (current_directory_name)))
1069 if (strlen (dst) == cwdlen)
1072 dst += isdirsep (current_directory_name[cwdlen - 1]) ? cwdlen : cwdlen + 1;
1074 memmove (win32_path, dst, strlen (dst) + 1);
1077 strcpy (win32_path, ".");
1078 if (trailing_slash_p)
1079 strcat (win32_path, "\\");
1082 else if (win32_path != dst)
1083 strcpy (win32_path, dst);
1087 debug_printf ("%s(rel), %s(abs) %p(flags) = conv_to_win32_path (%s)",
1088 win32_path, full_win32_path, *flags,
1093 /* Convert PATH (for which slash_drive_prefix_p returns 1) to WIN32 form. */
1096 mount_info::slash_drive_to_win32_path (const char *path, char *buf,
1097 int trailing_slash_p)
1102 strcpy (buf + 2, "\\");
1104 backslashify (path + 3, buf + 2, trailing_slash_p);
1107 /* cygdrive_posix_path: Build POSIX path used as the
1108 mount point for cygdrives created when there is no other way to
1109 obtain a POSIX path from a Win32 one. */
1112 mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
1114 int len = cygdrive_len;
1116 memcpy (dst, cygdrive, len + 1);
1118 /* Now finish the path off with the drive letter to be used.
1119 The cygdrive prefix always ends with a trailing slash so
1120 the drive letter is added after the path. */
1121 dst[len++] = tolower (src[0]);
1123 dst[len++] = '\000';
1127 strcpy (dst + len, src + 3);
1129 slashify (dst, dst, trailing_slash_p);
1133 mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
1135 const char *p = src + cygdrive_len;
1136 if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
1140 strcpy (dst + 2, p + 1);
1141 backslashify (dst, dst, trailing_slash_p || !dst[2]);
1142 debug_printf ("src '%s', dst '%s'", src, dst);
1146 /* conv_to_posix_path: Ensure src_path is a POSIX path.
1148 The result is zero for success, or an errno value.
1149 posix_path must have sufficient space (i.e. MAX_PATH bytes).
1150 If keep_rel_p is non-zero, relative paths stay that way. */
1153 mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
1156 int src_path_len = strlen (src_path);
1157 int trailing_slash_p = (src_path_len > 0
1158 && SLASH_P (src_path[src_path_len - 1]));
1159 int relative_path_p = (! SLASH_P (*src_path)
1160 && strchr (src_path, ':') == NULL);
1162 debug_printf ("conv_to_posix_path (%s, %s)", src_path,
1163 keep_rel_p ? "keep-rel" : "no-keep-rel");
1166 if (src_path_len >= MAX_PATH)
1168 debug_printf ("ENAMETOOLONG");
1169 return ENAMETOOLONG;
1172 /* FIXME: For now, if the path is relative and it's supposed to stay
1173 that way, skip mount table processing. */
1175 if (keep_rel_p && relative_path_p)
1177 slashify (src_path, posix_path, 0);
1178 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1182 char pathbuf[MAX_PATH];
1185 /* No need to fetch cwd if path is absolute. */
1186 if (relative_path_p)
1187 getcwd_inner (cwd, MAX_PATH, 0); /* FIXME: check rc */
1189 strcpy (cwd, "/"); /* some innocuous value */
1191 int rc = normalize_win32_path (cwd, src_path, pathbuf);
1194 debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1198 int pathbuflen = strlen (pathbuf);
1199 for (int i = 0; i < nmounts; ++i)
1201 mount_item &mi = mount[native_sorted[i]];
1202 if (! path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1205 /* SRC_PATH is in the mount table. */
1207 if (!pathbuf[mi.native_pathlen])
1209 else if (isdirsep (pathbuf[mi.native_pathlen]))
1214 int addslash = nextchar > 0 ? 1 : 0;
1215 if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH)
1216 return ENAMETOOLONG;
1217 strcpy (posix_path, mi.posix_path);
1219 strcat (posix_path, "/");
1221 slashify (pathbuf + mi.native_pathlen,
1222 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
1227 /* Not in the database. This should [theoretically] only happen if either
1228 the path begins with //, or / isn't mounted, or the path has a drive
1229 letter not covered by the mount table. If it's a relative path then the
1230 caller must want an absolute path (otherwise we would have returned
1231 above). So we always return an absolute path at this point. */
1232 if ((isalpha (pathbuf[0])) && (pathbuf[1] == ':'))
1233 cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p &&
1237 /* The use of src_path and not pathbuf here is intentional.
1238 We couldn't translate the path, so just ensure no \'s are present. */
1239 slashify (src_path, posix_path, trailing_slash_p);
1243 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1248 /* Return flags associated with a mount point given the win32 path. */
1251 mount_info::set_flags_from_win32_path (const char *p)
1253 for (int i = 0; i < nmounts; i++)
1255 mount_item &mi = mount[native_sorted[i]];
1256 if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
1262 /* read_mounts: Given a specific regkey, read mounts from under its
1266 mount_info::read_mounts (reg_key& r)
1268 char posix_path[MAX_PATH];
1269 HKEY key = r.get_key ();
1270 DWORD i, posix_path_size;
1275 posix_path_size = MAX_PATH;
1276 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1279 if (err != ERROR_SUCCESS)
1282 if (iscygdrive (posix_path))
1284 /* This shouldn't be in the mount table. */
1285 (void) r.kill (posix_path);
1290 /* Loop through subkeys */
1291 /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
1292 shared area is currently statically allocated so we can't have an
1293 arbitrarily large number of mounts. */
1294 for (DWORD i = 0; i < MAX_MOUNTS; i++)
1296 char native_path[MAX_PATH];
1299 posix_path_size = MAX_PATH;
1300 /* FIXME: if maximum posix_path_size is 256, we're going to
1301 run into problems if we ever try to store a mount point that's
1302 over 256 but is under MAX_PATH! */
1303 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1306 if (err == ERROR_NO_MORE_ITEMS)
1308 else if (err != ERROR_SUCCESS)
1310 debug_printf ("RegEnumKeyEx failed, error %d!\n", err);
1314 if (iscygdrive (posix_path))
1316 /* This shouldn't be in the mount table. */
1317 // (void) r.kill (posix_path);
1321 /* Get a reg_key based on i. */
1322 reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1324 /* Check the mount table for prefix matches. */
1325 for (int j = 0; j < nmounts; j++)
1326 if (strcasematch (mount[j].posix_path, posix_path))
1327 goto next; /* Can't have more than one */
1329 /* Fetch info from the subkey. */
1330 subkey.get_string ("native", native_path, sizeof (native_path), "");
1331 mount_flags = subkey.get_int ("flags", 0);
1333 /* Add mount_item corresponding to registry mount point. */
1334 cygwin_shared->mount.add_item (native_path, posix_path, mount_flags);
1340 /* from_registry: Build the entire mount table from the registry. Also,
1341 read in cygdrive-related information from its registry location. */
1344 mount_info::from_registry ()
1346 /* Use current mount areas if either user or system mount areas
1347 already exist. Otherwise, import old mounts. */
1351 /* Retrieve cygdrive-related information. */
1352 read_cygdrive_info_from_registry ();
1356 /* First read mounts from user's table. */
1359 /* Then read mounts from system-wide mount table. */
1360 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1361 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1362 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1363 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1367 /* If we had to create both user and system mount areas, import
1369 if (had_to_create_mount_areas == 2)
1370 import_v1_mounts ();
1375 /* add_reg_mount: Add mount item to registry. Return zero on success,
1376 non-zero on failure. */
1377 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1380 mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1382 /* Add the mount to the right registry location, depending on
1383 whether MOUNT_SYSTEM is set in the mount flags. */
1384 if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
1386 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1389 /* Start by deleting existing mount if one exists. */
1390 reg_user.kill (posix_path);
1392 /* Create the new mount. */
1393 reg_key subkey = reg_key (reg_user.get_key (),
1396 subkey.set_string ("native", native_path);
1397 subkey.set_int ("flags", mountflags);
1399 else /* local_machine mount */
1401 /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
1402 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1403 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1404 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1405 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1408 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1414 /* Start by deleting existing mount if one exists. */
1415 reg_sys.kill (posix_path);
1417 /* Create the new mount. */
1418 reg_key subkey = reg_key (reg_sys.get_key (),
1421 subkey.set_string ("native", native_path);
1422 subkey.set_int ("flags", mountflags);
1425 return 0; /* Success! */
1428 /* del_reg_mount: delete mount item from registry indicated in flags.
1429 Return zero on success, non-zero on failure.*/
1430 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1433 mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1437 if ((flags & MOUNT_SYSTEM) == 0) /* Delete from user registry */
1439 reg_key reg_user (KEY_ALL_ACCESS,
1440 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
1441 killres = reg_user.kill (posix_path);
1443 else /* Delete from system registry */
1445 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1446 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1447 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1448 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1451 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1457 killres = reg_sys.kill (posix_path);
1460 if (killres != ERROR_SUCCESS)
1462 __seterrno_from_win_error (killres);
1466 return 0; /* Success! */
1469 /* read_cygdrive_info_from_registry: Read the default prefix and flags
1470 to use when creating cygdrives from the special user registry
1471 location used to store cygdrive information. */
1474 mount_info::read_cygdrive_info_from_registry ()
1476 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1479 if (r.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1481 /* Didn't find it so write the default to the registry and use it. */
1482 write_cygdrive_info_to_registry ("/cygdrive", MOUNT_AUTO);
1486 /* Fetch cygdrive_flags from registry; returns MOUNT_AUTO on error. */
1487 cygdrive_flags = r.get_int ("cygdrive flags", MOUNT_AUTO);
1488 slashify (cygdrive, cygdrive, 1);
1489 cygdrive_len = strlen(cygdrive);
1493 /* write_cygdrive_info_to_registry: Write the default prefix and flags
1494 to use when creating cygdrives to the special user registry
1495 location used to store cygdrive information. */
1498 mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1500 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1503 /* Verify cygdrive prefix starts with a forward slash and if there's
1504 another character, it's not a slash. */
1505 if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
1506 (!isslash (cygdrive_prefix[0])) ||
1507 ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
1513 char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1];
1514 /* Ensure that there is never a final slash */
1515 nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
1517 r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
1518 r.set_int ("cygdrive flags", flags);
1520 /* This also needs to go in the in-memory copy of "cygdrive" */
1521 slashify (cygdrive_prefix, cygwin_shared->mount.cygdrive, 1);
1522 cygwin_shared->mount.cygdrive_flags = flags;
1523 cygwin_shared->mount.cygdrive_len = strlen(cygwin_shared->mount.cygdrive);
1529 mount_info::getmntent (int x)
1531 if (x < 0 || x >= nmounts)
1534 return mount[native_sorted[x]].getmntent ();
1537 static mount_item *mounts_for_sort;
1539 /* sort_by_posix_name: qsort callback to sort the mount entries. Sort
1540 user mounts ahead of system mounts to the same POSIX path. */
1541 /* FIXME: should the user should be able to choose whether to
1542 prefer user or system mounts??? */
1544 sort_by_posix_name (const void *a, const void *b)
1546 mount_item *ap = mounts_for_sort + (*((int*) a));
1547 mount_item *bp = mounts_for_sort + (*((int*) b));
1549 /* Base weighting on longest posix path first so that the most
1550 obvious path will be chosen. */
1551 size_t alen = strlen (ap->posix_path);
1552 size_t blen = strlen (bp->posix_path);
1554 int res = blen - alen;
1557 return res; /* Path lengths differed */
1559 /* The two paths were the same length, so just determine normal
1560 lexical sorted order. */
1561 res = strcmp (ap->posix_path, bp->posix_path);
1565 /* need to select between user and system mount to same POSIX path */
1566 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1575 /* sort_by_native_name: qsort callback to sort the mount entries. Sort
1576 user mounts ahead of system mounts to the same POSIX path. */
1577 /* FIXME: should the user should be able to choose whether to
1578 prefer user or system mounts??? */
1580 sort_by_native_name (const void *a, const void *b)
1582 mount_item *ap = mounts_for_sort + (*((int*) a));
1583 mount_item *bp = mounts_for_sort + (*((int*) b));
1585 /* Base weighting on longest win32 path first so that the most
1586 obvious path will be chosen. */
1587 size_t alen = strlen (ap->native_path);
1588 size_t blen = strlen (bp->native_path);
1590 int res = blen - alen;
1593 return res; /* Path lengths differed */
1595 /* The two paths were the same length, so just determine normal
1596 lexical sorted order. */
1597 res = strcasecmp (ap->posix_path, bp->posix_path);
1601 /* need to select between user and system mount to same POSIX path */
1602 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1614 for (int i = 0; i < nmounts; i++)
1615 native_sorted[i] = posix_sorted[i] = i;
1616 /* Sort them into reverse length order, otherwise we won't
1617 be able to look for /foo in /. */
1618 mounts_for_sort = mount; /* ouch. */
1619 qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
1620 qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
1623 /* Add an entry to the in-memory mount table.
1624 Returns 0 on success, -1 on failure and errno is set.
1626 This is where all argument validation is done. It may not make sense to
1627 do this when called internally, but it's cleaner to keep it all here. */
1630 mount_info::add_item (const char *native, const char *posix, unsigned mountflags)
1632 /* Can't add more than MAX_MOUNTS. */
1633 if (nmounts == MAX_MOUNTS)
1639 /* Something's wrong if either path is NULL or empty, or if it's
1640 not a UNC or absolute path. */
1642 if ((native == NULL) || (*native == 0) ||
1643 (posix == NULL) || (*posix == 0) ||
1644 (!slash_unc_prefix_p (native) && !isabspath (native)))
1650 /* Make sure both paths do not end in /. */
1651 char nativetmp[MAX_PATH];
1652 char posixtmp[MAX_PATH];
1654 if (slash_drive_prefix_p (native))
1655 slash_drive_to_win32_path (native, nativetmp, 0);
1658 backslashify (native, nativetmp, 0);
1659 nofinalslash (nativetmp, nativetmp);
1662 slashify (posix, posixtmp, 0);
1663 nofinalslash (posixtmp, posixtmp);
1665 debug_printf ("%s[%s], %s[%s], %p",
1666 native, nativetmp, posix, posixtmp, mountflags);
1668 /* Duplicate /'s in path are an error. */
1669 for (char *p = posixtmp + 1; *p; ++p)
1671 if (p[-1] == '/' && p[0] == '/')
1678 /* Write over an existing mount item with the same POSIX path if
1679 it exists and is from the same registry area. */
1680 for (int i = 0; i < nmounts; i++)
1682 if ((strcmp (mount[i].posix_path, posixtmp) == 0) &&
1683 ((mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM)))
1685 /* replace existing mount item */
1686 mount[i].init (nativetmp, posixtmp, mountflags);
1691 mount[nmounts++].init (nativetmp, posixtmp, mountflags);
1699 /* Delete a mount table entry where path is either a Win32 or POSIX
1700 path. Since the mount table is really just a table of aliases,
1701 deleting / is ok (although running without a slash mount is
1702 strongly discouraged because some programs may run erratically
1703 without one). If MOUNT_SYSTEM is set in flags, remove from system
1704 registry, otherwise remove the user registry mount.
1708 mount_info::del_item (const char *path, unsigned flags)
1710 char pathtmp[MAX_PATH];
1712 /* Something's wrong if path is NULL or empty. */
1713 if ((path == NULL) || (*path == 0))
1719 slashify (path, pathtmp, 0);
1720 nofinalslash (pathtmp, pathtmp);
1722 debug_printf ("%s[%s]", path, pathtmp);
1724 for (int i = 0; i < nmounts; i++)
1726 /* Delete if paths and mount locations match. */
1727 if (((strcmp (mount[i].posix_path, pathtmp) == 0
1728 || strcmp (mount[i].native_path, pathtmp) == 0)) &&
1729 ((mount[i].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM)))
1731 nmounts--; /* One less mount table entry */
1732 /* Fill in the hole if not at the end of the table */
1734 memcpy (mount + i, mount + i + 1,
1735 sizeof (mount[i]) * (nmounts - i));
1736 sort (); /* Resort the table */
1744 /* read_v1_mounts: Given a reg_key to an old mount table registry area,
1745 read in the mounts. The "which" arg contains zero if we're reading
1746 the user area and MOUNT_SYSTEM if we're reading the system area.
1747 This way we can store the mounts read in the appropriate place when
1748 they are written back to the new registry layout. */
1751 mount_info::read_v1_mounts (reg_key r, unsigned which)
1753 unsigned mountflags = 0;
1755 /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
1756 for (int i = 0; i < 30; i++)
1759 char win32path[MAX_PATH];
1760 char unixpath[MAX_PATH];
1762 __small_sprintf (key_name, "%02x", i);
1764 reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
1766 /* The registry names are historical but useful so are left alone. */
1767 k.get_string ("native", win32path, sizeof (win32path), "");
1768 k.get_string ("unix", unixpath, sizeof (unixpath), "");
1770 /* Does this entry contain something? */
1771 if (*win32path != 0)
1775 if (k.get_int ("fbinary", 0))
1776 mountflags |= MOUNT_BINARY;
1778 /* Or in zero or MOUNT_SYSTEM depending on which table
1780 mountflags |= which;
1782 cygwin_shared->mount.add_item (win32path, unixpath, mountflags);
1787 /* from_v1_registry: Build the entire mount table from the old v1 registry
1791 mount_info::from_v1_registry ()
1793 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
1803 /* First read mounts from user's table. */
1804 read_v1_mounts (r, 0);
1806 /* Then read mounts from system-wide mount table. */
1807 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
1814 read_v1_mounts (r1, MOUNT_SYSTEM);
1816 /* Note: we don't need to sort internal table here since it is
1817 done in main from_registry call after this function would be
1821 /* import_v1_mounts: If v1 mounts are present, load them and write
1822 the new entries to the new registry area. */
1825 mount_info::import_v1_mounts ()
1827 /* Read in old mounts into memory. */
1828 from_v1_registry ();
1830 /* Write all mounts to the new registry. */
1834 /* to_registry: For every mount point in memory, add a corresponding
1835 registry mount point. */
1838 mount_info::to_registry ()
1840 for (int i = 0; i < MAX_MOUNTS; i++)
1844 mount_item *p = mount + i;
1846 add_reg_mount (p->native_path, p->posix_path, p->flags);
1848 debug_printf ("%02x: %s, %s, %d",
1849 i, p->native_path, p->posix_path, p->flags);
1854 /************************* mount_item class ****************************/
1857 mount_item::getmntent ()
1860 struct mntent &ret=_reent_winsup()->_ret;
1862 static NO_COPY struct mntent ret;
1865 /* Pass back pointers to mount_info strings reserved for use by
1866 getmntent rather than pointers to strings in the internal mount
1867 table because the mount table might change, causing weird effects
1868 from the getmntent user's point of view. */
1870 strcpy (cygwin_shared->mount.mnt_fsname, native_path);
1871 ret.mnt_fsname = cygwin_shared->mount.mnt_fsname;
1872 strcpy (cygwin_shared->mount.mnt_dir, posix_path);
1873 ret.mnt_dir = cygwin_shared->mount.mnt_dir;
1875 if (!(flags & MOUNT_SYSTEM)) /* user mount */
1876 strcpy (cygwin_shared->mount.mnt_type, (char *) "user");
1877 else /* system mount */
1878 strcpy (cygwin_shared->mount.mnt_type, (char *) "system");
1880 if ((flags & MOUNT_AUTO)) /* cygdrive */
1881 strcat (cygwin_shared->mount.mnt_type, (char *) ",auto");
1883 ret.mnt_type = cygwin_shared->mount.mnt_type;
1885 /* mnt_opts is a string that details mount params such as
1886 binary or textmode, or exec. We don't print
1887 `silent' here; it's a magic internal thing. */
1889 if (! (flags & MOUNT_BINARY))
1890 strcpy (cygwin_shared->mount.mnt_opts, (char *) "textmode");
1892 strcpy (cygwin_shared->mount.mnt_opts, (char *) "binmode");
1894 if (flags & MOUNT_EXEC)
1895 strcat (cygwin_shared->mount.mnt_opts, (char *) ",exec");
1897 ret.mnt_opts = cygwin_shared->mount.mnt_opts;
1904 /* Fill in the fields of a mount table entry. */
1907 mount_item::init (const char *native, const char *posix, unsigned mountflags)
1909 strcpy ((char *) native_path, native);
1910 strcpy ((char *) posix_path, posix);
1912 native_pathlen = strlen (native_path);
1913 posix_pathlen = strlen (posix_path);
1918 /********************** Mount System Calls **************************/
1920 /* Mount table system calls.
1921 Note that these are exported to the application. */
1923 /* mount: Add a mount to the mount table in memory and to the registry
1924 that will cause paths under win32_path to be translated to paths
1925 under posix_path. */
1929 mount (const char *win32_path, const char *posix_path, unsigned flags)
1933 if (flags & MOUNT_AUTO) /* normal mount */
1935 /* When flags include MOUNT_AUTO, take this to mean that
1936 we actually want to change the cygdrive prefix and flags
1937 without actually mounting anything. */
1938 res = cygwin_shared->mount.write_cygdrive_info_to_registry (posix_path, flags);
1943 if (iscygdrive (posix_path))
1946 return res; /* Don't try to add cygdrive prefix. */
1949 res = cygwin_shared->mount.add_reg_mount (win32_path, posix_path, flags);
1952 cygwin_shared->mount.add_item (win32_path, posix_path, flags);
1955 syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
1959 /* umount: The standard umount call only has a path parameter. Since
1960 it is not possible for this call to specify whether to remove the
1961 mount from the user or global mount registry table, assume the user
1966 umount (const char *path)
1968 return cygwin_umount (path, 0);
1971 /* cygwin_umount: This is like umount but takes an additional flags
1972 parameter that specifies whether to umount from the user or system-wide
1977 cygwin_umount (const char *path, unsigned flags)
1979 int res = cygwin_shared->mount.del_reg_mount (path, flags);
1982 cygwin_shared->mount.del_item (path, flags);
1984 syscall_printf ("%d = cygwin_umount (%s, %d)", res, path, flags);
1989 #define iteration _reent_winsup()->_iteration
1991 static int iteration;
1996 setmntent (const char *filep, const char *)
1999 return (FILE *) filep;
2006 return cygwin_shared->mount.getmntent (iteration++);
2016 /********************** Symbolic Link Support **************************/
2018 /* Create a symlink from FROMPATH to TOPATH. */
2022 symlink (const char *topath, const char *frompath)
2027 path_conv win32_path (frompath, SYMLINK_NOFOLLOW);
2028 if (win32_path.error)
2030 set_errno (win32_path.error);
2034 syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
2041 if (strlen (topath) >= MAX_PATH)
2043 set_errno (ENAMETOOLONG);
2047 if (win32_path.is_device () ||
2048 win32_path.file_attributes () != (DWORD) -1)
2054 h = CreateFileA(win32_path.get_win32 (), GENERIC_WRITE, 0, &sec_none_nih,
2055 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
2056 if (h == INVALID_HANDLE_VALUE)
2060 char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10];
2062 __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
2063 DWORD len = strlen (buf) + 1;
2065 /* Note that the terminating nul is written. */
2067 if (!WriteFile (h, buf, len, &written, NULL) || written != len)
2071 DeleteFileA (win32_path.get_win32 ());
2076 set_file_attribute (win32_path.has_acls (),
2077 win32_path.get_win32 (),
2078 S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
2079 SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_SYSTEM);
2085 syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath);
2089 static __inline char *
2090 has_suffix (const char *path, const suffix_info *suffixes)
2092 char *ext = strrchr (path, '.');
2094 for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
2095 if (strcasematch (ext, ex->name))
2100 static __inline__ int
2101 next_suffix (char *ext_here, const suffix_info *&suffixes)
2106 while (suffixes && suffixes->name)
2107 if (!suffixes->addon)
2111 strcpy (ext_here, suffixes->name);
2118 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2120 If PATH is a symlink, put the value of the symlink--the file to
2121 which it points--into BUF. The value stored in BUF is not
2122 necessarily null terminated. BUFLEN is the length of BUF; only up
2123 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2124 which case nothing will be stored.
2126 Set *SYML if PATH is a symlink.
2128 Set *EXEC if PATH appears to be executable. This is an efficiency
2129 hack because we sometimes have to open the file anyhow. *EXEC will
2130 not be set for every executable file.
2132 Return -1 on error, 0 if PATH is not a symlink, or the length
2133 stored into BUF if PATH is a symlink. */
2136 symlink_info::check (const char *in_path, const suffix_info *suffixes)
2140 char extbuf[MAX_PATH + 5];
2141 const char *path = in_path;
2145 else if ((known_suffix = has_suffix (in_path, suffixes)) != NULL)
2152 path = strcpy (extbuf, in_path);
2153 ext_here = strchr (path, '\0');
2160 if (!next_suffix (ext_here, suffixes))
2162 fileattr = GetFileAttributesA (path);
2163 if (fileattr == (DWORD) -1)
2165 /* The GetFileAttributesA call can fail for reasons that don't
2166 matter, so we just return 0. For example, getting the
2167 attributes of \\HOST will typically fail. */
2168 debug_printf ("GetFileAttributesA (%s) failed", path);
2173 /* Windows allows path\. even when `path' isn't a directory.
2174 Detect this scenario and disallow it, since it is non-UNIX like. */
2175 char *p = strchr (path, '\0');
2176 if (p > path + 1 && p[-1] == '.' && SLASH_P (p[-2]) &&
2177 !(fileattr & FILE_ATTRIBUTE_DIRECTORY))
2179 debug_printf ("\\. specified on non-directory");
2180 set_errno (ENOTDIR);
2184 /* A symlink will have the `system' file attribute. */
2185 /* Only files can be symlinks (which can be symlinks to directories). */
2186 if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))
2187 goto file_not_symlink;
2189 /* Open the file. */
2191 h = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
2192 FILE_ATTRIBUTE_NORMAL, 0);
2194 syscall_printf ("opened '%s'(%p)", path, h);
2197 if (h == INVALID_HANDLE_VALUE)
2201 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2204 syscall_printf ("ReadFile");
2205 if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
2207 else if (got == sizeof (cookie_buf)
2208 && memcmp (cookie_buf, SYMLINK_COOKIE,
2209 sizeof (cookie_buf)) == 0)
2211 /* It's a symlink. */
2212 pflags = PATH_SYMLINK;
2214 res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2219 /* Versions prior to b16 stored several trailing
2220 NULs with the path (to fill the path out to 1024
2221 chars). Current versions only store one trailing
2222 NUL. The length returned is the path without
2223 *any* trailing NULs. We also have to handle (or
2224 at least not die from) corrupted paths. */
2225 if (memchr (contents, 0, got) != NULL)
2226 res = strlen (contents);
2231 else if (got == sizeof (cookie_buf)
2232 && memcmp (cookie_buf, SOCKET_COOKIE,
2233 sizeof (cookie_buf)) == 0)
2235 pflags |= PATH_SOCKET;
2236 goto close_and_return;
2240 /* Not a symlink, see if executable. */
2241 if (!(pflags & PATH_EXEC) && got >= 2 &&
2242 ((cookie_buf[0] == '#' && cookie_buf[1] == '!') ||
2243 (cookie_buf[0] == ':' && cookie_buf[1] == '\n')))
2244 pflags |= PATH_EXEC;
2246 syscall_printf ("close_and_return");
2248 goto file_not_symlink;
2252 syscall_printf ("breaking from loop");
2262 syscall_printf ("not a symlink");
2266 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2267 res, path, contents, pflags);
2272 /* readlink system call */
2276 readlink (const char *path, char *buf, int buflen)
2278 extern suffix_info stat_suffixes[];
2279 path_conv pathbuf (path, SYMLINK_CONTENTS, 0, stat_suffixes);
2283 set_errno (pathbuf.error);
2284 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2288 if (!pathbuf.issymlink ())
2290 if (pathbuf.fileattr != (DWORD) -1)
2295 int len = strlen (pathbuf.get_win32 ());
2296 if (len > (buflen - 1))
2298 set_errno (ENAMETOOLONG);
2301 memcpy (buf, pathbuf.get_win32 (), len);
2304 /* errno set by symlink.check if error */
2308 /* Some programs rely on st_dev/st_ino being unique for each file.
2309 Hash the path name and hope for the best. The hash arg is not
2310 always initialized to zero since readdir needs to compute the
2311 dirent ino_t based on a combination of the hash of the directory
2312 done during the opendir call and the hash or the filename within
2313 the directory. FIXME: Not bullet-proof. */
2314 /* Cygwin internal */
2316 unsigned long __stdcall
2317 hash_path_name (unsigned long hash, const char *name)
2322 /* Perform some initial permutations on the pathname if this is
2326 /* Simplistic handling of drives. If there is a drive specified,
2327 make sure that the initial letter is upper case. If there is
2328 no \ after the ':' assume access through the root directory
2330 FIXME: Should really honor MS-Windows convention of using
2331 the environment to track current directory on various drives. */
2334 char *nn, *newname = (char *) alloca (strlen (name) + 2);
2335 nn = strncpy (newname, name, 2);
2337 *newname = toupper (*nn);
2350 /* Fill out the hashed path name with the current working directory if
2351 this is not an absolute path and there is no pre-specified hash value.
2352 Otherwise the inodes same will differ depending on whether a file is
2353 referenced with an absolute value or relatively. */
2355 if (*name != '\\' && (current_directory_name == NULL ||
2356 get_current_directory_name ()))
2358 hash = current_directory_hash;
2359 if (name[0] == '.' && name[1] == '\0')
2361 hash = hash_path_name (hash, "\\");
2366 /* Build up hash. Ignore single trailing slash or \a\b\ != \a\b or
2367 \a\b\. but allow a single \ if that's all there is. */
2370 hash += *name + (*name << 17);
2373 while (*++name != '\0' &&
2374 !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
2379 get_current_directory_name ()
2383 for (dlen = 256; ; dlen *= 2)
2385 current_directory_name = (char *) realloc (current_directory_name, dlen + 2);
2386 if ((len = GetCurrentDirectoryA (dlen, current_directory_name)) < dlen)
2393 current_directory_hash = hash_path_name (0, current_directory_name);
2401 getcwd_inner (char *buf, size_t ulen, int posix_p)
2403 char *resbuf = NULL;
2406 if (current_directory_name == NULL && !get_current_directory_name ())
2411 if (strlen (current_directory_name) >= len)
2415 strcpy (buf, current_directory_name);
2419 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, win32) (cached)",
2420 resbuf, resbuf ? resbuf : "", buf, len);
2423 else if (current_directory_posix_name != NULL)
2425 if (strlen (current_directory_posix_name) >= len)
2429 strcpy (buf, current_directory_posix_name);
2433 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, posix) (cached)",
2434 resbuf, resbuf ? resbuf : "", buf, len);
2438 /* posix_p required and current_directory_posix_name == NULL */
2440 char temp[MAX_PATH];
2442 /* Turn from Win32 style to our style. */
2443 cygwin_shared->mount.conv_to_posix_path (current_directory_name, temp, 0);
2445 size_t tlen = strlen (temp);
2447 current_directory_posix_name = (char *) realloc (
2448 current_directory_posix_name, tlen + 1);
2449 if (current_directory_posix_name != NULL)
2450 strcpy (current_directory_posix_name, temp);
2454 /* len was too small */
2463 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, %s)",
2464 resbuf, resbuf ? resbuf : "",
2465 buf, len, posix_p ? "posix" : "win32");
2470 getcwd (char *buf, size_t ulen)
2474 if (buf == NULL || ulen == 0)
2476 buf = (char *) alloca (MAX_PATH);
2477 res = getcwd_inner (buf, MAX_PATH, 1);
2482 res = getcwd_inner (buf, ulen, 1);
2488 /* getwd: standards? */
2493 return getcwd (buf, MAX_PATH);
2496 /* chdir: POSIX 5.2.1.1 */
2499 chdir (const char *dir)
2501 path_conv path (dir);
2505 set_errno (path.error);
2506 syscall_printf ("-1 = chdir (%s)", dir);
2510 char *native_dir = path.get_win32 ();
2512 /* Check to see if path translates to something like C:.
2513 If it does, append a \ to the native directory specification to
2514 defeat the Windows 95 (i.e. MS-DOS) tendency of returning to
2515 the last directory visited on the given drive. */
2516 if (isalpha (native_dir[0]) && native_dir[1] == ':' && !native_dir[2])
2518 native_dir[2] = '\\';
2519 native_dir[3] = '\0';
2521 int res = SetCurrentDirectoryA (native_dir);
2525 /* Clear the cache until we need to retrieve the directory again. */
2526 if (current_directory_name != NULL)
2528 free (current_directory_name);
2529 current_directory_name = NULL;
2531 if (current_directory_posix_name != NULL)
2533 free (current_directory_posix_name);
2534 current_directory_posix_name = NULL;
2537 syscall_printf ("%d = chdir (%s) (dos %s)", res ? 0 : -1, dir, native_dir);
2538 return res ? 0 : -1;
2541 /******************** Exported Path Routines *********************/
2543 /* Cover functions to the path conversion routines.
2544 These are exported to the world as cygwin_foo by cygwin.din. */
2548 cygwin_conv_to_win32_path (const char *path, char *win32_path)
2550 path_conv p (path, SYMLINK_FOLLOW, 0);
2553 set_errno (p.error);
2557 strcpy (win32_path, p.get_win32 ());
2563 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
2565 path_conv p (path, SYMLINK_FOLLOW, 1);
2568 set_errno (p.error);
2572 strcpy (win32_path, p.get_win32 ());
2576 /* This is exported to the world as cygwin_foo by cygwin.din. */
2580 cygwin_conv_to_posix_path (const char *path, char *posix_path)
2582 if (check_null_empty_path_errno (path))
2584 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 1);
2590 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
2592 if (check_null_empty_path_errno (path))
2594 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 0);
2598 /* The realpath function is supported on some UNIX systems. */
2602 realpath (const char *path, char *resolved)
2606 path_conv real_path (path, SYMLINK_FOLLOW, 1);
2608 if (real_path.error)
2609 err = real_path.error;
2612 err = cygwin_shared->mount.conv_to_posix_path (real_path.get_win32 (), resolved, 0);
2617 /* FIXME: on error, we are supposed to put the name of the path
2618 component which could not be resolved into RESOLVED. */
2625 /* Return non-zero if path is a POSIX path list.
2626 This is exported to the world as cygwin_foo by cygwin.din.
2629 <sect1 id="add-func-cygwin-posix-path-list-p">
2630 <para>Rather than use a mode to say what the "proper" path list
2631 format is, we allow any, and give apps the tools they need to
2632 convert between the two. If a ';' is present in the path list it's
2633 a Win32 path list. Otherwise, if the first path begins with
2634 [letter]: (in which case it can be the only element since if it
2635 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
2636 it's a POSIX path list.</para>
2643 cygwin_posix_path_list_p (const char *path)
2645 int posix_p = ! (strchr (path, ';')
2646 || (isalpha (path[0]) && path[1] == ':'));
2650 /* These are used for apps that need to convert env vars like PATH back and
2651 forth. The conversion is a two step process. First, an upper bound on the
2652 size of the buffer needed is computed. Then the conversion is done. This
2653 allows the caller to use alloca if it wants. */
2656 conv_path_list_buf_size (const char *path_list, int to_posix_p)
2658 int i, num_elms, max_mount_path_len, size;
2661 /* The theory is that an upper bound is
2662 current_size + (num_elms * max_mount_path_len) */
2664 char delim = to_posix_p ? ';' : ':';
2666 for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms)
2669 /* 7: strlen ("//c") + slop, a conservative initial value */
2670 for (max_mount_path_len = 7, i = 0; i < cygwin_shared->mount.nmounts; ++i)
2672 int mount_len = (to_posix_p
2673 ? cygwin_shared->mount.mount[i].posix_pathlen
2674 : cygwin_shared->mount.mount[i].native_pathlen);
2675 if (max_mount_path_len < mount_len)
2676 max_mount_path_len = mount_len;
2680 size = strlen (path_list) + (num_elms * max_mount_path_len) + 100;
2686 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
2688 return conv_path_list_buf_size (path_list, 1);
2693 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
2695 return conv_path_list_buf_size (path_list, 0);
2700 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
2702 conv_path_list (win32, posix, 1);
2708 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
2710 conv_path_list (posix, win32, 0);
2714 /* cygwin_split_path: Split a path into directory and file name parts.
2715 Buffers DIR and FILE are assumed to be big enough.
2717 Examples (path -> `dir' / `file'):
2720 . -> `.' / `.' (FIXME: should this be `.' / `'?)
2721 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
2723 foo/bar -> `foo' / `bar'
2724 foo/bar/ -> `foo' / `bar'
2726 /foo/bar -> `/foo' / `bar'
2729 c:foo -> `c:/' / `foo'
2730 c:/foo -> `c:/' / `foo'
2735 cygwin_split_path (const char *path, char *dir, char *file)
2737 int dir_started_p = 0;
2739 /* Deal with drives.
2740 Remember that c:foo <==> c:/foo. */
2741 if (isalpha (path[0]) && path[1] == ':')
2752 if (SLASH_P (*path))
2757 /* Determine if there are trailing slashes and "delete" them if present.
2758 We pretend as if they don't exist. */
2759 const char *end = path + strlen (path);
2760 /* path + 1: keep leading slash. */
2761 while (end > path + 1 && SLASH_P (end[-1]))
2764 /* At this point, END points to one beyond the last character
2765 (with trailing slashes "deleted"). */
2767 /* Point LAST_SLASH at the last slash (duh...). */
2768 const char *last_slash;
2769 for (last_slash = end - 1; last_slash >= path; --last_slash)
2770 if (SLASH_P (*last_slash))
2773 if (last_slash == path)
2778 else if (last_slash > path)
2780 memcpy (dir, path, last_slash - path);
2781 dir[last_slash - path] = 0;
2786 ; /* nothing to do */
2792 memcpy (file, last_slash + 1, end - last_slash - 1);
2793 file[end - last_slash - 1] = 0;
2796 /********************** String Helper Functions ************************/
2798 #define CHXOR ('a' ^ 'A')
2799 #define ch_case_eq(ch1, ch2) \
2802 !((x = ((unsigned char)ch1 ^ (unsigned char)ch2)) && \
2803 (x != CHXOR || !isalpha (ch1))); \
2807 strncasematch (const char *s1, const char *s2, size_t n)
2815 if (!ch_case_eq (*s1, *s2))
2819 return !n || *s2 == '\0';
2823 strcasematch (const char *s1, const char *s2)
2830 if (!ch_case_eq (*s1, *s2))
2838 strcasestr (const char *searchee, const char *lookfor)
2844 return (char *) searchee;
2852 if (lookfor[i] == 0)
2853 return (char *) searchee;
2855 if (!ch_case_eq (lookfor[i], searchee[i]))