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 Text vs Binary issues are not considered here in path style
51 / and \ are treated as equivalent. One or the other is prefered in
52 certain situations (e.g. / is preferred in result of getcwd, \ is
53 preferred in arguments to Win32 api calls), but this code will
54 translate as necessary.
56 Apps wishing to translate to/from pure Win32 and POSIX-like
57 pathnames can use cygwin_foo.
59 Removing mounted filesystem support would simplify things greatly,
60 but having it gives us a mechanism of treating disk that lives on a
61 UNIX machine as having UNIX semantics [it allows one to edit a text
62 file on that disk and not have cr's magically appear and perhaps
63 break apps running on UNIX boxes]. It also useful to be able to
64 layout a hierarchy without changing the underlying directories.
66 The semantics of mounting file systems is not intended to precisely
67 follow normal UNIX systems.
69 Each DOS drive is defined to have a current directory. Supporting
70 this would complicate things so for now things are defined so that
76 #include <sys/mount.h>
84 static int normalize_win32_path (const char *cwd, const char *src, char *dst);
85 static char *getcwd_inner (char *buf, size_t ulen, int posix_p);
86 static void slashify (const char *src, char *dst, int trailing_slash_p);
87 static void backslashify (const char *src, char *dst, int trailing_slash_p);
88 static int path_prefix_p_ (const char *path1, const char *path2, int len1);
89 static int get_current_directory_name ();
91 static NO_COPY const char escape_char = '^';
95 char buf[3 + MAX_PATH * 3];
102 symlink_info (): known_suffix (NULL), contents (buf + MAX_PATH + 1) {}
103 int check (const char *path, const suffix_info *suffixes);
106 /********************** Path Helper Functions *************************/
108 #define path_prefix_p(p1, p2, l1) \
109 ((tolower(*(p1))==tolower(*(p2))) && \
110 path_prefix_p_(p1, p2, l1))
112 #define SYMLINKATTR(x) \
113 (((x) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) == \
114 FILE_ATTRIBUTE_SYSTEM)
116 /* Return non-zero if PATH1 is a prefix of PATH2.
117 Both are assumed to be of the same path style and / vs \ usage.
119 LEN1 = strlen (PATH1). It's passed because often it's already known.
122 /foo/ is a prefix of /foo <-- may seem odd, but desired
123 /foo is a prefix of /foo/
124 / is a prefix of /foo/bar
125 / is not a prefix of foo/bar
126 foo/ is a prefix foo/bar
127 /foo is not a prefix of /foobar
130 /* Determine if path prefix matches current cygdrive */
131 #define iscygdrive(path) \
132 (path_prefix_p (cygwin_shared->mount.cygdrive, (path), cygwin_shared->mount.cygdrive_len))
134 #define iscygdrive_device(path) \
135 (iscygdrive(path) && isalpha(path[cygwin_shared->mount.cygdrive_len]) && \
136 (isdirsep(path[cygwin_shared->mount.cygdrive_len + 1]) || \
137 !path[cygwin_shared->mount.cygdrive_len + 1]))
139 /******************** Directory-related Support **************************/
141 /* Cache getcwd value. FIXME: We need a lock for these in order to
142 support multiple threads. */
145 #define current_directory_name _reent_winsup()->_current_directory_name
146 #define current_directory_posix_name _reent_winsup()->_current_directory_posix_name
147 #define current_directory_hash _reent_winsup()->_current_directory_hash
149 static char *current_directory_name;
150 static char *current_directory_posix_name;
151 static unsigned long current_directory_hash;
155 path_prefix_p_ (const char *path1, const char *path2, int len1)
157 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
158 if (len1 > 0 && SLASH_P (path1[len1 - 1]))
162 return SLASH_P (path2[0]) && !SLASH_P (path2[1]);
164 if (!strncasematch (path1, path2, len1))
167 return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
170 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
171 passing to Win32 API routines.
173 If an error occurs, `error' is set to the errno value.
174 Otherwise it is set to 0.
177 SYMLINK_FOLLOW - convert to PATH symlink points to
178 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
179 SYMLINK_IGNORE - do not check PATH for symlinks
180 SYMLINK_CONTENTS - just return symlink contents
184 path_conv::check (const char *src, symlink_follow follow_mode,
185 int use_full_path, const suffix_info *suffixes)
187 /* This array is used when expanding symlinks. It is MAX_PATH * 2
188 in length so that we can hold the expanded symlink plus a
190 char path_buf[MAX_PATH];
191 char path_copy[MAX_PATH];
194 char *rel_path, *full_path;
196 if ((error = check_null_empty_path (src)))
200 rel_path = path_buf, full_path = this->path;
202 rel_path = this->path, full_path = path_buf;
204 /* This loop handles symlink expansion. */
208 fileattr = (DWORD) -1;
212 /* Must look up path in mount table, etc. */
213 error = cygwin_shared->mount.conv_to_win32_path (src, rel_path,
215 devn, unit, &path_flags);
225 /* Eat trailing slashes */
226 char *tail = strchr (full_path, '\0');
227 /* If path is only a drivename, Windows interprets it as
228 the current working directory on this drive instead of
229 the root dir which is what we want. So we need
230 the trailing backslash in this case. */
231 while (tail > full_path + 3 && (*--tail == '\\'))
233 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
234 strcat (full_path, "\\");
236 if (follow_mode == SYMLINK_IGNORE)
238 fileattr = GetFileAttributesA (path);
242 /* Make a copy of the path that we can munge up */
243 strcpy (path_copy, full_path);
245 tail = path_copy + 1 + (tail - full_path); // Point to end of copy
247 /* Scan path_copy from right to left looking either for a symlink
248 or an actual existing file. If an existing file is found, just
249 return. If a symlink is found exit the for loop.
250 Also: be careful to preserve the errno returned from
251 symlink.check as the caller may need it. */
252 /* FIXME: Do we have to worry about multiple \'s here? */
253 int component = 0; // Number of translated components
254 sym.contents[0] = '\0';
259 const suffix_info *suff;
261 /* Don't allow symlink.check to set anything in the path_conv
262 class if we're working on an inner component of the path */
271 sym.pflags = path_flags;
274 int len = sym.check (path_copy, suff);
277 path_flags = sym.pflags;
279 /* If symlink.check found an existing non-symlink file, then
280 it returns a length of 0 and sets errno to EINVAL. It also sets
281 any suffix found into `ext_here'. */
282 if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
286 fileattr = sym.fileattr;
289 goto out; // file found
291 /* Found a symlink if len > 0. If component == 0, then the
292 src path itself was a symlink. If !follow_mode then
293 we're done. Otherwise we have to insert the path found
294 into the full path that we are building and perform all of
295 these operations again on the newly derived path. */
298 if (component == 0 && follow_mode != SYMLINK_FOLLOW)
300 set_symlink (); // last component of path is a symlink.
301 fileattr = sym.fileattr;
302 if (follow_mode == SYMLINK_CONTENTS)
303 strcpy (path, sym.contents);
309 /* No existing file found. */
310 s.reset (); // remember errno from symlink.check
312 if (!(tail = strrchr (path_copy, '\\')) ||
313 (tail > path_copy && tail[-1] == ':'))
314 goto out; // all done
316 /* Haven't found a valid pathname component yet.
317 Pinch off the tail and try again. */
322 /* Arrive here if above loop detected a symlink. */
323 if (++loop > MAX_LINK_DEPTH)
325 error = ELOOP; // Eep.
330 tail = full_path + (tail - path_copy);
331 int taillen = strlen (tail);
332 int buflen = strlen (sym.contents);
333 if (buflen + taillen > MAX_PATH)
335 error = ENAMETOOLONG;
336 strcpy (path, "::ENAMETOOLONG::");
340 /* Copy tail of full_path to discovered symlink. */
342 for (p = sym.contents + buflen; *tail; tail++)
343 *p++ = *tail == '\\' ? '/' : *tail;
346 /* If symlink referred to an absolute path, then we
347 just use sym.contents and loop. Otherwise tack the head of
348 path_copy before sym.contents and translate it back from a
349 Win32-style path to a POSIX-style one. */
350 if (isabspath (sym.contents))
352 else if (!(tail = strrchr (path_copy, '\\')))
353 system_printf ("problem parsing %s - '%s'", src, full_path);
356 char tmp_buf[MAX_PATH];
357 int headlen = 1 + tail - path_copy;
358 p = sym.contents - headlen;
359 memcpy (p, path_copy, headlen);
361 error = cygwin_shared->mount.conv_to_posix_path (p, tmp_buf, 1);
370 if (sym.known_suffix)
371 known_suffix = this->path + (sym.known_suffix - path_copy);
372 else if (sym.ext_here && follow_mode != SYMLINK_CONTENTS)
374 known_suffix = strchr (this->path, '\0');
375 strcpy (known_suffix, sym.ext_here);
379 DWORD serial, volflags;
381 char root[strlen(full_path) + 10];
382 strcpy (root, full_path);
383 if (!rootdir (root) ||
384 !GetVolumeInformation (root, NULL, 0, &serial, NULL, &volflags, NULL, 0))
386 debug_printf ("GetVolumeInformation(%s) = ERR, full_path(%s), set_has_acls(FALSE)",
387 root, full_path, GetLastError ());
388 set_has_acls (FALSE);
392 debug_printf ("GetVolumeInformation(%s) = OK, full_path(%s), set_has_acls(%d)",
393 root, full_path, volflags & FS_PERSISTENT_ACLS);
394 set_has_acls (volflags & FS_PERSISTENT_ACLS);
398 #define deveq(s) (strcasematch (name, (s)))
399 #define deveqn(s, n) (strncasematch (name, (s), (n)))
402 digits (const char *name)
405 int n = strtol(name, &p, 10);
407 return p > name && !*p ? n : -1;
410 const char *windows_device_names[] =
437 get_raw_device_number (const char *uxname, const char *w32path, int &unit)
441 if (strncasecmp (w32path, "\\\\.\\tape", 8) == 0)
444 unit = digits (w32path + 8);
445 // norewind tape devices have leading n in name
446 if (! strncasecmp (uxname, "/dev/n", 6))
449 else if (isalpha (w32path[4]) && w32path[5] == ':')
452 unit = tolower (w32path[4]) - 'a';
454 else if (strncasecmp (w32path, "\\\\.\\physicaldrive", 17) == 0)
457 unit = digits (w32path + 17) + 128;
463 get_device_number (const char *name, int &unit, BOOL from_conv)
468 if ((*name == '/' && deveqn ("/dev/", 5)) ||
469 (*name == '\\' && deveqn ("\\dev\\", 5)))
474 if (tty_attached (myself))
479 else if (myself->ctty > 0)
482 else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
484 else if (deveq ("ttym"))
486 else if (deveq ("ptmx"))
488 else if (deveq ("windows"))
490 else if (deveq ("conin"))
492 else if (deveq ("conout"))
494 else if (deveq ("null"))
496 else if (deveq ("zero"))
498 else if (deveq ("random") || deveq ("urandom"))
501 unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
503 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
505 else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew"))
507 else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket")
508 || deveq ("dgsocket"))
510 else if (! from_conv)
511 devn = get_raw_device_number (name - 5,
513 SYMLINK_IGNORE).get_win32 (),
516 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
522 /* Return TRUE if src_path is a Win32 device name, filling out the device
523 name in win32_path */
526 win32_device_name (const char *src_path, char *win32_path,
527 DWORD &devn, int &unit)
531 devn = get_device_number (src_path, unit, TRUE);
536 if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL)
538 if (devn == FH_RANDOM)
539 __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
541 __small_sprintf (win32_path, devfmt, unit);
545 /* Normalize a POSIX path.
546 \'s are converted to /'s in the process.
547 All duplicate /'s, except for 2 leading /'s, are deleted.
548 The result is 0 for success, or an errno error value. */
550 #define isslash(c) ((c) == '/')
553 normalize_posix_path (const char *cwd, const char *src, char *dst)
555 const char *src_start = src;
556 char *dst_start = dst;
558 if (!isslash (src[0]))
560 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
562 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
566 dst = strchr (dst, '\0');
569 if (dst == dst_start + 1)
573 if (dst > dst_start && !isslash (dst[-1]))
576 /* Two leading /'s? If so, preserve them. */
577 else if (isslash (src[1]))
583 { /* Starts with three or more slashes - reset. */
592 /* Strip runs of /'s. */
599 while (isslash (*src))
608 if ((src[1] && !isslash (src[1])))
613 if (src[2] && !isslash (src[2]))
615 while (dst > dst_start && !isslash (*--dst))
626 if (--dst > dst_start && isslash (*dst))
629 debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start);
633 /* Normalize a Win32 path.
634 /'s are converted to \'s in the process.
635 All duplicate \'s, except for 2 leading \'s, are deleted.
637 The result is 0 for success, or an errno error value.
638 FIXME: A lot of this should be mergeable with the POSIX critter. */
641 normalize_win32_path (const char *cwd, const char *src, char *dst)
643 const char *src_start = src;
644 char *dst_start = dst;
646 if (!SLASH_P (src[0]) && strchr (src, ':') == NULL)
648 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
650 debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
655 if (!*cwd || !SLASH_P (dst[-1]))
658 /* Two leading \'s? If so, preserve them. */
659 else if (SLASH_P (src[0]) && SLASH_P (src[1]))
667 /* Strip duplicate /'s. */
668 if (SLASH_P (src[0]) && SLASH_P (src[1]))
671 else if (src[0] == '.' && SLASH_P (src[1])
672 && (src == src_start || SLASH_P (src[-1])))
677 /* Backup if "..". */
678 else if (src[0] == '.' && src[1] == '.'
679 /* dst must be greater than dst_start */
681 && (SLASH_P (src[2]) || src[2] == 0))
683 /* Back up over /, but not if it's the first one. */
684 if (dst > dst_start + 1)
686 /* Now back up to the next /. */
687 while (dst > dst_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
693 /* Otherwise, add char to result. */
704 debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
709 /* Various utilities. */
711 /* slashify: Convert all back slashes in src path to forward slashes
712 in dst path. Add a trailing slash to dst when trailing_slash_p arg
716 slashify (const char *src, char *dst, int trailing_slash_p)
718 const char *start = src;
730 && !isdirsep (src[-1]))
735 /* backslashify: Convert all forward slashes in src path to back slashes
736 in dst path. Add a trailing slash to dst when trailing_slash_p arg
740 backslashify (const char *src, char *dst, int trailing_slash_p)
742 const char *start = src;
754 && !isdirsep (src[-1]))
759 /* nofinalslash: Remove trailing / and \ from SRC (except for the
760 first one). It is ok for src == dst. */
763 nofinalslash (const char *src, char *dst)
765 int len = strlen (src);
767 memcpy (dst, src, len + 1);
768 while (len > 1 && SLASH_P (dst[--len]))
772 /* slash_drive_prefix_p: Return non-zero if PATH begins with
776 slash_drive_prefix_p (const char *path)
778 return (isdirsep(path[0])
781 && (path[3] == 0 || path[3] == '/'));
784 /* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
787 slash_unc_prefix_p (const char *path)
790 int ret = (isdirsep (path[0])
791 && isdirsep (path[1])
794 && !isdirsep (path[3])
795 && ((p = strchr(&path[3], '/')) != NULL));
796 if (!ret || p == NULL)
798 return ret && isalnum (p[1]);
801 /* conv_path_list: Convert a list of path names to/from Win32/POSIX.
803 SRC is not a const char * because we temporarily modify it to ease
806 I believe Win32 always has '.' in $PATH. POSIX obviously doesn't.
807 We certainly don't want to handle that here, but it is something for
808 the caller to think about. */
811 conv_path_list (const char *src, char *dst, int to_posix_p)
815 char src_delim = to_posix_p ? ';' : ':';
816 char dst_delim = to_posix_p ? ':' : ';';
817 int (*conv_fn) (const char *, char *) = (to_posix_p
818 ? cygwin_conv_to_posix_path
819 : cygwin_conv_to_win32_path);
823 s = strchr (src, src_delim);
827 (*conv_fn) (src[0] != 0 ? src : ".", d);
836 (*conv_fn) (src[0] != 0 ? src : ".", d);
842 /************************* mount_info class ****************************/
844 /* init: Initialize the mount table. */
852 had_to_create_mount_areas = 0;
854 /* Fetch the mount table and cygdrive-related information from
858 /* If slash isn't already mounted, mount system directory as slash. */
860 for (int i = 0; i < nmounts; i++)
862 if (strcmp (mount[i].posix_path, "/") == 0)
873 /* mount_slash: mount the system partition as slash. */
876 mount_info::mount_slash ()
878 char drivestring[MAX_PATH];
879 GetSystemDirectory (drivestring, MAX_PATH);
880 drivestring[2] = 0; /* truncate path to "<drive>:" */
882 if (add_reg_mount (drivestring, "/", 0) == 0)
883 add_item (drivestring, "/", 0);
886 /* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
887 the result in win32_path.
889 If win32_path != NULL, the relative path, if possible to keep, is
890 stored in win32_path. If the relative path isn't possible to keep,
891 the full path is stored.
893 If full_win32_path != NULL, the full path is stored there.
895 The result is zero for success, or an errno value.
897 {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */
900 mount_info::conv_to_win32_path (const char *src_path, char *win32_path,
901 char *full_win32_path, DWORD &devn, int &unit,
904 int src_path_len = strlen (src_path);
905 int trailing_slash_p = (src_path_len > 0
906 && SLASH_P (src_path[src_path_len - 1]));
909 unsigned dummy_flags;
915 flags = &dummy_flags;
918 debug_printf ("conv_to_win32_path (%s)", src_path);
920 if (src_path_len >= MAX_PATH)
922 debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path);
928 mount_item *mi = NULL; /* initialized to avoid compiler warning */
929 char pathbuf[MAX_PATH];
932 getcwd_inner (cwd, MAX_PATH, TRUE); /* FIXME: check rc */
934 /* Determine where the destination should be placed. */
935 if (full_win32_path != NULL)
936 dst = full_win32_path;
937 else if (win32_path != NULL)
941 goto out; /* Sanity check. */
943 /* An MS-DOS spec has either a : or a \. If this is found, short
944 circuit most of the rest of this function. */
945 if (strpbrk (src_path, ":\\") != NULL)
947 debug_printf ("%s already win32", src_path);
948 rc = normalize_win32_path (current_directory_name, src_path, dst);
951 debug_printf ("normalize_win32_path failed, rc %d", rc);
954 isrelpath = !isabspath (src_path);
955 *flags = set_flags_from_win32_path (dst);
959 /* Normalize the path, taking out ../../ stuff, we need to do this
960 so that we can move from one mounted directory to another with relative
963 eg mounting c:/foo /foo
969 should look in c:/foo, not d:/foo.
971 We do this by first getting an absolute UNIX-style path and then
972 converting it to a DOS-style path, looking up the appropriate drive
973 in the mount table. */
975 /* No need to fetch cwd if path is absolute. */
976 isrelpath = !isslash (*src_path);
978 rc = normalize_posix_path (cwd, src_path, pathbuf);
982 debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
987 /* See if this is a cygwin "device" */
988 if (win32_device_name (pathbuf, dst, devn, unit))
990 *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */
994 /* Check if the cygdrive prefix was specified. If so, just strip
995 off the prefix and transform it into an MS-DOS path. */
997 if (iscygdrive_device (pathbuf))
999 if (!cygdrive_win32_path (pathbuf, dst, trailing_slash_p))
1001 *flags = cygdrive_flags;
1005 /* Check the mount table for prefix matches. */
1006 for (i = 0; i < nmounts; i++)
1008 mi = mount + posix_sorted[i];
1009 if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen))
1015 if (slash_drive_prefix_p (pathbuf))
1016 slash_drive_to_win32_path (pathbuf, dst, trailing_slash_p);
1018 backslashify (pathbuf, dst, trailing_slash_p); /* just convert */
1023 int n = mi->native_pathlen;
1024 memcpy (dst, mi->native_path, n);
1025 char *p = pathbuf + mi->posix_pathlen;
1026 if (!trailing_slash_p && !*p)
1030 /* Do not add trailing \ to UNC device names like \\.\a: */
1031 if (*p != '/' && /* FIXME: this test seems wrong. */
1032 (strncmp (mi->native_path, "\\\\.\\", 4) != 0 ||
1033 strncmp (mi->native_path + 4, "UNC\\", 4) == 0))
1035 strcpy (dst + n, p);
1037 backslashify (dst, dst, trailing_slash_p);
1042 /* Compute relative path if asked to and able to. */
1044 cwdlen = 0; /* avoid a (hopefully) bogus compiler warning */
1045 if (win32_path == NULL)
1046 /* nothing to do */;
1047 else if (isrelpath &&
1048 path_prefix_p (current_directory_name, dst,
1049 cwdlen = strlen (current_directory_name)))
1051 if (strlen (dst) == cwdlen)
1054 dst += isdirsep (current_directory_name[cwdlen - 1]) ? cwdlen : cwdlen + 1;
1056 memmove (win32_path, dst, strlen (dst) + 1);
1059 strcpy (win32_path, ".");
1060 if (trailing_slash_p)
1061 strcat (win32_path, "\\");
1064 else if (win32_path != dst)
1065 strcpy (win32_path, dst);
1069 debug_printf ("%s(rel), %s(abs) %p(flags) = conv_to_win32_path (%s)",
1070 win32_path, full_win32_path, *flags,
1075 /* Convert PATH (for which slash_drive_prefix_p returns 1) to WIN32 form. */
1078 mount_info::slash_drive_to_win32_path (const char *path, char *buf,
1079 int trailing_slash_p)
1084 strcpy (buf + 2, "\\");
1086 backslashify (path + 3, buf + 2, trailing_slash_p);
1089 /* cygdrive_posix_path: Build POSIX path used as the
1090 mount point for cygdrives created when there is no other way to
1091 obtain a POSIX path from a Win32 one. */
1094 mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
1096 int len = cygdrive_len;
1098 memcpy (dst, cygdrive, len + 1);
1100 /* Now finish the path off with the drive letter to be used.
1101 The cygdrive prefix always ends with a trailing slash so
1102 the drive letter is added after the path. */
1103 dst[len++] = tolower (src[0]);
1105 dst[len++] = '\000';
1109 strcpy (dst + len, src + 3);
1111 slashify (dst, dst, trailing_slash_p);
1115 mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
1117 const char *p = src + cygdrive_len;
1118 if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
1122 strcpy (dst + 2, p + 1);
1123 backslashify (dst, dst, trailing_slash_p || !dst[2]);
1124 debug_printf ("src '%s', dst '%s'", src, dst);
1128 /* conv_to_posix_path: Ensure src_path is a POSIX path.
1130 The result is zero for success, or an errno value.
1131 posix_path must have sufficient space (i.e. MAX_PATH bytes).
1132 If keep_rel_p is non-zero, relative paths stay that way. */
1135 mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
1138 int src_path_len = strlen (src_path);
1139 int trailing_slash_p = (src_path_len > 0
1140 && SLASH_P (src_path[src_path_len - 1]));
1141 int relative_path_p = (! SLASH_P (*src_path)
1142 && strchr (src_path, ':') == NULL);
1144 debug_printf ("conv_to_posix_path (%s, %s)", src_path,
1145 keep_rel_p ? "keep-rel" : "no-keep-rel");
1148 if (src_path_len >= MAX_PATH)
1150 debug_printf ("ENAMETOOLONG");
1151 return ENAMETOOLONG;
1154 /* FIXME: For now, if the path is relative and it's supposed to stay
1155 that way, skip mount table processing. */
1157 if (keep_rel_p && relative_path_p)
1159 slashify (src_path, posix_path, 0);
1160 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1164 char pathbuf[MAX_PATH];
1167 /* No need to fetch cwd if path is absolute. */
1168 if (relative_path_p)
1169 getcwd_inner (cwd, MAX_PATH, 0); /* FIXME: check rc */
1171 strcpy (cwd, "/"); /* some innocuous value */
1173 int rc = normalize_win32_path (cwd, src_path, pathbuf);
1176 debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1180 int pathbuflen = strlen (pathbuf);
1181 for (int i = 0; i < nmounts; ++i)
1183 mount_item &mi = mount[native_sorted[i]];
1184 if (! path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1187 /* SRC_PATH is in the mount table. */
1189 if (!pathbuf[mi.native_pathlen])
1191 else if (isdirsep (pathbuf[mi.native_pathlen]))
1196 int addslash = nextchar > 0 ? 1 : 0;
1197 if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH)
1198 return ENAMETOOLONG;
1199 strcpy (posix_path, mi.posix_path);
1201 strcat (posix_path, "/");
1203 slashify (pathbuf + mi.native_pathlen,
1204 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
1209 /* Not in the database. This should [theoretically] only happen if either
1210 the path begins with //, or / isn't mounted, or the path has a drive
1211 letter not covered by the mount table. If it's a relative path then the
1212 caller must want an absolute path (otherwise we would have returned
1213 above). So we always return an absolute path at this point. */
1214 if ((isalpha (pathbuf[0])) && (pathbuf[1] == ':'))
1215 cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p &&
1219 /* The use of src_path and not pathbuf here is intentional.
1220 We couldn't translate the path, so just ensure no \'s are present. */
1221 slashify (src_path, posix_path, trailing_slash_p);
1225 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1230 /* Return flags associated with a mount point given the win32 path. */
1233 mount_info::set_flags_from_win32_path (const char *p)
1235 for (int i = 0; i < nmounts; i++)
1237 mount_item &mi = mount[native_sorted[i]];
1238 if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
1244 /* read_mounts: Given a specific regkey, read mounts from under its
1248 mount_info::read_mounts (reg_key& r)
1250 char posix_path[MAX_PATH];
1251 HKEY key = r.get_key ();
1252 DWORD i, posix_path_size;
1257 posix_path_size = MAX_PATH;
1258 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1261 if (err != ERROR_SUCCESS)
1264 if (iscygdrive (posix_path))
1266 /* This shouldn't be in the mount table. */
1267 (void) r.kill (posix_path);
1272 /* Loop through subkeys */
1273 /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
1274 shared area is currently statically allocated so we can't have an
1275 arbitrarily large number of mounts. */
1276 for (DWORD i = 0; i < MAX_MOUNTS; i++)
1278 char native_path[MAX_PATH];
1281 posix_path_size = MAX_PATH;
1282 /* FIXME: if maximum posix_path_size is 256, we're going to
1283 run into problems if we ever try to store a mount point that's
1284 over 256 but is under MAX_PATH! */
1285 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1288 if (err == ERROR_NO_MORE_ITEMS)
1290 else if (err != ERROR_SUCCESS)
1292 debug_printf ("RegEnumKeyEx failed, error %d!\n", err);
1296 if (iscygdrive (posix_path))
1298 /* This shouldn't be in the mount table. */
1299 // (void) r.kill (posix_path);
1303 /* Get a reg_key based on i. */
1304 reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1306 /* Check the mount table for prefix matches. */
1307 for (int j = 0; j < nmounts; j++)
1308 if (strcasematch (mount[j].posix_path, posix_path))
1309 goto next; /* Can't have more than one */
1311 /* Fetch info from the subkey. */
1312 subkey.get_string ("native", native_path, sizeof (native_path), "");
1313 mount_flags = subkey.get_int ("flags", 0);
1315 /* Add mount_item corresponding to registry mount point. */
1316 cygwin_shared->mount.add_item (native_path, posix_path, mount_flags);
1322 /* from_registry: Build the entire mount table from the registry. Also,
1323 read in cygdrive-related information from its registry location. */
1326 mount_info::from_registry ()
1328 /* Use current mount areas if either user or system mount areas
1329 already exist. Otherwise, import old mounts. */
1333 /* Retrieve cygdrive-related information. */
1334 read_cygdrive_info_from_registry ();
1338 /* First read mounts from user's table. */
1341 /* Then read mounts from system-wide mount table. */
1342 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1343 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1344 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1345 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1349 /* If we had to create both user and system mount areas, import
1351 if (had_to_create_mount_areas == 2)
1352 import_v1_mounts ();
1357 /* add_reg_mount: Add mount item to registry. Return zero on success,
1358 non-zero on failure. */
1359 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1362 mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1364 /* Add the mount to the right registry location, depending on
1365 whether MOUNT_SYSTEM is set in the mount flags. */
1366 if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
1368 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1371 /* Start by deleting existing mount if one exists. */
1372 reg_user.kill (posix_path);
1374 /* Create the new mount. */
1375 reg_key subkey = reg_key (reg_user.get_key (),
1378 subkey.set_string ("native", native_path);
1379 subkey.set_int ("flags", mountflags);
1381 else /* local_machine mount */
1383 /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
1384 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1385 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1386 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1387 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1390 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1396 /* Start by deleting existing mount if one exists. */
1397 reg_sys.kill (posix_path);
1399 /* Create the new mount. */
1400 reg_key subkey = reg_key (reg_sys.get_key (),
1403 subkey.set_string ("native", native_path);
1404 subkey.set_int ("flags", mountflags);
1407 return 0; /* Success! */
1410 /* del_reg_mount: delete mount item from registry indicated in flags.
1411 Return zero on success, non-zero on failure.*/
1412 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1415 mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1419 if ((flags & MOUNT_SYSTEM) == 0) /* Delete from user registry */
1421 reg_key reg_user (KEY_ALL_ACCESS,
1422 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
1423 killres = reg_user.kill (posix_path);
1425 else /* Delete from system registry */
1427 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1428 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1429 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1430 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1433 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1439 killres = reg_sys.kill (posix_path);
1442 if (killres != ERROR_SUCCESS)
1444 __seterrno_from_win_error (killres);
1448 return 0; /* Success! */
1451 /* read_cygdrive_info_from_registry: Read the default prefix and flags
1452 to use when creating cygdrives from the special user registry
1453 location used to store cygdrive information. */
1456 mount_info::read_cygdrive_info_from_registry ()
1458 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1461 if (r.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1463 /* Didn't find it so write the default to the registry and use it. */
1464 write_cygdrive_info_to_registry ("/cygdrive", MOUNT_AUTO);
1468 /* Fetch cygdrive_flags from registry; returns MOUNT_AUTO on error. */
1469 cygdrive_flags = r.get_int ("cygdrive flags", MOUNT_AUTO);
1470 slashify (cygdrive, cygdrive, 1);
1471 cygdrive_len = strlen(cygdrive);
1475 /* write_cygdrive_info_to_registry: Write the default prefix and flags
1476 to use when creating cygdrives to the special user registry
1477 location used to store cygdrive information. */
1480 mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1482 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1485 /* Verify cygdrive prefix starts with a forward slash and if there's
1486 another character, it's not a slash. */
1487 if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
1488 (!isslash (cygdrive_prefix[0])) ||
1489 ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
1495 char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1];
1496 /* Ensure that there is never a final slash */
1497 nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
1499 r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
1500 r.set_int ("cygdrive flags", flags);
1502 /* This also needs to go in the in-memory copy of "cygdrive" */
1503 slashify (cygdrive_prefix, cygwin_shared->mount.cygdrive, 1);
1504 cygwin_shared->mount.cygdrive_flags = flags;
1505 cygwin_shared->mount.cygdrive_len = strlen(cygwin_shared->mount.cygdrive);
1511 mount_info::getmntent (int x)
1513 if (x < 0 || x >= nmounts)
1516 return mount[native_sorted[x]].getmntent ();
1519 static mount_item *mounts_for_sort;
1521 /* sort_by_posix_name: qsort callback to sort the mount entries. Sort
1522 user mounts ahead of system mounts to the same POSIX path. */
1523 /* FIXME: should the user should be able to choose whether to
1524 prefer user or system mounts??? */
1526 sort_by_posix_name (const void *a, const void *b)
1528 mount_item *ap = mounts_for_sort + (*((int*) a));
1529 mount_item *bp = mounts_for_sort + (*((int*) b));
1531 /* Base weighting on longest posix path first so that the most
1532 obvious path will be chosen. */
1533 size_t alen = strlen (ap->posix_path);
1534 size_t blen = strlen (bp->posix_path);
1536 int res = blen - alen;
1539 return res; /* Path lengths differed */
1541 /* The two paths were the same length, so just determine normal
1542 lexical sorted order. */
1543 res = strcmp (ap->posix_path, bp->posix_path);
1547 /* need to select between user and system mount to same POSIX path */
1548 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1557 /* sort_by_native_name: qsort callback to sort the mount entries. Sort
1558 user mounts ahead of system mounts to the same POSIX path. */
1559 /* FIXME: should the user should be able to choose whether to
1560 prefer user or system mounts??? */
1562 sort_by_native_name (const void *a, const void *b)
1564 mount_item *ap = mounts_for_sort + (*((int*) a));
1565 mount_item *bp = mounts_for_sort + (*((int*) b));
1567 /* Base weighting on longest win32 path first so that the most
1568 obvious path will be chosen. */
1569 size_t alen = strlen (ap->native_path);
1570 size_t blen = strlen (bp->native_path);
1572 int res = blen - alen;
1575 return res; /* Path lengths differed */
1577 /* The two paths were the same length, so just determine normal
1578 lexical sorted order. */
1579 res = strcasecmp (ap->posix_path, bp->posix_path);
1583 /* need to select between user and system mount to same POSIX path */
1584 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1596 for (int i = 0; i < nmounts; i++)
1597 native_sorted[i] = posix_sorted[i] = i;
1598 /* Sort them into reverse length order, otherwise we won't
1599 be able to look for /foo in /. */
1600 mounts_for_sort = mount; /* ouch. */
1601 qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
1602 qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
1605 /* Add an entry to the in-memory mount table.
1606 Returns 0 on success, -1 on failure and errno is set.
1608 This is where all argument validation is done. It may not make sense to
1609 do this when called internally, but it's cleaner to keep it all here. */
1612 mount_info::add_item (const char *native, const char *posix, unsigned mountflags)
1614 /* Can't add more than MAX_MOUNTS. */
1615 if (nmounts == MAX_MOUNTS)
1621 /* Something's wrong if either path is NULL or empty, or if it's
1622 not a UNC or absolute path. */
1624 if ((native == NULL) || (*native == 0) ||
1625 (posix == NULL) || (*posix == 0) ||
1626 (!slash_unc_prefix_p (native) && !isabspath (native)))
1632 /* Make sure both paths do not end in /. */
1633 char nativetmp[MAX_PATH];
1634 char posixtmp[MAX_PATH];
1636 if (slash_drive_prefix_p (native))
1637 slash_drive_to_win32_path (native, nativetmp, 0);
1640 backslashify (native, nativetmp, 0);
1641 nofinalslash (nativetmp, nativetmp);
1644 slashify (posix, posixtmp, 0);
1645 nofinalslash (posixtmp, posixtmp);
1647 debug_printf ("%s[%s], %s[%s], %p",
1648 native, nativetmp, posix, posixtmp, mountflags);
1650 /* Duplicate /'s in path are an error. */
1651 for (char *p = posixtmp + 1; *p; ++p)
1653 if (p[-1] == '/' && p[0] == '/')
1660 /* Write over an existing mount item with the same POSIX path if
1661 it exists and is from the same registry area. */
1662 for (int i = 0; i < nmounts; i++)
1664 if ((strcmp (mount[i].posix_path, posixtmp) == 0) &&
1665 ((mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM)))
1667 /* replace existing mount item */
1668 mount[i].init (nativetmp, posixtmp, mountflags);
1673 mount[nmounts++].init (nativetmp, posixtmp, mountflags);
1681 /* Delete a mount table entry where path is either a Win32 or POSIX
1682 path. Since the mount table is really just a table of aliases,
1683 deleting / is ok (although running without a slash mount is
1684 strongly discouraged because some programs may run erratically
1685 without one). If MOUNT_SYSTEM is set in flags, remove from system
1686 registry, otherwise remove the user registry mount.
1690 mount_info::del_item (const char *path, unsigned flags)
1692 char pathtmp[MAX_PATH];
1694 /* Something's wrong if path is NULL or empty. */
1695 if ((path == NULL) || (*path == 0))
1701 slashify (path, pathtmp, 0);
1702 nofinalslash (pathtmp, pathtmp);
1704 debug_printf ("%s[%s]", path, pathtmp);
1706 for (int i = 0; i < nmounts; i++)
1708 /* Delete if paths and mount locations match. */
1709 if (((strcmp (mount[i].posix_path, pathtmp) == 0
1710 || strcmp (mount[i].native_path, pathtmp) == 0)) &&
1711 ((mount[i].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM)))
1713 nmounts--; /* One less mount table entry */
1714 /* Fill in the hole if not at the end of the table */
1716 memcpy (mount + i, mount + i + 1,
1717 sizeof (mount[i]) * (nmounts - i));
1718 sort (); /* Resort the table */
1726 /* read_v1_mounts: Given a reg_key to an old mount table registry area,
1727 read in the mounts. The "which" arg contains zero if we're reading
1728 the user area and MOUNT_SYSTEM if we're reading the system area.
1729 This way we can store the mounts read in the appropriate place when
1730 they are written back to the new registry layout. */
1733 mount_info::read_v1_mounts (reg_key r, unsigned which)
1735 unsigned mountflags = 0;
1737 /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
1738 for (int i = 0; i < 30; i++)
1741 char win32path[MAX_PATH];
1742 char unixpath[MAX_PATH];
1744 __small_sprintf (key_name, "%02x", i);
1746 reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
1748 /* The registry names are historical but useful so are left alone. */
1749 k.get_string ("native", win32path, sizeof (win32path), "");
1750 k.get_string ("unix", unixpath, sizeof (unixpath), "");
1752 /* Does this entry contain something? */
1753 if (*win32path != 0)
1757 if (k.get_int ("fbinary", 0))
1758 mountflags |= MOUNT_BINARY;
1760 /* Or in zero or MOUNT_SYSTEM depending on which table
1762 mountflags |= which;
1764 cygwin_shared->mount.add_item (win32path, unixpath, mountflags);
1769 /* from_v1_registry: Build the entire mount table from the old v1 registry
1773 mount_info::from_v1_registry ()
1775 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
1785 /* First read mounts from user's table. */
1786 read_v1_mounts (r, 0);
1788 /* Then read mounts from system-wide mount table. */
1789 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
1796 read_v1_mounts (r1, MOUNT_SYSTEM);
1798 /* Note: we don't need to sort internal table here since it is
1799 done in main from_registry call after this function would be
1803 /* import_v1_mounts: If v1 mounts are present, load them and write
1804 the new entries to the new registry area. */
1807 mount_info::import_v1_mounts ()
1809 /* Read in old mounts into memory. */
1810 from_v1_registry ();
1812 /* Write all mounts to the new registry. */
1816 /* to_registry: For every mount point in memory, add a corresponding
1817 registry mount point. */
1820 mount_info::to_registry ()
1822 for (int i = 0; i < MAX_MOUNTS; i++)
1826 mount_item *p = mount + i;
1828 add_reg_mount (p->native_path, p->posix_path, p->flags);
1830 debug_printf ("%02x: %s, %s, %d",
1831 i, p->native_path, p->posix_path, p->flags);
1836 /************************* mount_item class ****************************/
1839 mount_item::getmntent ()
1842 struct mntent &ret=_reent_winsup()->_ret;
1844 static NO_COPY struct mntent ret;
1847 /* Pass back pointers to mount_info strings reserved for use by
1848 getmntent rather than pointers to strings in the internal mount
1849 table because the mount table might change, causing weird effects
1850 from the getmntent user's point of view. */
1852 strcpy (cygwin_shared->mount.mnt_fsname, native_path);
1853 ret.mnt_fsname = cygwin_shared->mount.mnt_fsname;
1854 strcpy (cygwin_shared->mount.mnt_dir, posix_path);
1855 ret.mnt_dir = cygwin_shared->mount.mnt_dir;
1857 if (!(flags & MOUNT_SYSTEM)) /* user mount */
1858 strcpy (cygwin_shared->mount.mnt_type, (char *) "user");
1859 else /* system mount */
1860 strcpy (cygwin_shared->mount.mnt_type, (char *) "system");
1862 if ((flags & MOUNT_AUTO)) /* cygdrive */
1863 strcat (cygwin_shared->mount.mnt_type, (char *) ",auto");
1865 ret.mnt_type = cygwin_shared->mount.mnt_type;
1867 /* mnt_opts is a string that details mount params such as
1868 binary or textmode, or exec. We don't print
1869 `silent' here; it's a magic internal thing. */
1871 if (! (flags & MOUNT_BINARY))
1872 strcpy (cygwin_shared->mount.mnt_opts, (char *) "textmode");
1874 strcpy (cygwin_shared->mount.mnt_opts, (char *) "binmode");
1876 if (flags & MOUNT_CYGWIN_EXEC)
1877 strcat (cygwin_shared->mount.mnt_opts, (char *) ",cygexec");
1878 else if (flags & MOUNT_EXEC)
1879 strcat (cygwin_shared->mount.mnt_opts, (char *) ",exec");
1882 ret.mnt_opts = cygwin_shared->mount.mnt_opts;
1889 /* Fill in the fields of a mount table entry. */
1892 mount_item::init (const char *native, const char *posix, unsigned mountflags)
1894 strcpy ((char *) native_path, native);
1895 strcpy ((char *) posix_path, posix);
1897 native_pathlen = strlen (native_path);
1898 posix_pathlen = strlen (posix_path);
1903 /********************** Mount System Calls **************************/
1905 /* Mount table system calls.
1906 Note that these are exported to the application. */
1908 /* mount: Add a mount to the mount table in memory and to the registry
1909 that will cause paths under win32_path to be translated to paths
1910 under posix_path. */
1914 mount (const char *win32_path, const char *posix_path, unsigned flags)
1918 if (flags & MOUNT_AUTO) /* normal mount */
1920 /* When flags include MOUNT_AUTO, take this to mean that
1921 we actually want to change the cygdrive prefix and flags
1922 without actually mounting anything. */
1923 res = cygwin_shared->mount.write_cygdrive_info_to_registry (posix_path, flags);
1928 if (iscygdrive (posix_path))
1931 return res; /* Don't try to add cygdrive prefix. */
1934 res = cygwin_shared->mount.add_reg_mount (win32_path, posix_path, flags);
1937 cygwin_shared->mount.add_item (win32_path, posix_path, flags);
1940 syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
1944 /* umount: The standard umount call only has a path parameter. Since
1945 it is not possible for this call to specify whether to remove the
1946 mount from the user or global mount registry table, assume the user
1951 umount (const char *path)
1953 return cygwin_umount (path, 0);
1956 /* cygwin_umount: This is like umount but takes an additional flags
1957 parameter that specifies whether to umount from the user or system-wide
1962 cygwin_umount (const char *path, unsigned flags)
1964 int res = cygwin_shared->mount.del_reg_mount (path, flags);
1967 cygwin_shared->mount.del_item (path, flags);
1969 syscall_printf ("%d = cygwin_umount (%s, %d)", res, path, flags);
1974 #define iteration _reent_winsup()->_iteration
1976 static int iteration;
1981 setmntent (const char *filep, const char *)
1984 return (FILE *) filep;
1991 return cygwin_shared->mount.getmntent (iteration++);
2001 /********************** Symbolic Link Support **************************/
2003 /* Create a symlink from FROMPATH to TOPATH. */
2007 symlink (const char *topath, const char *frompath)
2012 path_conv win32_path (frompath, SYMLINK_NOFOLLOW);
2013 if (win32_path.error)
2015 set_errno (win32_path.error);
2019 syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
2026 if (strlen (topath) >= MAX_PATH)
2028 set_errno (ENAMETOOLONG);
2032 if (win32_path.is_device () ||
2033 win32_path.file_attributes () != (DWORD) -1)
2039 h = CreateFileA(win32_path.get_win32 (), GENERIC_WRITE, 0, &sec_none_nih,
2040 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
2041 if (h == INVALID_HANDLE_VALUE)
2045 char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10];
2047 __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
2048 DWORD len = strlen (buf) + 1;
2050 /* Note that the terminating nul is written. */
2052 if (!WriteFile (h, buf, len, &written, NULL) || written != len)
2056 DeleteFileA (win32_path.get_win32 ());
2061 set_file_attribute (win32_path.has_acls (),
2062 win32_path.get_win32 (),
2063 S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
2064 SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_SYSTEM);
2070 syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath);
2074 static __inline char *
2075 has_suffix (const char *path, const suffix_info *suffixes)
2077 char *ext = strrchr (path, '.');
2079 for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
2080 if (strcasematch (ext, ex->name))
2085 static __inline__ int
2086 next_suffix (char *ext_here, const suffix_info *&suffixes)
2091 while (suffixes && suffixes->name)
2092 if (!suffixes->addon)
2096 strcpy (ext_here, suffixes->name);
2103 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2105 If PATH is a symlink, put the value of the symlink--the file to
2106 which it points--into BUF. The value stored in BUF is not
2107 necessarily null terminated. BUFLEN is the length of BUF; only up
2108 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2109 which case nothing will be stored.
2111 Set *SYML if PATH is a symlink.
2113 Set *EXEC if PATH appears to be executable. This is an efficiency
2114 hack because we sometimes have to open the file anyhow. *EXEC will
2115 not be set for every executable file.
2117 Return -1 on error, 0 if PATH is not a symlink, or the length
2118 stored into BUF if PATH is a symlink. */
2121 symlink_info::check (const char *in_path, const suffix_info *suffixes)
2125 char extbuf[MAX_PATH + 5];
2126 const char *path = in_path;
2130 else if ((known_suffix = has_suffix (in_path, suffixes)) != NULL)
2137 path = strcpy (extbuf, in_path);
2138 ext_here = strchr (path, '\0');
2145 if (!next_suffix (ext_here, suffixes))
2147 fileattr = GetFileAttributesA (path);
2148 if (fileattr == (DWORD) -1)
2150 /* The GetFileAttributesA call can fail for reasons that don't
2151 matter, so we just return 0. For example, getting the
2152 attributes of \\HOST will typically fail. */
2153 debug_printf ("GetFileAttributesA (%s) failed", path);
2158 /* Windows allows path\. even when `path' isn't a directory.
2159 Detect this scenario and disallow it, since it is non-UNIX like. */
2160 char *p = strchr (path, '\0');
2161 if (p > path + 1 && p[-1] == '.' && SLASH_P (p[-2]) &&
2162 !(fileattr & FILE_ATTRIBUTE_DIRECTORY))
2164 debug_printf ("\\. specified on non-directory");
2165 set_errno (ENOTDIR);
2169 /* A symlink will have the `system' file attribute. */
2170 /* Only files can be symlinks (which can be symlinks to directories). */
2171 if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))
2172 goto file_not_symlink;
2174 /* Open the file. */
2176 h = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
2177 FILE_ATTRIBUTE_NORMAL, 0);
2179 if (h == INVALID_HANDLE_VALUE)
2180 goto file_not_symlink;
2183 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2186 if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
2188 else if (got == sizeof (cookie_buf)
2189 && memcmp (cookie_buf, SYMLINK_COOKIE,
2190 sizeof (cookie_buf)) == 0)
2192 /* It's a symlink. */
2193 pflags = PATH_SYMLINK;
2195 res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2200 /* Versions prior to b16 stored several trailing
2201 NULs with the path (to fill the path out to 1024
2202 chars). Current versions only store one trailing
2203 NUL. The length returned is the path without
2204 *any* trailing NULs. We also have to handle (or
2205 at least not die from) corrupted paths. */
2206 if (memchr (contents, 0, got) != NULL)
2207 res = strlen (contents);
2212 else if (got == sizeof (cookie_buf)
2213 && memcmp (cookie_buf, SOCKET_COOKIE,
2214 sizeof (cookie_buf)) == 0)
2216 pflags |= PATH_SOCKET;
2217 goto close_and_return;
2221 /* Not a symlink, see if executable. */
2222 if (!(pflags & (PATH_EXEC | PATH_CYGWIN_EXEC)) && got >= 2 &&
2223 ((cookie_buf[0] == '#' && cookie_buf[1] == '!') ||
2224 (cookie_buf[0] == ':' && cookie_buf[1] == '\n')))
2225 pflags |= PATH_EXEC;
2228 goto file_not_symlink;
2241 syscall_printf ("not a symlink");
2245 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2246 res, path, contents, pflags);
2251 /* readlink system call */
2255 readlink (const char *path, char *buf, int buflen)
2257 extern suffix_info stat_suffixes[];
2258 path_conv pathbuf (path, SYMLINK_CONTENTS, 0, stat_suffixes);
2262 set_errno (pathbuf.error);
2263 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2267 if (!pathbuf.issymlink ())
2269 if (pathbuf.fileattr != (DWORD) -1)
2274 int len = strlen (pathbuf.get_win32 ());
2275 if (len > (buflen - 1))
2277 set_errno (ENAMETOOLONG);
2280 memcpy (buf, pathbuf.get_win32 (), len);
2283 /* errno set by symlink.check if error */
2287 /* Some programs rely on st_dev/st_ino being unique for each file.
2288 Hash the path name and hope for the best. The hash arg is not
2289 always initialized to zero since readdir needs to compute the
2290 dirent ino_t based on a combination of the hash of the directory
2291 done during the opendir call and the hash or the filename within
2292 the directory. FIXME: Not bullet-proof. */
2293 /* Cygwin internal */
2295 unsigned long __stdcall
2296 hash_path_name (unsigned long hash, const char *name)
2301 /* Perform some initial permutations on the pathname if this is
2305 /* Simplistic handling of drives. If there is a drive specified,
2306 make sure that the initial letter is upper case. If there is
2307 no \ after the ':' assume access through the root directory
2309 FIXME: Should really honor MS-Windows convention of using
2310 the environment to track current directory on various drives. */
2313 char *nn, *newname = (char *) alloca (strlen (name) + 2);
2314 nn = strncpy (newname, name, 2);
2316 *newname = toupper (*nn);
2329 /* Fill out the hashed path name with the current working directory if
2330 this is not an absolute path and there is no pre-specified hash value.
2331 Otherwise the inodes same will differ depending on whether a file is
2332 referenced with an absolute value or relatively. */
2334 if (*name != '\\' && (current_directory_name == NULL ||
2335 get_current_directory_name ()))
2337 hash = current_directory_hash;
2338 if (name[0] == '.' && name[1] == '\0')
2340 hash = hash_path_name (hash, "\\");
2345 /* Build up hash. Ignore single trailing slash or \a\b\ != \a\b or
2346 \a\b\. but allow a single \ if that's all there is. */
2349 hash += *name + (*name << 17);
2352 while (*++name != '\0' &&
2353 !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
2358 get_current_directory_name ()
2362 for (dlen = 256; ; dlen *= 2)
2364 current_directory_name = (char *) realloc (current_directory_name, dlen + 2);
2365 if ((len = GetCurrentDirectoryA (dlen, current_directory_name)) < dlen)
2372 current_directory_hash = hash_path_name (0, current_directory_name);
2380 getcwd_inner (char *buf, size_t ulen, int posix_p)
2382 char *resbuf = NULL;
2385 if (current_directory_name == NULL && !get_current_directory_name ())
2390 if (strlen (current_directory_name) >= len)
2394 strcpy (buf, current_directory_name);
2398 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, win32) (cached)",
2399 resbuf, resbuf ? resbuf : "", buf, len);
2402 else if (current_directory_posix_name != NULL)
2404 if (strlen (current_directory_posix_name) >= len)
2408 strcpy (buf, current_directory_posix_name);
2412 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, posix) (cached)",
2413 resbuf, resbuf ? resbuf : "", buf, len);
2417 /* posix_p required and current_directory_posix_name == NULL */
2419 char temp[MAX_PATH];
2421 /* Turn from Win32 style to our style. */
2422 cygwin_shared->mount.conv_to_posix_path (current_directory_name, temp, 0);
2424 size_t tlen = strlen (temp);
2426 current_directory_posix_name = (char *) realloc (
2427 current_directory_posix_name, tlen + 1);
2428 if (current_directory_posix_name != NULL)
2429 strcpy (current_directory_posix_name, temp);
2433 /* len was too small */
2442 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, %s)",
2443 resbuf, resbuf ? resbuf : "",
2444 buf, len, posix_p ? "posix" : "win32");
2449 getcwd (char *buf, size_t ulen)
2453 if (buf == NULL || ulen == 0)
2455 buf = (char *) alloca (MAX_PATH);
2456 res = getcwd_inner (buf, MAX_PATH, 1);
2461 res = getcwd_inner (buf, ulen, 1);
2467 /* getwd: standards? */
2472 return getcwd (buf, MAX_PATH);
2475 /* chdir: POSIX 5.2.1.1 */
2478 chdir (const char *dir)
2480 path_conv path (dir);
2484 set_errno (path.error);
2485 syscall_printf ("-1 = chdir (%s)", dir);
2489 char *native_dir = path.get_win32 ();
2491 /* Check to see if path translates to something like C:.
2492 If it does, append a \ to the native directory specification to
2493 defeat the Windows 95 (i.e. MS-DOS) tendency of returning to
2494 the last directory visited on the given drive. */
2495 if (isalpha (native_dir[0]) && native_dir[1] == ':' && !native_dir[2])
2497 native_dir[2] = '\\';
2498 native_dir[3] = '\0';
2500 int res = SetCurrentDirectoryA (native_dir);
2504 /* Clear the cache until we need to retrieve the directory again. */
2505 if (current_directory_name != NULL)
2507 free (current_directory_name);
2508 current_directory_name = NULL;
2510 if (current_directory_posix_name != NULL)
2512 free (current_directory_posix_name);
2513 current_directory_posix_name = NULL;
2516 syscall_printf ("%d = chdir (%s) (dos %s)", res ? 0 : -1, dir, native_dir);
2517 return res ? 0 : -1;
2520 /******************** Exported Path Routines *********************/
2522 /* Cover functions to the path conversion routines.
2523 These are exported to the world as cygwin_foo by cygwin.din. */
2527 cygwin_conv_to_win32_path (const char *path, char *win32_path)
2529 path_conv p (path, SYMLINK_FOLLOW, 0);
2532 set_errno (p.error);
2536 strcpy (win32_path, p.get_win32 ());
2542 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
2544 path_conv p (path, SYMLINK_FOLLOW, 1);
2547 set_errno (p.error);
2551 strcpy (win32_path, p.get_win32 ());
2555 /* This is exported to the world as cygwin_foo by cygwin.din. */
2559 cygwin_conv_to_posix_path (const char *path, char *posix_path)
2561 if (check_null_empty_path_errno (path))
2563 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 1);
2569 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
2571 if (check_null_empty_path_errno (path))
2573 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 0);
2577 /* The realpath function is supported on some UNIX systems. */
2581 realpath (const char *path, char *resolved)
2585 path_conv real_path (path, SYMLINK_FOLLOW, 1);
2587 if (real_path.error)
2588 err = real_path.error;
2591 err = cygwin_shared->mount.conv_to_posix_path (real_path.get_win32 (), resolved, 0);
2596 /* FIXME: on error, we are supposed to put the name of the path
2597 component which could not be resolved into RESOLVED. */
2604 /* Return non-zero if path is a POSIX path list.
2605 This is exported to the world as cygwin_foo by cygwin.din.
2608 <sect1 id="add-func-cygwin-posix-path-list-p">
2609 <para>Rather than use a mode to say what the "proper" path list
2610 format is, we allow any, and give apps the tools they need to
2611 convert between the two. If a ';' is present in the path list it's
2612 a Win32 path list. Otherwise, if the first path begins with
2613 [letter]: (in which case it can be the only element since if it
2614 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
2615 it's a POSIX path list.</para>
2622 cygwin_posix_path_list_p (const char *path)
2624 int posix_p = ! (strchr (path, ';')
2625 || (isalpha (path[0]) && path[1] == ':'));
2629 /* These are used for apps that need to convert env vars like PATH back and
2630 forth. The conversion is a two step process. First, an upper bound on the
2631 size of the buffer needed is computed. Then the conversion is done. This
2632 allows the caller to use alloca if it wants. */
2635 conv_path_list_buf_size (const char *path_list, int to_posix_p)
2637 int i, num_elms, max_mount_path_len, size;
2640 /* The theory is that an upper bound is
2641 current_size + (num_elms * max_mount_path_len) */
2643 char delim = to_posix_p ? ';' : ':';
2645 for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms)
2648 /* 7: strlen ("//c") + slop, a conservative initial value */
2649 for (max_mount_path_len = 7, i = 0; i < cygwin_shared->mount.nmounts; ++i)
2651 int mount_len = (to_posix_p
2652 ? cygwin_shared->mount.mount[i].posix_pathlen
2653 : cygwin_shared->mount.mount[i].native_pathlen);
2654 if (max_mount_path_len < mount_len)
2655 max_mount_path_len = mount_len;
2659 size = strlen (path_list) + (num_elms * max_mount_path_len) + 100;
2665 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
2667 return conv_path_list_buf_size (path_list, 1);
2672 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
2674 return conv_path_list_buf_size (path_list, 0);
2679 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
2681 conv_path_list (win32, posix, 1);
2687 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
2689 conv_path_list (posix, win32, 0);
2693 /* cygwin_split_path: Split a path into directory and file name parts.
2694 Buffers DIR and FILE are assumed to be big enough.
2696 Examples (path -> `dir' / `file'):
2699 . -> `.' / `.' (FIXME: should this be `.' / `'?)
2700 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
2702 foo/bar -> `foo' / `bar'
2703 foo/bar/ -> `foo' / `bar'
2705 /foo/bar -> `/foo' / `bar'
2708 c:foo -> `c:/' / `foo'
2709 c:/foo -> `c:/' / `foo'
2714 cygwin_split_path (const char *path, char *dir, char *file)
2716 int dir_started_p = 0;
2718 /* Deal with drives.
2719 Remember that c:foo <==> c:/foo. */
2720 if (isalpha (path[0]) && path[1] == ':')
2731 if (SLASH_P (*path))
2736 /* Determine if there are trailing slashes and "delete" them if present.
2737 We pretend as if they don't exist. */
2738 const char *end = path + strlen (path);
2739 /* path + 1: keep leading slash. */
2740 while (end > path + 1 && SLASH_P (end[-1]))
2743 /* At this point, END points to one beyond the last character
2744 (with trailing slashes "deleted"). */
2746 /* Point LAST_SLASH at the last slash (duh...). */
2747 const char *last_slash;
2748 for (last_slash = end - 1; last_slash >= path; --last_slash)
2749 if (SLASH_P (*last_slash))
2752 if (last_slash == path)
2757 else if (last_slash > path)
2759 memcpy (dir, path, last_slash - path);
2760 dir[last_slash - path] = 0;
2765 ; /* nothing to do */
2771 memcpy (file, last_slash + 1, end - last_slash - 1);
2772 file[end - last_slash - 1] = 0;
2775 /********************** String Helper Functions ************************/
2777 #define CHXOR ('a' ^ 'A')
2778 #define ch_case_eq(ch1, ch2) \
2781 !((x = ((unsigned char)ch1 ^ (unsigned char)ch2)) && \
2782 (x != CHXOR || !isalpha (ch1))); \
2786 strncasematch (const char *s1, const char *s2, size_t n)
2794 if (!ch_case_eq (*s1, *s2))
2798 return !n || *s2 == '\0';
2802 strcasematch (const char *s1, const char *s2)
2809 if (!ch_case_eq (*s1, *s2))
2817 strcasestr (const char *searchee, const char *lookfor)
2823 return (char *) searchee;
2831 if (lookfor[i] == 0)
2832 return (char *) searchee;
2834 if (!ch_case_eq (lookfor[i], searchee[i]))