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. */
547 normalize_posix_path (const char *cwd, const char *src, char *dst)
549 const char *src_start = src;
550 char *dst_start = dst;
552 if (! SLASH_P (src[0]))
554 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
556 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
560 dst = strchr (dst, '\0');
561 if (dst > dst_start && !isdirsep(dst[-1]))
564 /* Two leading /'s? If so, preserve them. */
565 else if (SLASH_P (src[1]))
571 { /* Starts with three or more slashes - reset. */
580 /* Strip runs of /'s. */
585 while (SLASH_P(*src))
589 else if (src[0] == '.' && SLASH_P (src[1])
590 && (src == src_start || SLASH_P (src[-1])))
593 while(SLASH_P(src[0]))
596 /* Backup if "..". */
597 else if (src[0] == '.' && src[1] == '.'
598 /* dst must be greater than dst_start */
599 && isdirsep (dst[-1])
600 && (SLASH_P (src[2]) || src[2] == 0))
602 /* Back up over /, but not if it's the first one. */
603 if (dst > dst_start + 1)
605 /* Now back up to the next /. */
606 while (dst > dst_start + 1 && !isdirsep (dst[-1]))
609 while (SLASH_P (*src))
612 /* Otherwise, add char to result. */
623 debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start);
627 /* Normalize a Win32 path.
628 /'s are converted to \'s in the process.
629 All duplicate \'s, except for 2 leading \'s, are deleted.
631 The result is 0 for success, or an errno error value.
632 FIXME: A lot of this should be mergeable with the POSIX critter. */
635 normalize_win32_path (const char *cwd, const char *src, char *dst)
637 const char *src_start = src;
638 char *dst_start = dst;
640 if (! SLASH_P (src[0])
641 && strchr (src, ':') == NULL)
643 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
645 debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
652 /* Two leading \'s? If so, preserve them. */
653 else if (SLASH_P (src[0]) && SLASH_P (src[1]))
661 /* Strip duplicate /'s. */
662 if (SLASH_P (src[0]) && SLASH_P (src[1]))
665 else if (src[0] == '.' && SLASH_P (src[1])
666 && (src == src_start || SLASH_P (src[-1])))
671 /* Backup if "..". */
672 else if (src[0] == '.' && src[1] == '.'
673 /* dst must be greater than dst_start */
675 && (SLASH_P (src[2]) || src[2] == 0))
677 /* Back up over /, but not if it's the first one. */
678 if (dst > dst_start + 1)
680 /* Now back up to the next /. */
681 while (dst > dst_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
687 /* Otherwise, add char to result. */
698 debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
703 /* Various utilities. */
705 /* slashify: Convert all back slashes in src path to forward slashes
706 in dst path. Add a trailing slash to dst when trailing_slash_p arg
710 slashify (const char *src, char *dst, int trailing_slash_p)
712 const char *start = src;
724 && !isdirsep (src[-1]))
729 /* backslashify: Convert all forward slashes in src path to back slashes
730 in dst path. Add a trailing slash to dst when trailing_slash_p arg
734 backslashify (const char *src, char *dst, int trailing_slash_p)
736 const char *start = src;
748 && !isdirsep (src[-1]))
753 /* nofinalslash: Remove trailing / and \ from SRC (except for the
754 first one). It is ok for src == dst. */
757 nofinalslash (const char *src, char *dst)
759 int len = strlen (src);
761 memcpy (dst, src, len + 1);
762 while (len > 1 && SLASH_P (dst[--len]))
766 /* slash_drive_prefix_p: Return non-zero if PATH begins with
770 slash_drive_prefix_p (const char *path)
772 return (isdirsep(path[0])
775 && (path[3] == 0 || path[3] == '/'));
778 /* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
781 slash_unc_prefix_p (const char *path)
784 int ret = (isdirsep (path[0])
785 && isdirsep (path[1])
788 && !isdirsep (path[3])
789 && ((p = strchr(&path[3], '/')) != NULL));
790 if (!ret || p == NULL)
792 return ret && isalnum (p[1]);
795 /* conv_path_list: Convert a list of path names to/from Win32/POSIX.
797 SRC is not a const char * because we temporarily modify it to ease
800 I believe Win32 always has '.' in $PATH. POSIX obviously doesn't.
801 We certainly don't want to handle that here, but it is something for
802 the caller to think about. */
805 conv_path_list (const char *src, char *dst, int to_posix_p)
809 char src_delim = to_posix_p ? ';' : ':';
810 char dst_delim = to_posix_p ? ':' : ';';
811 int (*conv_fn) (const char *, char *) = (to_posix_p
812 ? cygwin_conv_to_posix_path
813 : cygwin_conv_to_win32_path);
817 s = strchr (src, src_delim);
821 (*conv_fn) (src[0] != 0 ? src : ".", d);
830 (*conv_fn) (src[0] != 0 ? src : ".", d);
836 /************************* mount_info class ****************************/
838 /* init: Initialize the mount table. */
846 had_to_create_mount_areas = 0;
848 /* Fetch the mount table and cygdrive-related information from
852 /* If slash isn't already mounted, mount system directory as slash. */
854 for (int i = 0; i < nmounts; i++)
856 if (strcmp (mount[i].posix_path, "/") == 0)
867 /* mount_slash: mount the system partition as slash. */
870 mount_info::mount_slash ()
872 char drivestring[MAX_PATH];
873 GetSystemDirectory (drivestring, MAX_PATH);
874 drivestring[2] = 0; /* truncate path to "<drive>:" */
876 if (add_reg_mount (drivestring, "/", 0) == 0)
877 add_item (drivestring, "/", 0);
880 /* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
881 the result in win32_path.
883 If win32_path != NULL, the relative path, if possible to keep, is
884 stored in win32_path. If the relative path isn't possible to keep,
885 the full path is stored.
887 If full_win32_path != NULL, the full path is stored there.
889 The result is zero for success, or an errno value.
891 {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */
894 mount_info::conv_to_win32_path (const char *src_path, char *win32_path,
895 char *full_win32_path, DWORD &devn, int &unit,
898 int src_path_len = strlen (src_path);
899 int trailing_slash_p = (src_path_len > 0
900 && SLASH_P (src_path[src_path_len - 1]));
903 unsigned dummy_flags;
909 flags = &dummy_flags;
912 debug_printf ("conv_to_win32_path (%s)", src_path);
914 if (src_path_len >= MAX_PATH)
916 debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path);
922 mount_item *mi = NULL; /* initialized to avoid compiler warning */
923 char pathbuf[MAX_PATH];
925 /* The rule is :'s can't appear in [our] POSIX path names so this is a safe
926 test; if ':' is present it already be in Win32 form. */
927 /* Additional test: If the path has \'s in it, we assume that it's a Win32
929 if (strchr (src_path, ':') != NULL
930 || (strchr (src_path, '\\')/* && !strchr (src_path, '/')*/))
932 debug_printf ("%s already win32", src_path);
933 rc = normalize_win32_path ("", src_path, pathbuf);
936 /* FIXME: Do we have to worry about trailing_slash_p here? */
937 if (win32_path != NULL)
939 /* If src_path is a relativ win32 path, normalize_win32_path
940 adds a leading slash, nevertheless. So we have to test
942 strcpy (win32_path, strchr("/\\", src_path[0]) || src_path[1] == ':'
943 ? pathbuf : pathbuf + 1);
945 if (full_win32_path != NULL)
947 *full_win32_path = '\0';
948 /* Add drive if it's a local relative Win32 path */
949 if (! strchr(src_path, ':') && strncmp (src_path, "\\\\", 2))
951 GetCurrentDirectory (MAX_PATH, full_win32_path);
952 if (src_path[0] == '\\') // drive relative absolute path
953 full_win32_path[2] = '\0';
955 strcat (full_win32_path, pathbuf);
957 *flags = set_flags_from_win32_path (pathbuf);
961 /* Normalize the path, taking out ../../ stuff, we need to do this
962 so that we can move from one mounted directory to another with relative
965 eg mounting c:/foo /foo
971 should look in c:/foo, not d:/foo.
973 We do this by first getting an absolute UNIX-style path and then
974 converting it to a DOS-style path, looking up the appropriate drive
975 in the mount table. */
979 /* No need to fetch cwd if path is absolute. */
980 if ((isrelpath = ! SLASH_P (*src_path)))
981 getcwd_inner (cwd, MAX_PATH, TRUE); /* FIXME: check rc */
983 strcpy (cwd, "/"); /* some innocuous value */
985 rc = normalize_posix_path (cwd, src_path, pathbuf);
989 debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
993 nofinalslash (pathbuf, pathbuf);
995 /* Determine where the destination should be placed. */
996 if (full_win32_path != NULL)
997 dst = full_win32_path;
998 else if (win32_path != NULL)
1002 goto out; /* Sanity check. */
1004 /* See if this is a cygwin "device" */
1005 if (win32_device_name (pathbuf, dst, devn, unit))
1007 *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */
1011 /* Check if the cygdrive prefix was specified. If so, just strip
1012 off the prefix and transform it into an MS-DOS path. */
1014 if (iscygdrive_device (pathbuf))
1016 if (!cygdrive_win32_path (pathbuf, dst, trailing_slash_p))
1018 *flags = cygdrive_flags;
1022 /* Check the mount table for prefix matches. */
1023 for (i = 0; i < nmounts; i++)
1025 mi = mount + posix_sorted[i];
1026 if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen))
1032 if (slash_drive_prefix_p (pathbuf))
1033 slash_drive_to_win32_path (pathbuf, dst, trailing_slash_p);
1035 backslashify (pathbuf, dst, trailing_slash_p); /* just convert */
1040 int n = mi->native_pathlen;
1041 memcpy (dst, mi->native_path, n);
1042 char *p = pathbuf + mi->posix_pathlen;
1043 if (!trailing_slash_p && !*p)
1047 /* Do not add trailing \ to UNC device names like \\.\a: */
1048 if (*p != '/' && /* FIXME: this test seems wrong. */
1049 (strncmp (mi->native_path, "\\\\.\\", 4) != 0 ||
1050 strncmp (mi->native_path + 4, "UNC\\", 4) == 0))
1052 strcpy (dst + n, p);
1054 backslashify (dst, dst, trailing_slash_p);
1059 /* Compute relative path if asked to and able to. */
1061 cwdlen = 0; /* avoid a (hopefully) bogus compiler warning */
1062 if (win32_path == NULL)
1063 /* nothing to do */;
1064 else if (isrelpath &&
1065 path_prefix_p (current_directory_name, dst,
1066 cwdlen = strlen (current_directory_name)))
1068 if (strlen (dst) == cwdlen)
1071 dst += isdirsep (current_directory_name[cwdlen - 1]) ? cwdlen : cwdlen + 1;
1073 memmove (win32_path, dst, strlen (dst) + 1);
1076 strcpy (win32_path, ".");
1077 if (trailing_slash_p)
1078 strcat (win32_path, "\\");
1081 else if (win32_path != dst)
1082 strcpy (win32_path, dst);
1086 debug_printf ("%s(rel), %s(abs) %p(flags) = conv_to_win32_path (%s)",
1087 win32_path, full_win32_path, *flags,
1092 /* Convert PATH (for which slash_drive_prefix_p returns 1) to WIN32 form. */
1095 mount_info::slash_drive_to_win32_path (const char *path, char *buf,
1096 int trailing_slash_p)
1101 strcpy (buf + 2, "\\");
1103 backslashify (path + 3, buf + 2, trailing_slash_p);
1106 /* cygdrive_posix_path: Build POSIX path used as the
1107 mount point for cygdrives created when there is no other way to
1108 obtain a POSIX path from a Win32 one. */
1111 mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
1113 int len = cygdrive_len;
1115 memcpy (dst, cygdrive, len + 1);
1117 /* Now finish the path off with the drive letter to be used.
1118 The cygdrive prefix always ends with a trailing slash so
1119 the drive letter is added after the path. */
1120 dst[len++] = tolower (src[0]);
1122 dst[len++] = '\000';
1126 strcpy (dst + len, src + 3);
1128 slashify (dst, dst, trailing_slash_p);
1132 mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
1134 const char *p = src + cygdrive_len;
1135 if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
1139 strcpy (dst + 2, p + 1);
1140 backslashify (dst, dst, trailing_slash_p || !dst[2]);
1141 debug_printf ("src '%s', dst '%s'", src, dst);
1145 /* conv_to_posix_path: Ensure src_path is a POSIX path.
1147 The result is zero for success, or an errno value.
1148 posix_path must have sufficient space (i.e. MAX_PATH bytes).
1149 If keep_rel_p is non-zero, relative paths stay that way. */
1152 mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
1155 int src_path_len = strlen (src_path);
1156 int trailing_slash_p = (src_path_len > 0
1157 && SLASH_P (src_path[src_path_len - 1]));
1158 int relative_path_p = (! SLASH_P (*src_path)
1159 && strchr (src_path, ':') == NULL);
1161 debug_printf ("conv_to_posix_path (%s, %s)", src_path,
1162 keep_rel_p ? "keep-rel" : "no-keep-rel");
1165 if (src_path_len >= MAX_PATH)
1167 debug_printf ("ENAMETOOLONG");
1168 return ENAMETOOLONG;
1171 /* FIXME: For now, if the path is relative and it's supposed to stay
1172 that way, skip mount table processing. */
1174 if (keep_rel_p && relative_path_p)
1176 slashify (src_path, posix_path, 0);
1177 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1181 char pathbuf[MAX_PATH];
1184 /* No need to fetch cwd if path is absolute. */
1185 if (relative_path_p)
1186 getcwd_inner (cwd, MAX_PATH, 0); /* FIXME: check rc */
1188 strcpy (cwd, "/"); /* some innocuous value */
1190 int rc = normalize_win32_path (cwd, src_path, pathbuf);
1194 debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1197 nofinalslash (pathbuf, pathbuf);
1200 int pathbuflen = strlen (pathbuf);
1201 for (int i = 0; i < nmounts; ++i)
1203 mount_item &mi = mount[native_sorted[i]];
1204 if (! path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1207 /* SRC_PATH is in the mount table. */
1209 if (!pathbuf[mi.native_pathlen])
1211 else if (isdirsep (pathbuf[mi.native_pathlen]))
1216 int addslash = nextchar > 0 ? 1 : 0;
1217 if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH)
1218 return ENAMETOOLONG;
1219 strcpy (posix_path, mi.posix_path);
1221 strcat (posix_path, "/");
1223 slashify (pathbuf + mi.native_pathlen,
1224 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
1229 /* Not in the database. This should [theoretically] only happen if either
1230 the path begins with //, or / isn't mounted, or the path has a drive
1231 letter not covered by the mount table. If it's a relative path then the
1232 caller must want an absolute path (otherwise we would have returned
1233 above). So we always return an absolute path at this point. */
1234 if ((isalpha (pathbuf[0])) && (pathbuf[1] == ':'))
1235 cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p &&
1239 /* The use of src_path and not pathbuf here is intentional.
1240 We couldn't translate the path, so just ensure no \'s are present. */
1241 slashify (src_path, posix_path, trailing_slash_p);
1245 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1250 /* Return flags associated with a mount point given the win32 path. */
1253 mount_info::set_flags_from_win32_path (const char *p)
1255 for (int i = 0; i < nmounts; i++)
1257 mount_item &mi = mount[native_sorted[i]];
1258 if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
1264 /* read_mounts: Given a specific regkey, read mounts from under its
1268 mount_info::read_mounts (reg_key& r)
1270 char posix_path[MAX_PATH];
1271 HKEY key = r.get_key ();
1272 DWORD i, posix_path_size;
1277 posix_path_size = MAX_PATH;
1278 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1281 if (err != ERROR_SUCCESS)
1284 if (iscygdrive (posix_path))
1286 /* This shouldn't be in the mount table. */
1287 (void) r.kill (posix_path);
1292 /* Loop through subkeys */
1293 /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
1294 shared area is currently statically allocated so we can't have an
1295 arbitrarily large number of mounts. */
1296 for (DWORD i = 0; i < MAX_MOUNTS; i++)
1298 char native_path[MAX_PATH];
1301 posix_path_size = MAX_PATH;
1302 /* FIXME: if maximum posix_path_size is 256, we're going to
1303 run into problems if we ever try to store a mount point that's
1304 over 256 but is under MAX_PATH! */
1305 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1308 if (err == ERROR_NO_MORE_ITEMS)
1310 else if (err != ERROR_SUCCESS)
1312 debug_printf ("RegEnumKeyEx failed, error %d!\n", err);
1316 if (iscygdrive (posix_path))
1318 /* This shouldn't be in the mount table. */
1319 // (void) r.kill (posix_path);
1323 /* Get a reg_key based on i. */
1324 reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1326 /* Check the mount table for prefix matches. */
1327 for (int j = 0; j < nmounts; j++)
1328 if (strcasematch (mount[j].posix_path, posix_path))
1329 goto next; /* Can't have more than one */
1331 /* Fetch info from the subkey. */
1332 subkey.get_string ("native", native_path, sizeof (native_path), "");
1333 mount_flags = subkey.get_int ("flags", 0);
1335 /* Add mount_item corresponding to registry mount point. */
1336 cygwin_shared->mount.add_item (native_path, posix_path, mount_flags);
1342 /* from_registry: Build the entire mount table from the registry. Also,
1343 read in cygdrive-related information from its registry location. */
1346 mount_info::from_registry ()
1348 /* Use current mount areas if either user or system mount areas
1349 already exist. Otherwise, import old mounts. */
1353 /* Retrieve cygdrive-related information. */
1354 read_cygdrive_info_from_registry ();
1358 /* First read mounts from user's table. */
1361 /* Then read mounts from system-wide mount table. */
1362 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1363 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1364 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1365 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1369 /* If we had to create both user and system mount areas, import
1371 if (had_to_create_mount_areas == 2)
1372 import_v1_mounts ();
1377 /* add_reg_mount: Add mount item to registry. Return zero on success,
1378 non-zero on failure. */
1379 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1382 mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1384 /* Add the mount to the right registry location, depending on
1385 whether MOUNT_SYSTEM is set in the mount flags. */
1386 if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
1388 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1391 /* Start by deleting existing mount if one exists. */
1392 reg_user.kill (posix_path);
1394 /* Create the new mount. */
1395 reg_key subkey = reg_key (reg_user.get_key (),
1398 subkey.set_string ("native", native_path);
1399 subkey.set_int ("flags", mountflags);
1401 else /* local_machine mount */
1403 /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
1404 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1405 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1406 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1407 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1410 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1416 /* Start by deleting existing mount if one exists. */
1417 reg_sys.kill (posix_path);
1419 /* Create the new mount. */
1420 reg_key subkey = reg_key (reg_sys.get_key (),
1423 subkey.set_string ("native", native_path);
1424 subkey.set_int ("flags", mountflags);
1427 return 0; /* Success! */
1430 /* del_reg_mount: delete mount item from registry indicated in flags.
1431 Return zero on success, non-zero on failure.*/
1432 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1435 mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1439 if ((flags & MOUNT_SYSTEM) == 0) /* Delete from user registry */
1441 reg_key reg_user (KEY_ALL_ACCESS,
1442 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
1443 killres = reg_user.kill (posix_path);
1445 else /* Delete from system registry */
1447 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1448 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1449 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1450 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1453 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1459 killres = reg_sys.kill (posix_path);
1462 if (killres != ERROR_SUCCESS)
1464 __seterrno_from_win_error (killres);
1468 return 0; /* Success! */
1471 /* read_cygdrive_info_from_registry: Read the default prefix and flags
1472 to use when creating cygdrives from the special user registry
1473 location used to store cygdrive information. */
1476 mount_info::read_cygdrive_info_from_registry ()
1478 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1481 if (r.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1483 /* Didn't find it so write the default to the registry and use it. */
1484 write_cygdrive_info_to_registry ("/cygdrive", MOUNT_AUTO);
1488 /* Fetch cygdrive_flags from registry; returns MOUNT_AUTO on error. */
1489 cygdrive_flags = r.get_int ("cygdrive flags", MOUNT_AUTO);
1490 slashify (cygdrive, cygdrive, 1);
1491 cygdrive_len = strlen(cygdrive);
1495 /* write_cygdrive_info_to_registry: Write the default prefix and flags
1496 to use when creating cygdrives to the special user registry
1497 location used to store cygdrive information. */
1500 mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1502 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1505 /* Verify cygdrive prefix starts with a forward slash and if there's
1506 another character, it's not a slash. */
1507 if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
1508 (cygdrive_prefix[0] != '/') ||
1509 ((cygdrive_prefix[1] != '\0') && (SLASH_P (cygdrive_prefix[1]))))
1515 char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1];
1516 /* Ensure that there is never a final slash */
1517 nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
1519 r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
1520 r.set_int ("cygdrive flags", flags);
1522 /* This also needs to go in the in-memory copy of "cygdrive" */
1523 slashify (cygdrive_prefix, cygwin_shared->mount.cygdrive, 1);
1524 cygwin_shared->mount.cygdrive_flags = flags;
1525 cygwin_shared->mount.cygdrive_len = strlen(cygwin_shared->mount.cygdrive);
1531 mount_info::getmntent (int x)
1533 if (x < 0 || x >= nmounts)
1536 return mount[native_sorted[x]].getmntent ();
1539 static mount_item *mounts_for_sort;
1541 /* sort_by_posix_name: qsort callback to sort the mount entries. Sort
1542 user mounts ahead of system mounts to the same POSIX path. */
1543 /* FIXME: should the user should be able to choose whether to
1544 prefer user or system mounts??? */
1546 sort_by_posix_name (const void *a, const void *b)
1548 mount_item *ap = mounts_for_sort + (*((int*) a));
1549 mount_item *bp = mounts_for_sort + (*((int*) b));
1551 /* Base weighting on longest posix path first so that the most
1552 obvious path will be chosen. */
1553 size_t alen = strlen (ap->posix_path);
1554 size_t blen = strlen (bp->posix_path);
1556 int res = blen - alen;
1559 return res; /* Path lengths differed */
1561 /* The two paths were the same length, so just determine normal
1562 lexical sorted order. */
1563 res = strcmp (ap->posix_path, bp->posix_path);
1567 /* need to select between user and system mount to same POSIX path */
1568 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1577 /* sort_by_native_name: qsort callback to sort the mount entries. Sort
1578 user mounts ahead of system mounts to the same POSIX path. */
1579 /* FIXME: should the user should be able to choose whether to
1580 prefer user or system mounts??? */
1582 sort_by_native_name (const void *a, const void *b)
1584 mount_item *ap = mounts_for_sort + (*((int*) a));
1585 mount_item *bp = mounts_for_sort + (*((int*) b));
1587 /* Base weighting on longest win32 path first so that the most
1588 obvious path will be chosen. */
1589 size_t alen = strlen (ap->native_path);
1590 size_t blen = strlen (bp->native_path);
1592 int res = blen - alen;
1595 return res; /* Path lengths differed */
1597 /* The two paths were the same length, so just determine normal
1598 lexical sorted order. */
1599 res = strcasecmp (ap->posix_path, bp->posix_path);
1603 /* need to select between user and system mount to same POSIX path */
1604 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1616 for (int i = 0; i < nmounts; i++)
1617 native_sorted[i] = posix_sorted[i] = i;
1618 /* Sort them into reverse length order, otherwise we won't
1619 be able to look for /foo in /. */
1620 mounts_for_sort = mount; /* ouch. */
1621 qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
1622 qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
1625 /* Add an entry to the in-memory mount table.
1626 Returns 0 on success, -1 on failure and errno is set.
1628 This is where all argument validation is done. It may not make sense to
1629 do this when called internally, but it's cleaner to keep it all here. */
1632 mount_info::add_item (const char *native, const char *posix, unsigned mountflags)
1634 /* Can't add more than MAX_MOUNTS. */
1635 if (nmounts == MAX_MOUNTS)
1641 /* Something's wrong if either path is NULL or empty, or if it's
1642 not a UNC or absolute path. */
1644 if ((native == NULL) || (*native == 0) ||
1645 (posix == NULL) || (*posix == 0) ||
1646 (!slash_unc_prefix_p (native) && !isabspath (native)))
1652 /* Make sure both paths do not end in /. */
1653 char nativetmp[MAX_PATH];
1654 char posixtmp[MAX_PATH];
1656 if (slash_drive_prefix_p (native))
1657 slash_drive_to_win32_path (native, nativetmp, 0);
1660 backslashify (native, nativetmp, 0);
1661 nofinalslash (nativetmp, nativetmp);
1664 slashify (posix, posixtmp, 0);
1665 nofinalslash (posixtmp, posixtmp);
1667 debug_printf ("%s[%s], %s[%s], %p",
1668 native, nativetmp, posix, posixtmp, mountflags);
1670 /* Duplicate /'s in path are an error. */
1671 for (char *p = posixtmp + 1; *p; ++p)
1673 if (p[-1] == '/' && p[0] == '/')
1680 /* Write over an existing mount item with the same POSIX path if
1681 it exists and is from the same registry area. */
1682 for (int i = 0; i < nmounts; i++)
1684 if ((strcmp (mount[i].posix_path, posixtmp) == 0) &&
1685 ((mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM)))
1687 /* replace existing mount item */
1688 mount[i].init (nativetmp, posixtmp, mountflags);
1693 mount[nmounts++].init (nativetmp, posixtmp, mountflags);
1701 /* Delete a mount table entry where path is either a Win32 or POSIX
1702 path. Since the mount table is really just a table of aliases,
1703 deleting / is ok (although running without a slash mount is
1704 strongly discouraged because some programs may run erratically
1705 without one). If MOUNT_SYSTEM is set in flags, remove from system
1706 registry, otherwise remove the user registry mount.
1710 mount_info::del_item (const char *path, unsigned flags)
1712 char pathtmp[MAX_PATH];
1714 /* Something's wrong if path is NULL or empty. */
1715 if ((path == NULL) || (*path == 0))
1721 slashify (path, pathtmp, 0);
1722 nofinalslash (pathtmp, pathtmp);
1724 debug_printf ("%s[%s]", path, pathtmp);
1726 for (int i = 0; i < nmounts; i++)
1728 /* Delete if paths and mount locations match. */
1729 if (((strcmp (mount[i].posix_path, pathtmp) == 0
1730 || strcmp (mount[i].native_path, pathtmp) == 0)) &&
1731 ((mount[i].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM)))
1733 nmounts--; /* One less mount table entry */
1734 /* Fill in the hole if not at the end of the table */
1736 memcpy (mount + i, mount + i + 1,
1737 sizeof (mount[i]) * (nmounts - i));
1738 sort (); /* Resort the table */
1746 /* read_v1_mounts: Given a reg_key to an old mount table registry area,
1747 read in the mounts. The "which" arg contains zero if we're reading
1748 the user area and MOUNT_SYSTEM if we're reading the system area.
1749 This way we can store the mounts read in the appropriate place when
1750 they are written back to the new registry layout. */
1753 mount_info::read_v1_mounts (reg_key r, unsigned which)
1755 unsigned mountflags = 0;
1757 /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
1758 for (int i = 0; i < 30; i++)
1761 char win32path[MAX_PATH];
1762 char unixpath[MAX_PATH];
1764 __small_sprintf (key_name, "%02x", i);
1766 reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
1768 /* The registry names are historical but useful so are left alone. */
1769 k.get_string ("native", win32path, sizeof (win32path), "");
1770 k.get_string ("unix", unixpath, sizeof (unixpath), "");
1772 /* Does this entry contain something? */
1773 if (*win32path != 0)
1777 if (k.get_int ("fbinary", 0))
1778 mountflags |= MOUNT_BINARY;
1780 /* Or in zero or MOUNT_SYSTEM depending on which table
1782 mountflags |= which;
1784 cygwin_shared->mount.add_item (win32path, unixpath, mountflags);
1789 /* from_v1_registry: Build the entire mount table from the old v1 registry
1793 mount_info::from_v1_registry ()
1795 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
1805 /* First read mounts from user's table. */
1806 read_v1_mounts (r, 0);
1808 /* Then read mounts from system-wide mount table. */
1809 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
1816 read_v1_mounts (r1, MOUNT_SYSTEM);
1818 /* Note: we don't need to sort internal table here since it is
1819 done in main from_registry call after this function would be
1823 /* import_v1_mounts: If v1 mounts are present, load them and write
1824 the new entries to the new registry area. */
1827 mount_info::import_v1_mounts ()
1829 /* Read in old mounts into memory. */
1830 from_v1_registry ();
1832 /* Write all mounts to the new registry. */
1836 /* to_registry: For every mount point in memory, add a corresponding
1837 registry mount point. */
1840 mount_info::to_registry ()
1842 for (int i = 0; i < MAX_MOUNTS; i++)
1846 mount_item *p = mount + i;
1848 add_reg_mount (p->native_path, p->posix_path, p->flags);
1850 debug_printf ("%02x: %s, %s, %d",
1851 i, p->native_path, p->posix_path, p->flags);
1856 /************************* mount_item class ****************************/
1859 mount_item::getmntent ()
1862 struct mntent &ret=_reent_winsup()->_ret;
1864 static NO_COPY struct mntent ret;
1867 /* Pass back pointers to mount_info strings reserved for use by
1868 getmntent rather than pointers to strings in the internal mount
1869 table because the mount table might change, causing weird effects
1870 from the getmntent user's point of view. */
1872 strcpy (cygwin_shared->mount.mnt_fsname, native_path);
1873 ret.mnt_fsname = cygwin_shared->mount.mnt_fsname;
1874 strcpy (cygwin_shared->mount.mnt_dir, posix_path);
1875 ret.mnt_dir = cygwin_shared->mount.mnt_dir;
1877 if (!(flags & MOUNT_SYSTEM)) /* user mount */
1878 strcpy (cygwin_shared->mount.mnt_type, (char *) "user");
1879 else /* system mount */
1880 strcpy (cygwin_shared->mount.mnt_type, (char *) "system");
1882 if ((flags & MOUNT_AUTO)) /* cygdrive */
1883 strcat (cygwin_shared->mount.mnt_type, (char *) ",auto");
1885 ret.mnt_type = cygwin_shared->mount.mnt_type;
1887 /* mnt_opts is a string that details mount params such as
1888 binary or textmode, or exec. We don't print
1889 `silent' here; it's a magic internal thing. */
1891 if (! (flags & MOUNT_BINARY))
1892 strcpy (cygwin_shared->mount.mnt_opts, (char *) "textmode");
1894 strcpy (cygwin_shared->mount.mnt_opts, (char *) "binmode");
1896 if (flags & MOUNT_EXEC)
1897 strcat (cygwin_shared->mount.mnt_opts, (char *) ",exec");
1899 ret.mnt_opts = cygwin_shared->mount.mnt_opts;
1906 /* Fill in the fields of a mount table entry. */
1909 mount_item::init (const char *native, const char *posix, unsigned mountflags)
1911 strcpy ((char *) native_path, native);
1912 strcpy ((char *) posix_path, posix);
1914 native_pathlen = strlen (native_path);
1915 posix_pathlen = strlen (posix_path);
1920 /********************** Mount System Calls **************************/
1922 /* Mount table system calls.
1923 Note that these are exported to the application. */
1925 /* mount: Add a mount to the mount table in memory and to the registry
1926 that will cause paths under win32_path to be translated to paths
1927 under posix_path. */
1931 mount (const char *win32_path, const char *posix_path, unsigned flags)
1935 if (flags & MOUNT_AUTO) /* normal mount */
1937 /* When flags include MOUNT_AUTO, take this to mean that
1938 we actually want to change the cygdrive prefix and flags
1939 without actually mounting anything. */
1940 res = cygwin_shared->mount.write_cygdrive_info_to_registry (posix_path, flags);
1945 if (iscygdrive (posix_path))
1948 return res; /* Don't try to add cygdrive prefix. */
1951 res = cygwin_shared->mount.add_reg_mount (win32_path, posix_path, flags);
1954 cygwin_shared->mount.add_item (win32_path, posix_path, flags);
1957 syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
1961 /* umount: The standard umount call only has a path parameter. Since
1962 it is not possible for this call to specify whether to remove the
1963 mount from the user or global mount registry table, assume the user
1968 umount (const char *path)
1970 return cygwin_umount (path, 0);
1973 /* cygwin_umount: This is like umount but takes an additional flags
1974 parameter that specifies whether to umount from the user or system-wide
1979 cygwin_umount (const char *path, unsigned flags)
1981 int res = cygwin_shared->mount.del_reg_mount (path, flags);
1984 cygwin_shared->mount.del_item (path, flags);
1986 syscall_printf ("%d = cygwin_umount (%s, %d)", res, path, flags);
1991 #define iteration _reent_winsup()->_iteration
1993 static int iteration;
1998 setmntent (const char *filep, const char *)
2001 return (FILE *) filep;
2008 return cygwin_shared->mount.getmntent (iteration++);
2018 /********************** Symbolic Link Support **************************/
2020 /* Create a symlink from FROMPATH to TOPATH. */
2024 symlink (const char *topath, const char *frompath)
2029 path_conv win32_path (frompath, SYMLINK_NOFOLLOW);
2030 if (win32_path.error)
2032 set_errno (win32_path.error);
2036 syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
2043 if (strlen (topath) >= MAX_PATH)
2045 set_errno (ENAMETOOLONG);
2049 if (win32_path.is_device () ||
2050 win32_path.file_attributes () != (DWORD) -1)
2056 h = CreateFileA(win32_path.get_win32 (), GENERIC_WRITE, 0, &sec_none_nih,
2057 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
2058 if (h == INVALID_HANDLE_VALUE)
2062 char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10];
2064 __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
2065 DWORD len = strlen (buf) + 1;
2067 /* Note that the terminating nul is written. */
2069 if (!WriteFile (h, buf, len, &written, NULL) || written != len)
2073 DeleteFileA (win32_path.get_win32 ());
2078 set_file_attribute (win32_path.has_acls (),
2079 win32_path.get_win32 (),
2080 S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
2081 SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_SYSTEM);
2087 syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath);
2091 static __inline char *
2092 has_suffix (const char *path, const suffix_info *suffixes)
2094 char *ext = strrchr (path, '.');
2096 for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
2097 if (strcasematch (ext, ex->name))
2102 static __inline__ int
2103 next_suffix (char *ext_here, const suffix_info *&suffixes)
2108 while (suffixes && suffixes->name)
2109 if (!suffixes->addon)
2113 strcpy (ext_here, suffixes->name);
2120 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2122 If PATH is a symlink, put the value of the symlink--the file to
2123 which it points--into BUF. The value stored in BUF is not
2124 necessarily null terminated. BUFLEN is the length of BUF; only up
2125 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2126 which case nothing will be stored.
2128 Set *SYML if PATH is a symlink.
2130 Set *EXEC if PATH appears to be executable. This is an efficiency
2131 hack because we sometimes have to open the file anyhow. *EXEC will
2132 not be set for every executable file.
2134 Return -1 on error, 0 if PATH is not a symlink, or the length
2135 stored into BUF if PATH is a symlink. */
2138 symlink_info::check (const char *in_path, const suffix_info *suffixes)
2142 char extbuf[MAX_PATH + 5];
2143 const char *path = in_path;
2147 else if ((known_suffix = has_suffix (in_path, suffixes)) != NULL)
2154 path = strcpy (extbuf, in_path);
2155 ext_here = strchr (path, '\0');
2162 if (!next_suffix (ext_here, suffixes))
2164 fileattr = GetFileAttributesA (path);
2165 if (fileattr == (DWORD) -1)
2167 /* The GetFileAttributesA call can fail for reasons that don't
2168 matter, so we just return 0. For example, getting the
2169 attributes of \\HOST will typically fail. */
2170 debug_printf ("GetFileAttributesA (%s) failed", path);
2175 /* Windows allows path\. even when `path' isn't a directory.
2176 Detect this scenario and disallow it, since it is non-UNIX like. */
2177 char *p = strchr (path, '\0');
2178 if (p > path + 1 && p[-1] == '.' && SLASH_P (p[-2]) &&
2179 !(fileattr & FILE_ATTRIBUTE_DIRECTORY))
2181 debug_printf ("\\. specified on non-directory");
2182 set_errno (ENOTDIR);
2186 /* A symlink will have the `system' file attribute. */
2187 /* Only files can be symlinks (which can be symlinks to directories). */
2188 if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))
2189 goto file_not_symlink;
2191 /* Check the file's extended attributes, if it has any. */
2193 if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
2194 unixattr |= S_IFDIR;
2196 if (!get_file_attribute (TRUE, path, &unixattr))
2198 if (unixattr & STD_XBITS)
2199 pflags |= PATH_EXEC;
2202 /* Open the file. */
2204 h = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
2205 FILE_ATTRIBUTE_NORMAL, 0);
2207 syscall_printf ("opened '%s'(%p)", path, h);
2210 if (h == INVALID_HANDLE_VALUE)
2214 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2217 syscall_printf ("ReadFile");
2218 if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
2220 else if (got == sizeof (cookie_buf)
2221 && memcmp (cookie_buf, SYMLINK_COOKIE,
2222 sizeof (cookie_buf)) == 0)
2224 /* It's a symlink. */
2225 pflags = PATH_SYMLINK;
2227 res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2232 /* Versions prior to b16 stored several trailing
2233 NULs with the path (to fill the path out to 1024
2234 chars). Current versions only store one trailing
2235 NUL. The length returned is the path without
2236 *any* trailing NULs. We also have to handle (or
2237 at least not die from) corrupted paths. */
2238 if (memchr (contents, 0, got) != NULL)
2239 res = strlen (contents);
2244 else if (got == sizeof (cookie_buf)
2245 && memcmp (cookie_buf, SOCKET_COOKIE,
2246 sizeof (cookie_buf)) == 0)
2248 pflags |= PATH_SOCKET;
2249 goto close_and_return;
2253 /* Not a symlink, see if executable. */
2254 if (!(pflags & PATH_EXEC) && got >= 2 &&
2255 ((cookie_buf[0] == '#' && cookie_buf[1] == '!') ||
2256 (cookie_buf[0] == ':' && cookie_buf[1] == '\n')))
2257 pflags |= PATH_EXEC;
2259 syscall_printf ("close_and_return");
2261 goto file_not_symlink;
2265 syscall_printf ("breaking from loop");
2275 syscall_printf ("not a symlink");
2279 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2280 res, path, contents, pflags);
2285 /* readlink system call */
2289 readlink (const char *path, char *buf, int buflen)
2291 extern suffix_info stat_suffixes[];
2292 path_conv pathbuf (path, SYMLINK_CONTENTS, 0, stat_suffixes);
2296 set_errno (pathbuf.error);
2297 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2301 if (!pathbuf.issymlink ())
2303 if (pathbuf.fileattr != (DWORD) -1)
2308 int len = strlen (pathbuf.get_win32 ());
2309 if (len > (buflen - 1))
2311 set_errno (ENAMETOOLONG);
2314 memcpy (buf, pathbuf.get_win32 (), len);
2317 /* errno set by symlink.check if error */
2321 /* Some programs rely on st_dev/st_ino being unique for each file.
2322 Hash the path name and hope for the best. The hash arg is not
2323 always initialized to zero since readdir needs to compute the
2324 dirent ino_t based on a combination of the hash of the directory
2325 done during the opendir call and the hash or the filename within
2326 the directory. FIXME: Not bullet-proof. */
2327 /* Cygwin internal */
2329 unsigned long __stdcall
2330 hash_path_name (unsigned long hash, const char *name)
2335 /* Perform some initial permutations on the pathname if this is
2339 /* Simplistic handling of drives. If there is a drive specified,
2340 make sure that the initial letter is upper case. If there is
2341 no \ after the ':' assume access through the root directory
2343 FIXME: Should really honor MS-Windows convention of using
2344 the environment to track current directory on various drives. */
2347 char *nn, *newname = (char *) alloca (strlen (name) + 2);
2348 nn = strncpy (newname, name, 2);
2350 *newname = toupper (*nn);
2363 /* Fill out the hashed path name with the current working directory if
2364 this is not an absolute path and there is no pre-specified hash value.
2365 Otherwise the inodes same will differ depending on whether a file is
2366 referenced with an absolute value or relatively. */
2368 if (*name != '\\' && (current_directory_name == NULL ||
2369 get_current_directory_name ()))
2371 hash = current_directory_hash;
2372 if (name[0] == '.' && name[1] == '\0')
2374 hash = hash_path_name (hash, "\\");
2379 /* Build up hash. Ignore single trailing slash or \a\b\ != \a\b or
2380 \a\b\. but allow a single \ if that's all there is. */
2383 hash += *name + (*name << 17);
2386 while (*++name != '\0' &&
2387 !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
2392 get_current_directory_name ()
2396 for (dlen = 256; ; dlen *= 2)
2398 current_directory_name = (char *) realloc (current_directory_name, dlen + 2);
2399 if ((len = GetCurrentDirectoryA (dlen, current_directory_name)) < dlen)
2406 current_directory_hash = hash_path_name (0, current_directory_name);
2414 getcwd_inner (char *buf, size_t ulen, int posix_p)
2416 char *resbuf = NULL;
2419 if (current_directory_name == NULL && !get_current_directory_name ())
2424 if (strlen (current_directory_name) >= len)
2428 strcpy (buf, current_directory_name);
2432 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, win32) (cached)",
2433 resbuf, resbuf ? resbuf : "", buf, len);
2436 else if (current_directory_posix_name != NULL)
2438 if (strlen (current_directory_posix_name) >= len)
2442 strcpy (buf, current_directory_posix_name);
2446 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, posix) (cached)",
2447 resbuf, resbuf ? resbuf : "", buf, len);
2451 /* posix_p required and current_directory_posix_name == NULL */
2453 char temp[MAX_PATH];
2455 /* Turn from Win32 style to our style. */
2456 cygwin_shared->mount.conv_to_posix_path (current_directory_name, temp, 0);
2458 size_t tlen = strlen (temp);
2460 current_directory_posix_name = (char *) realloc (
2461 current_directory_posix_name, tlen + 1);
2462 if (current_directory_posix_name != NULL)
2463 strcpy (current_directory_posix_name, temp);
2467 /* len was too small */
2476 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, %s)",
2477 resbuf, resbuf ? resbuf : "",
2478 buf, len, posix_p ? "posix" : "win32");
2483 getcwd (char *buf, size_t ulen)
2487 if (buf == NULL || ulen == 0)
2489 buf = (char *) alloca (MAX_PATH);
2490 res = getcwd_inner (buf, MAX_PATH, 1);
2495 res = getcwd_inner (buf, ulen, 1);
2501 /* getwd: standards? */
2506 return getcwd (buf, MAX_PATH);
2509 /* chdir: POSIX 5.2.1.1 */
2512 chdir (const char *dir)
2514 path_conv path (dir);
2518 set_errno (path.error);
2519 syscall_printf ("-1 = chdir (%s)", dir);
2523 char *native_dir = path.get_win32 ();
2525 /* Check to see if path translates to something like C:.
2526 If it does, append a \ to the native directory specification to
2527 defeat the Windows 95 (i.e. MS-DOS) tendency of returning to
2528 the last directory visited on the given drive. */
2529 if (isalpha (native_dir[0]) && native_dir[1] == ':' && !native_dir[2])
2531 native_dir[2] = '\\';
2532 native_dir[3] = '\0';
2534 int res = SetCurrentDirectoryA (native_dir);
2538 /* Clear the cache until we need to retrieve the directory again. */
2539 if (current_directory_name != NULL)
2541 free (current_directory_name);
2542 current_directory_name = NULL;
2544 if (current_directory_posix_name != NULL)
2546 free (current_directory_posix_name);
2547 current_directory_posix_name = NULL;
2550 syscall_printf ("%d = chdir (%s) (dos %s)", res ? 0 : -1, dir, native_dir);
2551 return res ? 0 : -1;
2554 /******************** Exported Path Routines *********************/
2556 /* Cover functions to the path conversion routines.
2557 These are exported to the world as cygwin_foo by cygwin.din. */
2561 cygwin_conv_to_win32_path (const char *path, char *win32_path)
2563 path_conv p (path, SYMLINK_FOLLOW, 0);
2566 set_errno (p.error);
2570 strcpy (win32_path, p.get_win32 ());
2576 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
2578 path_conv p (path, SYMLINK_FOLLOW, 1);
2581 set_errno (p.error);
2585 strcpy (win32_path, p.get_win32 ());
2589 /* This is exported to the world as cygwin_foo by cygwin.din. */
2593 cygwin_conv_to_posix_path (const char *path, char *posix_path)
2595 if (check_null_empty_path_errno (path))
2597 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 1);
2603 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
2605 if (check_null_empty_path_errno (path))
2607 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 0);
2611 /* The realpath function is supported on some UNIX systems. */
2615 realpath (const char *path, char *resolved)
2619 path_conv real_path (path, SYMLINK_FOLLOW, 1);
2621 if (real_path.error)
2622 err = real_path.error;
2625 err = cygwin_shared->mount.conv_to_posix_path (real_path.get_win32 (), resolved, 0);
2630 /* FIXME: on error, we are supposed to put the name of the path
2631 component which could not be resolved into RESOLVED. */
2638 /* Return non-zero if path is a POSIX path list.
2639 This is exported to the world as cygwin_foo by cygwin.din.
2642 <sect1 id="add-func-cygwin-posix-path-list-p">
2643 <para>Rather than use a mode to say what the "proper" path list
2644 format is, we allow any, and give apps the tools they need to
2645 convert between the two. If a ';' is present in the path list it's
2646 a Win32 path list. Otherwise, if the first path begins with
2647 [letter]: (in which case it can be the only element since if it
2648 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
2649 it's a POSIX path list.</para>
2656 cygwin_posix_path_list_p (const char *path)
2658 int posix_p = ! (strchr (path, ';')
2659 || (isalpha (path[0]) && path[1] == ':'));
2663 /* These are used for apps that need to convert env vars like PATH back and
2664 forth. The conversion is a two step process. First, an upper bound on the
2665 size of the buffer needed is computed. Then the conversion is done. This
2666 allows the caller to use alloca if it wants. */
2669 conv_path_list_buf_size (const char *path_list, int to_posix_p)
2671 int i, num_elms, max_mount_path_len, size;
2674 /* The theory is that an upper bound is
2675 current_size + (num_elms * max_mount_path_len) */
2677 char delim = to_posix_p ? ';' : ':';
2679 for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms)
2682 /* 7: strlen ("//c") + slop, a conservative initial value */
2683 for (max_mount_path_len = 7, i = 0; i < cygwin_shared->mount.nmounts; ++i)
2685 int mount_len = (to_posix_p
2686 ? cygwin_shared->mount.mount[i].posix_pathlen
2687 : cygwin_shared->mount.mount[i].native_pathlen);
2688 if (max_mount_path_len < mount_len)
2689 max_mount_path_len = mount_len;
2693 size = strlen (path_list) + (num_elms * max_mount_path_len) + 100;
2699 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
2701 return conv_path_list_buf_size (path_list, 1);
2706 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
2708 return conv_path_list_buf_size (path_list, 0);
2713 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
2715 conv_path_list (win32, posix, 1);
2721 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
2723 conv_path_list (posix, win32, 0);
2727 /* cygwin_split_path: Split a path into directory and file name parts.
2728 Buffers DIR and FILE are assumed to be big enough.
2730 Examples (path -> `dir' / `file'):
2733 . -> `.' / `.' (FIXME: should this be `.' / `'?)
2734 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
2736 foo/bar -> `foo' / `bar'
2737 foo/bar/ -> `foo' / `bar'
2739 /foo/bar -> `/foo' / `bar'
2742 c:foo -> `c:/' / `foo'
2743 c:/foo -> `c:/' / `foo'
2748 cygwin_split_path (const char *path, char *dir, char *file)
2750 int dir_started_p = 0;
2752 /* Deal with drives.
2753 Remember that c:foo <==> c:/foo. */
2754 if (isalpha (path[0]) && path[1] == ':')
2765 if (SLASH_P (*path))
2770 /* Determine if there are trailing slashes and "delete" them if present.
2771 We pretend as if they don't exist. */
2772 const char *end = path + strlen (path);
2773 /* path + 1: keep leading slash. */
2774 while (end > path + 1 && SLASH_P (end[-1]))
2777 /* At this point, END points to one beyond the last character
2778 (with trailing slashes "deleted"). */
2780 /* Point LAST_SLASH at the last slash (duh...). */
2781 const char *last_slash;
2782 for (last_slash = end - 1; last_slash >= path; --last_slash)
2783 if (SLASH_P (*last_slash))
2786 if (last_slash == path)
2791 else if (last_slash > path)
2793 memcpy (dir, path, last_slash - path);
2794 dir[last_slash - path] = 0;
2799 ; /* nothing to do */
2805 memcpy (file, last_slash + 1, end - last_slash - 1);
2806 file[end - last_slash - 1] = 0;
2809 /********************** String Helper Functions ************************/
2811 #define CHXOR ('a' ^ 'A')
2812 #define ch_case_eq(ch1, ch2) \
2815 !((x = ((unsigned char)ch1 ^ (unsigned char)ch2)) && \
2816 (x != CHXOR || !isalpha (ch1))); \
2820 strncasematch (const char *s1, const char *s2, size_t n)
2828 if (!ch_case_eq (*s1, *s2))
2832 return !n || *s2 == '\0';
2836 strcasematch (const char *s1, const char *s2)
2843 if (!ch_case_eq (*s1, *s2))
2851 strcasestr (const char *searchee, const char *lookfor)
2857 return (char *) searchee;
2865 if (lookfor[i] == 0)
2866 return (char *) searchee;
2868 if (!ch_case_eq (lookfor[i], searchee[i]))