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
77 #include <sys/mount.h>
93 static int normalize_win32_path (const char *cwd, const char *src, char *dst);
94 static char *getcwd_inner (char *buf, size_t ulen, int posix_p, int with_chroot);
95 static void slashify (const char *src, char *dst, int trailing_slash_p);
96 static void backslashify (const char *src, char *dst, int trailing_slash_p);
97 static int path_prefix_p_ (const char *path1, const char *path2, int len1);
98 static int get_cwd_win32 ();
100 static NO_COPY const char escape_char = '^';
104 char buf[3 + MAX_PATH * 3];
112 symlink_info (): known_suffix (NULL), contents (buf + MAX_PATH + 1) {}
113 int check (const char *path, const suffix_info *suffixes);
116 /********************** Path Helper Functions *************************/
118 #define path_prefix_p(p1, p2, l1) \
119 ((tolower(*(p1))==tolower(*(p2))) && \
120 path_prefix_p_(p1, p2, l1))
122 #define SYMLINKATTR(x) \
123 (((x) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) == \
124 FILE_ATTRIBUTE_SYSTEM)
126 /* Return non-zero if PATH1 is a prefix of PATH2.
127 Both are assumed to be of the same path style and / vs \ usage.
129 LEN1 = strlen (PATH1). It's passed because often it's already known.
132 /foo/ is a prefix of /foo <-- may seem odd, but desired
133 /foo is a prefix of /foo/
134 / is a prefix of /foo/bar
135 / is not a prefix of foo/bar
136 foo/ is a prefix foo/bar
137 /foo is not a prefix of /foobar
140 /* Determine if path prefix matches current cygdrive */
141 #define iscygdrive(path) \
142 (path_prefix_p (cygwin_shared->mount.cygdrive, (path), cygwin_shared->mount.cygdrive_len))
144 #define iscygdrive_device(path) \
145 (iscygdrive(path) && isalpha(path[cygwin_shared->mount.cygdrive_len]) && \
146 (isdirsep(path[cygwin_shared->mount.cygdrive_len + 1]) || \
147 !path[cygwin_shared->mount.cygdrive_len + 1]))
149 /******************** Directory-related Support **************************/
151 /* Cache getcwd value. FIXME: We need a lock for these in order to
152 support multiple threads. */
154 #define TMPCWD ((char *) alloca (MAX_PATH + 1))
167 cwd_win32 (char *buf)
170 cwd.lock->acquire ();
171 if (cwd.win32 == NULL)
173 else if (buf == NULL)
176 ret = strcpy (buf, cwd.win32);
177 cwd.lock->release ();
182 cwd_posix (char *buf)
185 cwd.lock->acquire ();
186 if (cwd.posix == NULL)
188 else if (buf == NULL)
191 ret = strcpy (buf, cwd.posix);
192 cwd.lock->release ();
200 cwd.lock->acquire ();
202 cwd.lock->release ();
209 cwd.lock = new_muto (FALSE, "cwd");
213 cwd_fixup_after_exec (char *win32, char *posix, DWORD hash)
220 #define ischrootpath(path) \
221 (myself->rootlen && \
222 strncasematch (myself->root, path, myself->rootlen) && \
223 (path[myself->rootlen] == '/' || path[myself->rootlen] == '\0'))
226 path_prefix_p_ (const char *path1, const char *path2, int len1)
228 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
229 if (len1 > 0 && SLASH_P (path1[len1 - 1]))
233 return SLASH_P (path2[0]) && !SLASH_P (path2[1]);
235 if (!strncasematch (path1, path2, len1))
238 return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
241 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
242 passing to Win32 API routines.
244 If an error occurs, `error' is set to the errno value.
245 Otherwise it is set to 0.
248 SYMLINK_FOLLOW - convert to PATH symlink points to
249 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
250 SYMLINK_IGNORE - do not check PATH for symlinks
251 SYMLINK_CONTENTS - just return symlink contents
255 path_conv::check (const char *src, unsigned opt,
256 const suffix_info *suffixes)
258 /* This array is used when expanding symlinks. It is MAX_PATH * 2
259 in length so that we can hold the expanded symlink plus a
261 char path_buf[MAX_PATH];
262 char path_copy[MAX_PATH];
263 char tmp_buf[MAX_PATH];
266 char *rel_path, *full_path;
268 if (!(opt & PC_NULLEMPTY))
270 else if ((error = check_null_empty_path (src)))
274 rel_path = path_buf, full_path = this->path;
276 rel_path = this->path, full_path = path_buf;
278 /* This loop handles symlink expansion. */
282 fileattr = (DWORD) -1;
286 /* Must look up path in mount table, etc. */
287 error = cygwin_shared->mount.conv_to_win32_path (src, rel_path,
289 devn, unit, &path_flags);
299 /* Eat trailing slashes */
300 char *tail = strchr (full_path, '\0');
301 /* If path is only a drivename, Windows interprets it as
302 the current working directory on this drive instead of
303 the root dir which is what we want. So we need
304 the trailing backslash in this case. */
305 while (tail > full_path + 3 && (*--tail == '\\'))
307 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
308 strcat (full_path, "\\");
310 if (opt & PC_SYM_IGNORE)
312 fileattr = GetFileAttributesA (path);
316 /* Make a copy of the path that we can munge up */
317 strcpy (path_copy, full_path);
319 tail = path_copy + 1 + (tail - full_path); // Point to end of copy
321 /* Scan path_copy from right to left looking either for a symlink
322 or an actual existing file. If an existing file is found, just
323 return. If a symlink is found exit the for loop.
324 Also: be careful to preserve the errno returned from
325 symlink.check as the caller may need it. */
326 /* FIXME: Do we have to worry about multiple \'s here? */
327 int component = 0; // Number of translated components
328 sym.contents[0] = '\0';
332 const suffix_info *suff;
334 /* Don't allow symlink.check to set anything in the path_conv
335 class if we're working on an inner component of the path */
344 sym.pflags = path_flags;
347 int len = sym.check (path_copy, suff);
350 path_flags = sym.pflags;
352 /* If symlink.check found an existing non-symlink file, then
353 it sets the appropriate flag. It also sets any suffix found
355 if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
360 fileattr = sym.fileattr;
363 goto out; // file found
365 /* Found a symlink if len > 0. If component == 0, then the
366 src path itself was a symlink. If !follow_mode then
367 we're done. Otherwise we have to insert the path found
368 into the full path that we are building and perform all of
369 these operations again on the newly derived path. */
372 if (component == 0 && !(opt & PC_SYM_FOLLOW))
374 set_symlink (); // last component of path is a symlink.
375 fileattr = sym.fileattr;
376 if (opt & PC_SYM_CONTENTS)
377 strcpy (path, sym.contents);
383 /* No existing file found. */
385 if (!(tail = strrchr (path_copy, '\\')) ||
386 (tail > path_copy && tail[-1] == ':'))
387 goto out; // all done
389 /* Haven't found a valid pathname component yet.
390 Pinch off the tail and try again. */
395 /* Arrive here if above loop detected a symlink. */
396 if (++loop > MAX_LINK_DEPTH)
398 error = ELOOP; // Eep.
403 tail = full_path + (tail - path_copy);
404 int taillen = strlen (tail);
405 int buflen = strlen (sym.contents);
406 if (buflen + taillen > MAX_PATH)
408 error = ENAMETOOLONG;
409 strcpy (path, "::ENAMETOOLONG::");
413 /* Copy tail of full_path to discovered symlink. */
415 for (p = sym.contents + buflen; *tail; tail++)
416 *p++ = *tail == '\\' ? '/' : *tail;
419 /* If symlink referred to an absolute path, then we
420 just use sym.contents and loop. Otherwise tack the head of
421 path_copy before sym.contents and translate it back from a
422 Win32-style path to a POSIX-style one. */
423 if (isabspath (sym.contents))
425 else if (!(tail = strrchr (path_copy, '\\')))
426 system_printf ("problem parsing %s - '%s'", src, full_path);
429 int headlen = 1 + tail - path_copy;
430 p = sym.contents - headlen;
431 memcpy (p, path_copy, headlen);
433 error = cygwin_shared->mount.conv_to_posix_path (p, tmp_buf, 1);
442 if (sym.known_suffix)
443 known_suffix = this->path + (sym.known_suffix - path_copy);
444 else if (sym.ext_here && !(opt & PC_SYM_CONTENTS))
446 known_suffix = strchr (this->path, '\0');
447 strcpy (known_suffix, sym.ext_here);
451 DWORD serial, volflags;
453 strcpy (tmp_buf, full_path);
454 if (!rootdir (tmp_buf) ||
455 !GetVolumeInformation (tmp_buf, NULL, 0, &serial, NULL, &volflags, NULL, 0))
457 debug_printf ("GetVolumeInformation(%s) = ERR, full_path(%s), set_has_acls(FALSE)",
458 tmp_buf, full_path, GetLastError ());
459 set_has_acls (FALSE);
463 debug_printf ("GetVolumeInformation(%s) = OK, full_path(%s), set_has_acls(%d)",
464 tmp_buf, full_path, volflags & FS_PERSISTENT_ACLS);
465 set_has_acls (volflags & FS_PERSISTENT_ACLS);
469 #define deveq(s) (strcasematch (name, (s)))
470 #define deveqn(s, n) (strncasematch (name, (s), (n)))
473 digits (const char *name)
476 int n = strtol(name, &p, 10);
478 return p > name && !*p ? n : -1;
481 const char *windows_device_names[] =
508 get_raw_device_number (const char *uxname, const char *w32path, int &unit)
512 if (strncasematch (w32path, "\\\\.\\tape", 8))
515 unit = digits (w32path + 8);
516 // norewind tape devices have leading n in name
517 if (strncasematch (uxname, "/dev/n", 6))
520 else if (isdrive (w32path + 4))
523 unit = tolower (w32path[4]) - 'a';
525 else if (strncasematch (w32path, "\\\\.\\physicaldrive", 17))
528 unit = digits (w32path + 17) + 128;
534 get_device_number (const char *name, int &unit, BOOL from_conv)
539 if ((*name == '/' && deveqn ("/dev/", 5)) ||
540 (*name == '\\' && deveqn ("\\dev\\", 5)))
545 if (tty_attached (myself))
550 else if (myself->ctty > 0)
553 else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
555 else if (deveq ("ttym"))
557 else if (deveq ("ptmx"))
559 else if (deveq ("windows"))
561 else if (deveq ("conin"))
563 else if (deveq ("conout"))
565 else if (deveq ("null"))
567 else if (deveq ("zero"))
569 else if (deveq ("random") || deveq ("urandom"))
572 unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
574 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
576 else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew"))
578 else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket")
579 || deveq ("dgsocket"))
581 else if (! from_conv)
582 devn = get_raw_device_number (name - 5,
584 PC_SYM_IGNORE).get_win32 (),
587 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
593 /* Return TRUE if src_path is a Win32 device name, filling out the device
594 name in win32_path */
597 win32_device_name (const char *src_path, char *win32_path,
598 DWORD &devn, int &unit)
602 devn = get_device_number (src_path, unit, TRUE);
607 if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL)
609 if (devn == FH_RANDOM)
610 __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
612 __small_sprintf (win32_path, devfmt, unit);
616 /* Normalize a POSIX path.
617 \'s are converted to /'s in the process.
618 All duplicate /'s, except for 2 leading /'s, are deleted.
619 The result is 0 for success, or an errno error value. */
621 #define isslash(c) ((c) == '/')
624 normalize_posix_path (const char *cwd, const char *src, char *dst)
626 const char *src_start = src;
627 char *dst_start = dst;
629 syscall_printf ("cwd %s, src %s", cwd, src);
630 if (isdrive (src) || strpbrk (src, "\\:"))
632 cygwin_conv_to_full_posix_path (src, dst);
635 if (!isslash (src[0]))
637 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
639 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
643 dst = strchr (dst, '\0');
646 if (dst == dst_start + 1)
650 if (dst > dst_start && !isslash (dst[-1]))
653 /* Two leading /'s? If so, preserve them. */
654 else if (isslash (src[1]))
658 debug_printf ("ENOENT = normalize_posix_path (%s)", src);
665 { /* Starts with three or more slashes - reset. */
671 /* Exactly one leading slash. Absolute path. Check for chroot. */
672 else if (myself->rootlen)
674 strcpy (dst, myself->root);
675 dst += myself->rootlen;
680 /* Strip runs of /'s. */
687 while (isslash (*src))
696 if (!src[1] || !isslash (src[1]))
701 if (src[2] && !isslash (src[2]))
703 if (!ischrootpath (dst_start) ||
704 dst - dst_start != (int) myself->rootlen)
705 while (dst > dst_start && !isslash (*--dst))
716 if (--dst > dst_start && isslash (*dst))
719 debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start);
723 /* Normalize a Win32 path.
724 /'s are converted to \'s in the process.
725 All duplicate \'s, except for 2 leading \'s, are deleted.
727 The result is 0 for success, or an errno error value.
728 FIXME: A lot of this should be mergeable with the POSIX critter. */
730 normalize_win32_path (const char *cwd, const char *src, char *dst)
732 const char *src_start = src;
733 char *dst_start = dst;
734 char *dst_root_start = dst;
736 if (!SLASH_P (src[0]) && strchr (src, ':') == NULL)
738 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
740 debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
745 if (!*cwd || !SLASH_P (dst[-1]))
748 /* Two leading \'s? If so, preserve them. */
749 else if (SLASH_P (src[0]) && SLASH_P (src[1]))
753 debug_printf ("ENOENT = normalize_win32_path (%s)", src);
759 /* If absolute path, care for chroot. */
760 else if (SLASH_P (src[0]) && !SLASH_P (src[1]) && myself->rootlen)
762 strcpy (dst, myself->root);
764 while ((c = strchr (dst, '/')) != NULL)
766 dst += myself->rootlen;
767 dst_root_start = dst;
773 /* Strip duplicate /'s. */
774 if (SLASH_P (src[0]) && SLASH_P (src[1]))
777 else if (src[0] == '.' && SLASH_P (src[1])
778 && (src == src_start || SLASH_P (src[-1])))
783 /* Backup if "..". */
784 else if (src[0] == '.' && src[1] == '.'
785 /* dst must be greater than dst_start */
787 && (SLASH_P (src[2]) || src[2] == 0))
789 /* Back up over /, but not if it's the first one. */
790 if (dst > dst_root_start + 1)
792 /* Now back up to the next /. */
793 while (dst > dst_root_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
799 /* Otherwise, add char to result. */
810 debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
815 /* Various utilities. */
817 /* slashify: Convert all back slashes in src path to forward slashes
818 in dst path. Add a trailing slash to dst when trailing_slash_p arg
822 slashify (const char *src, char *dst, int trailing_slash_p)
824 const char *start = src;
836 && !isdirsep (src[-1]))
841 /* backslashify: Convert all forward slashes in src path to back slashes
842 in dst path. Add a trailing slash to dst when trailing_slash_p arg
846 backslashify (const char *src, char *dst, int trailing_slash_p)
848 const char *start = src;
860 && !isdirsep (src[-1]))
865 /* nofinalslash: Remove trailing / and \ from SRC (except for the
866 first one). It is ok for src == dst. */
869 nofinalslash (const char *src, char *dst)
871 int len = strlen (src);
873 memcpy (dst, src, len + 1);
874 while (len > 1 && SLASH_P (dst[--len]))
878 /* slash_drive_prefix_p: Return non-zero if PATH begins with
882 slash_drive_prefix_p (const char *path)
884 return (isdirsep(path[0])
887 && (path[3] == 0 || path[3] == '/'));
890 /* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
893 slash_unc_prefix_p (const char *path)
896 int ret = (isdirsep (path[0])
897 && isdirsep (path[1])
900 && !isdirsep (path[3])
901 && ((p = strchr(&path[3], '/')) != NULL));
902 if (!ret || p == NULL)
904 return ret && isalnum (p[1]);
907 /* conv_path_list: Convert a list of path names to/from Win32/POSIX.
909 SRC is not a const char * because we temporarily modify it to ease
912 I believe Win32 always has '.' in $PATH. POSIX obviously doesn't.
913 We certainly don't want to handle that here, but it is something for
914 the caller to think about. */
917 conv_path_list (const char *src, char *dst, int to_posix_p)
921 char src_delim = to_posix_p ? ';' : ':';
922 char dst_delim = to_posix_p ? ':' : ';';
923 int (*conv_fn) (const char *, char *) = (to_posix_p
924 ? cygwin_conv_to_posix_path
925 : cygwin_conv_to_win32_path);
929 s = strchr (src, src_delim);
933 (*conv_fn) (src[0] != 0 ? src : ".", d);
942 (*conv_fn) (src[0] != 0 ? src : ".", d);
948 /************************* mount_info class ****************************/
950 /* init: Initialize the mount table. */
956 had_to_create_mount_areas = 0;
958 /* Fetch the mount table and cygdrive-related information from
963 /* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
964 the result in win32_path.
966 If win32_path != NULL, the relative path, if possible to keep, is
967 stored in win32_path. If the relative path isn't possible to keep,
968 the full path is stored.
970 If full_win32_path != NULL, the full path is stored there.
972 The result is zero for success, or an errno value.
974 {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */
977 mount_info::conv_to_win32_path (const char *src_path, char *win32_path,
978 char *full_win32_path, DWORD &devn, int &unit,
981 int src_path_len = strlen (src_path);
982 int trailing_slash_p = (src_path_len > 1
983 && SLASH_P (src_path[src_path_len - 1]));
986 unsigned dummy_flags;
992 flags = &dummy_flags;
995 debug_printf ("conv_to_win32_path (%s)", src_path);
997 if (src_path_len >= MAX_PATH)
999 debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path);
1000 return ENAMETOOLONG;
1005 mount_item *mi = NULL; /* initialized to avoid compiler warning */
1006 char pathbuf[MAX_PATH];
1009 getcwd_inner (cwd, MAX_PATH, TRUE, 0); /* FIXME: check rc */
1011 /* Determine where the destination should be placed. */
1012 if (full_win32_path != NULL)
1013 dst = full_win32_path;
1014 else if (win32_path != NULL)
1018 goto out; /* Sanity check. */
1020 /* An MS-DOS spec has either a : or a \. If this is found, short
1021 circuit most of the rest of this function. */
1022 if (strpbrk (src_path, ":\\") != NULL)
1024 debug_printf ("%s already win32", src_path);
1025 rc = normalize_win32_path (cwd_win32 (TMPCWD), src_path, dst);
1028 debug_printf ("normalize_win32_path failed, rc %d", rc);
1031 isrelpath = !isabspath (src_path);
1032 *flags = set_flags_from_win32_path (dst);
1033 if (myself->rootlen && dst[0] && dst[1] == ':')
1035 char posix_path[MAX_PATH + 1];
1037 rc = cygwin_shared->mount.conv_to_posix_path (dst, posix_path, 0);
1040 debug_printf ("conv_to_posix_path failed, rc %d", rc);
1043 if (!ischrootpath (posix_path))
1045 debug_printf ("ischrootpath failed");
1052 /* Normalize the path, taking out ../../ stuff, we need to do this
1053 so that we can move from one mounted directory to another with relative
1056 eg mounting c:/foo /foo
1062 should look in c:/foo, not d:/foo.
1064 We do this by first getting an absolute UNIX-style path and then
1065 converting it to a DOS-style path, looking up the appropriate drive
1066 in the mount table. */
1068 /* No need to fetch cwd if path is absolute. */
1069 isrelpath = !isslash (*src_path);
1071 rc = normalize_posix_path (cwd, src_path, pathbuf);
1075 debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
1080 /* See if this is a cygwin "device" */
1081 if (win32_device_name (pathbuf, dst, devn, unit))
1083 *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */
1087 /* Check if the cygdrive prefix was specified. If so, just strip
1088 off the prefix and transform it into an MS-DOS path. */
1090 if (iscygdrive_device (pathbuf))
1092 if (!cygdrive_win32_path (pathbuf, dst, trailing_slash_p))
1094 *flags = cygdrive_flags;
1098 /* Check the mount table for prefix matches. */
1099 for (i = 0; i < nmounts; i++)
1101 mi = mount + posix_sorted[i];
1102 if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen))
1108 if (slash_drive_prefix_p (pathbuf))
1109 slash_drive_to_win32_path (pathbuf, dst, trailing_slash_p);
1111 backslashify (pathbuf, dst, trailing_slash_p); /* just convert */
1116 int n = mi->native_pathlen;
1117 memcpy (dst, mi->native_path, n + 1);
1118 char *p = pathbuf + mi->posix_pathlen;
1119 if (!trailing_slash_p && !*p)
1121 if (isdrive (dst) && !dst[2])
1127 /* Do not add trailing \ to UNC device names like \\.\a: */
1128 if (*p != '/' && /* FIXME: this test seems wrong. */
1129 (strncmp (mi->native_path, "\\\\.\\", 4) != 0 ||
1130 strncmp (mi->native_path + 4, "UNC\\", 4) == 0))
1132 strcpy (dst + n, p);
1134 backslashify (dst, dst, trailing_slash_p);
1139 /* Compute relative path if asked to and able to. */
1141 cwdlen = 0; /* avoid a (hopefully) bogus compiler warning */
1142 char *cwd_win32_now;
1143 cwd_win32_now = cwd_win32 (TMPCWD);
1144 if (win32_path == NULL)
1145 /* nothing to do */;
1146 else if (isrelpath &&
1147 path_prefix_p (cwd_win32_now, dst, cwdlen = strlen (cwd_win32_now)))
1149 size_t n = strlen (dst);
1151 strcpy (win32_path, dst);
1157 dst += isdirsep (cwd_win32_now[cwdlen - 1]) ? cwdlen : cwdlen + 1;
1159 memmove (win32_path, dst, strlen (dst) + 1);
1162 strcpy (win32_path, ".");
1163 if (trailing_slash_p)
1164 strcat (win32_path, "\\");
1168 else if (win32_path != dst)
1169 strcpy (win32_path, dst);
1173 debug_printf ("%s(rel), %s(abs) %p(flags) = conv_to_win32_path (%s)",
1174 win32_path, full_win32_path, *flags,
1179 /* Convert PATH (for which slash_drive_prefix_p returns 1) to WIN32 form. */
1182 mount_info::slash_drive_to_win32_path (const char *path, char *buf,
1183 int trailing_slash_p)
1188 strcpy (buf + 2, "\\");
1190 backslashify (path + 3, buf + 2, trailing_slash_p);
1193 /* cygdrive_posix_path: Build POSIX path used as the
1194 mount point for cygdrives created when there is no other way to
1195 obtain a POSIX path from a Win32 one. */
1198 mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
1200 int len = cygdrive_len;
1202 memcpy (dst, cygdrive, len + 1);
1204 /* Now finish the path off with the drive letter to be used.
1205 The cygdrive prefix always ends with a trailing slash so
1206 the drive letter is added after the path. */
1207 dst[len++] = tolower (src[0]);
1208 if (!src[2] || (SLASH_P (src[2]) && !src[3]))
1209 dst[len++] = '\000';
1213 strcpy (dst + len, src + 3);
1215 slashify (dst, dst, trailing_slash_p);
1219 mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
1221 const char *p = src + cygdrive_len;
1222 if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
1226 strcpy (dst + 2, p + 1);
1227 backslashify (dst, dst, trailing_slash_p || !dst[2]);
1228 debug_printf ("src '%s', dst '%s'", src, dst);
1232 /* conv_to_posix_path: Ensure src_path is a POSIX path.
1234 The result is zero for success, or an errno value.
1235 posix_path must have sufficient space (i.e. MAX_PATH bytes).
1236 If keep_rel_p is non-zero, relative paths stay that way. */
1239 mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
1242 int src_path_len = strlen (src_path);
1243 int relative_path_p = !isabspath (src_path);
1244 int trailing_slash_p;
1246 if (src_path_len <= 1)
1247 trailing_slash_p = 0;
1250 const char *lastchar = src_path + src_path_len - 1;
1251 trailing_slash_p = SLASH_P (*lastchar) && lastchar[-1] != ':';
1254 debug_printf ("conv_to_posix_path (%s, %s, %s)", src_path,
1255 keep_rel_p ? "keep-rel" : "no-keep-rel",
1256 trailing_slash_p ? "add-slash" : "no-add-slash");
1259 if (src_path_len >= MAX_PATH)
1261 debug_printf ("ENAMETOOLONG");
1262 return ENAMETOOLONG;
1265 /* FIXME: For now, if the path is relative and it's supposed to stay
1266 that way, skip mount table processing. */
1268 if (keep_rel_p && relative_path_p)
1270 slashify (src_path, posix_path, 0);
1271 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1275 char pathbuf[MAX_PATH];
1278 /* No need to fetch cwd if path is absolute. */
1279 if (relative_path_p)
1280 getcwd_inner (cwd, MAX_PATH, 0, 0); /* FIXME: check rc */
1282 strcpy (cwd, "/"); /* some innocuous value */
1284 int rc = normalize_win32_path (cwd, src_path, pathbuf);
1287 debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1291 int pathbuflen = strlen (pathbuf);
1292 for (int i = 0; i < nmounts; ++i)
1294 mount_item &mi = mount[native_sorted[i]];
1295 if (! path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1298 /* SRC_PATH is in the mount table. */
1300 const char *p = pathbuf + mi.native_pathlen;
1304 else if (isdirsep (*p))
1309 int addslash = nextchar > 0 ? 1 : 0;
1310 if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH)
1311 return ENAMETOOLONG;
1312 strcpy (posix_path, mi.posix_path);
1314 strcat (posix_path, "/");
1317 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
1322 /* Not in the database. This should [theoretically] only happen if either
1323 the path begins with //, or / isn't mounted, or the path has a drive
1324 letter not covered by the mount table. If it's a relative path then the
1325 caller must want an absolute path (otherwise we would have returned
1326 above). So we always return an absolute path at this point. */
1327 if (isdrive (pathbuf))
1328 cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p);
1331 /* The use of src_path and not pathbuf here is intentional.
1332 We couldn't translate the path, so just ensure no \'s are present. */
1333 slashify (src_path, posix_path, trailing_slash_p);
1337 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1342 /* Return flags associated with a mount point given the win32 path. */
1345 mount_info::set_flags_from_win32_path (const char *p)
1347 for (int i = 0; i < nmounts; i++)
1349 mount_item &mi = mount[native_sorted[i]];
1350 if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
1356 /* read_mounts: Given a specific regkey, read mounts from under its
1360 mount_info::read_mounts (reg_key& r)
1362 char posix_path[MAX_PATH];
1363 HKEY key = r.get_key ();
1364 DWORD i, posix_path_size;
1365 int found_cygdrive = FALSE;
1367 /* Loop through subkeys */
1368 /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
1369 shared area is currently statically allocated so we can't have an
1370 arbitrarily large number of mounts. */
1371 for (DWORD i = 0; ; i++)
1373 char native_path[MAX_PATH];
1376 posix_path_size = MAX_PATH;
1377 /* FIXME: if maximum posix_path_size is 256, we're going to
1378 run into problems if we ever try to store a mount point that's
1379 over 256 but is under MAX_PATH! */
1380 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1383 if (err == ERROR_NO_MORE_ITEMS)
1385 else if (err != ERROR_SUCCESS)
1387 debug_printf ("RegEnumKeyEx failed, error %d!\n", err);
1391 if (iscygdrive (posix_path))
1393 found_cygdrive = TRUE;
1397 /* Get a reg_key based on i. */
1398 reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1400 /* Fetch info from the subkey. */
1401 subkey.get_string ("native", native_path, sizeof (native_path), "");
1402 mount_flags = subkey.get_int ("flags", 0);
1404 /* Add mount_item corresponding to registry mount point. */
1405 int res = cygwin_shared->mount.add_item (native_path, posix_path, mount_flags, FALSE);
1406 if (res && get_errno () == EMFILE)
1407 break; /* The number of entries exceeds MAX_MOUNTS */
1410 if (!found_cygdrive)
1416 posix_path_size = MAX_PATH;
1417 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1420 if (err != ERROR_SUCCESS)
1423 if (iscygdrive (posix_path))
1425 /* This shouldn't be in the mount table. */
1426 (void) r.kill (posix_path);
1432 /* from_registry: Build the entire mount table from the registry. Also,
1433 read in cygdrive-related information from its registry location. */
1436 mount_info::from_registry ()
1438 /* Use current mount areas if either user or system mount areas
1439 already exist. Otherwise, import old mounts. */
1443 /* Retrieve cygdrive-related information. */
1444 read_cygdrive_info_from_registry ();
1448 /* First read mounts from user's table. */
1451 /* Then read mounts from system-wide mount table. */
1452 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1453 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1454 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1455 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1459 /* If we had to create both user and system mount areas, import
1461 if (had_to_create_mount_areas == 2)
1462 import_v1_mounts ();
1465 /* add_reg_mount: Add mount item to registry. Return zero on success,
1466 non-zero on failure. */
1467 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1470 mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1472 /* Add the mount to the right registry location, depending on
1473 whether MOUNT_SYSTEM is set in the mount flags. */
1474 if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
1476 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1479 /* Start by deleting existing mount if one exists. */
1480 reg_user.kill (posix_path);
1482 /* Create the new mount. */
1483 reg_key subkey = reg_key (reg_user.get_key (),
1486 subkey.set_string ("native", native_path);
1487 subkey.set_int ("flags", mountflags);
1489 else /* local_machine mount */
1491 /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
1492 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1493 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1494 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1495 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1498 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1504 /* Start by deleting existing mount if one exists. */
1505 reg_sys.kill (posix_path);
1507 /* Create the new mount. */
1508 reg_key subkey = reg_key (reg_sys.get_key (),
1511 subkey.set_string ("native", native_path);
1512 subkey.set_int ("flags", mountflags);
1515 return 0; /* Success! */
1518 /* del_reg_mount: delete mount item from registry indicated in flags.
1519 Return zero on success, non-zero on failure.*/
1520 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1523 mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1527 if ((flags & MOUNT_SYSTEM) == 0) /* Delete from user registry */
1529 reg_key reg_user (KEY_ALL_ACCESS,
1530 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
1531 killres = reg_user.kill (posix_path);
1533 else /* Delete from system registry */
1535 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1536 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1537 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1538 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1541 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1547 killres = reg_sys.kill (posix_path);
1550 if (killres != ERROR_SUCCESS)
1552 __seterrno_from_win_error (killres);
1556 return 0; /* Success! */
1559 /* read_cygdrive_info_from_registry: Read the default prefix and flags
1560 to use when creating cygdrives from the special user registry
1561 location used to store cygdrive information. */
1564 mount_info::read_cygdrive_info_from_registry ()
1566 /* reg_key for user path prefix in HKEY_CURRENT_USER. */
1569 if (r.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1571 /* Didn't find the user path prefix so check the system path prefix. */
1573 /* reg_key for system path prefix in HKEY_LOCAL_MACHINE. */
1574 reg_key r2 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1575 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1576 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1577 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1580 if (r2.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1582 /* Didn't find either so write the default to the registry and use it.
1583 NOTE: We are writing and using the user path prefix. */
1584 write_cygdrive_info_to_registry ("/cygdrive", MOUNT_AUTO);
1588 /* Fetch system cygdrive_flags from registry; returns MOUNT_AUTO on
1590 cygdrive_flags = r2.get_int ("cygdrive flags", MOUNT_AUTO);
1591 slashify (cygdrive, cygdrive, 1);
1592 cygdrive_len = strlen(cygdrive);
1597 /* Fetch user cygdrive_flags from registry; returns MOUNT_AUTO on
1599 cygdrive_flags = r.get_int ("cygdrive flags", MOUNT_AUTO);
1600 slashify (cygdrive, cygdrive, 1);
1601 cygdrive_len = strlen(cygdrive);
1605 /* write_cygdrive_info_to_registry: Write the default prefix and flags
1606 to use when creating cygdrives to the special user registry
1607 location used to store cygdrive information. */
1610 mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1612 /* Determine whether to modify user or system cygdrive path prefix. */
1613 HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1615 /* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
1616 HKEY_LOCAL_MACHINE. */
1617 reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
1618 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1619 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1620 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1623 /* Verify cygdrive prefix starts with a forward slash and if there's
1624 another character, it's not a slash. */
1625 if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
1626 (!isslash (cygdrive_prefix[0])) ||
1627 ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
1633 char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1];
1634 /* Ensure that there is never a final slash */
1635 nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
1637 r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
1638 r.set_int ("cygdrive flags", flags);
1640 /* This also needs to go in the in-memory copy of "cygdrive", but only if
1642 1. setting user path prefix, or
1643 2. overwriting (a previous) system path prefix */
1644 if ((flags & MOUNT_SYSTEM) == 0 ||
1645 (cygwin_shared->mount.cygdrive_flags & MOUNT_SYSTEM) != 0)
1647 slashify (cygdrive_prefix, cygwin_shared->mount.cygdrive, 1);
1648 cygwin_shared->mount.cygdrive_flags = flags;
1649 cygwin_shared->mount.cygdrive_len = strlen(cygwin_shared->mount.cygdrive);
1656 mount_info::remove_cygdrive_info_from_registry (const char *cygdrive_prefix, unsigned flags)
1658 /* Determine whether to modify user or system cygdrive path prefix. */
1659 HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1661 /* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
1662 HKEY_LOCAL_MACHINE. */
1663 reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
1664 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1665 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1666 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1669 /* Delete cygdrive prefix and flags. */
1670 int res = r.killvalue ("cygdrive prefix");
1671 int res2 = r.killvalue ("cygdrive flags");
1673 /* Reinitialize the cygdrive path prefix to reflect to removal from the
1675 read_cygdrive_info_from_registry ();
1677 return (res != ERROR_SUCCESS) ? res : res2;
1681 mount_info::get_cygdrive_prefixes (char *user, char *system)
1683 /* Get the user path prefix from HKEY_CURRENT_USER. */
1685 int res = r.get_string ("cygdrive prefix", user, MAX_PATH, "");
1687 /* Get the system path prefix from HKEY_LOCAL_MACHINE. */
1688 reg_key r2 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1689 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1690 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1691 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1693 int res2 = r2.get_string ("cygdrive prefix", system, MAX_PATH, "");
1695 return (res != ERROR_SUCCESS) ? res : res2;
1699 mount_info::getmntent (int x)
1701 if (x < 0 || x >= nmounts)
1704 return mount[native_sorted[x]].getmntent ();
1707 static mount_item *mounts_for_sort;
1709 /* sort_by_posix_name: qsort callback to sort the mount entries. Sort
1710 user mounts ahead of system mounts to the same POSIX path. */
1711 /* FIXME: should the user should be able to choose whether to
1712 prefer user or system mounts??? */
1714 sort_by_posix_name (const void *a, const void *b)
1716 mount_item *ap = mounts_for_sort + (*((int*) a));
1717 mount_item *bp = mounts_for_sort + (*((int*) b));
1719 /* Base weighting on longest posix path first so that the most
1720 obvious path will be chosen. */
1721 size_t alen = strlen (ap->posix_path);
1722 size_t blen = strlen (bp->posix_path);
1724 int res = blen - alen;
1727 return res; /* Path lengths differed */
1729 /* The two paths were the same length, so just determine normal
1730 lexical sorted order. */
1731 res = strcmp (ap->posix_path, bp->posix_path);
1735 /* need to select between user and system mount to same POSIX path */
1736 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1745 /* sort_by_native_name: qsort callback to sort the mount entries. Sort
1746 user mounts ahead of system mounts to the same POSIX path. */
1747 /* FIXME: should the user should be able to choose whether to
1748 prefer user or system mounts??? */
1750 sort_by_native_name (const void *a, const void *b)
1752 mount_item *ap = mounts_for_sort + (*((int*) a));
1753 mount_item *bp = mounts_for_sort + (*((int*) b));
1755 /* Base weighting on longest win32 path first so that the most
1756 obvious path will be chosen. */
1757 size_t alen = strlen (ap->native_path);
1758 size_t blen = strlen (bp->native_path);
1760 int res = blen - alen;
1763 return res; /* Path lengths differed */
1765 /* The two paths were the same length, so just determine normal
1766 lexical sorted order. */
1767 res = strcmp (ap->native_path, bp->native_path);
1771 /* need to select between user and system mount to same POSIX path */
1772 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1784 for (int i = 0; i < nmounts; i++)
1785 native_sorted[i] = posix_sorted[i] = i;
1786 /* Sort them into reverse length order, otherwise we won't
1787 be able to look for /foo in /. */
1788 mounts_for_sort = mount; /* ouch. */
1789 qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
1790 qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
1793 /* Add an entry to the mount table.
1794 Returns 0 on success, -1 on failure and errno is set.
1796 This is where all argument validation is done. It may not make sense to
1797 do this when called internally, but it's cleaner to keep it all here. */
1800 mount_info::add_item (const char *native, const char *posix, unsigned mountflags, int reg_p)
1802 /* Something's wrong if either path is NULL or empty, or if it's
1803 not a UNC or absolute path. */
1805 if ((native == NULL) || (*native == 0) ||
1806 (posix == NULL) || (*posix == 0) ||
1807 (!slash_unc_prefix_p (native) && !isabspath (native)))
1813 /* Make sure both paths do not end in /. */
1814 char nativetmp[MAX_PATH];
1815 char posixtmp[MAX_PATH];
1817 if (slash_drive_prefix_p (native))
1818 slash_drive_to_win32_path (native, nativetmp, 0);
1820 backslashify (native, nativetmp, 0);
1821 nofinalslash (nativetmp, nativetmp);
1823 slashify (posix, posixtmp, 0);
1824 nofinalslash (posixtmp, posixtmp);
1826 debug_printf ("%s[%s], %s[%s], %p",
1827 native, nativetmp, posix, posixtmp, mountflags);
1829 /* Duplicate /'s in path are an error. */
1830 for (char *p = posixtmp + 1; *p; ++p)
1832 if (p[-1] == '/' && p[0] == '/')
1839 /* Write over an existing mount item with the same POSIX path if
1840 it exists and is from the same registry area. */
1842 for (i = 0; i < nmounts; i++)
1844 if (strcasematch (mount[i].posix_path, posixtmp) &&
1845 (mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM))
1851 if (nmounts < MAX_MOUNTS)
1860 if (reg_p && add_reg_mount (nativetmp, posixtmp, mountflags))
1863 mount[i].init (nativetmp, posixtmp, mountflags);
1869 /* Delete a mount table entry where path is either a Win32 or POSIX
1870 path. Since the mount table is really just a table of aliases,
1871 deleting / is ok (although running without a slash mount is
1872 strongly discouraged because some programs may run erratically
1873 without one). If MOUNT_SYSTEM is set in flags, remove from system
1874 registry, otherwise remove the user registry mount.
1878 mount_info::del_item (const char *path, unsigned flags, int reg_p)
1880 char pathtmp[MAX_PATH];
1881 int posix_path_p = FALSE;
1883 /* Something's wrong if path is NULL or empty. */
1884 if (path == NULL || *path == 0 || !isabspath (path))
1890 if (slash_drive_prefix_p (path))
1891 slash_drive_to_win32_path (path, pathtmp, 0);
1892 else if (slash_unc_prefix_p (path) || strpbrk (path, ":\\"))
1893 backslashify (path, pathtmp, 0);
1896 slashify (path, pathtmp, 0);
1897 posix_path_p = TRUE;
1899 nofinalslash (pathtmp, pathtmp);
1901 if (reg_p && posix_path_p &&
1902 del_reg_mount (pathtmp, flags) &&
1903 del_reg_mount (path, flags)) /* for old irregular entries */
1906 for (int i = 0; i < nmounts; i++)
1908 int ent = native_sorted[i]; /* in the same order as getmntent() */
1910 ? strcasematch (mount[ent].posix_path, pathtmp)
1911 : strcasematch (mount[ent].native_path, pathtmp)) &&
1912 (mount[ent].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM))
1914 if (!posix_path_p &&
1915 reg_p && del_reg_mount (mount[ent].posix_path, flags))
1918 nmounts--; /* One less mount table entry */
1919 /* Fill in the hole if not at the end of the table */
1921 memmove (mount + ent, mount + ent + 1,
1922 sizeof (mount[ent]) * (nmounts - ent));
1923 sort (); /* Resort the table */
1931 /* read_v1_mounts: Given a reg_key to an old mount table registry area,
1932 read in the mounts. The "which" arg contains zero if we're reading
1933 the user area and MOUNT_SYSTEM if we're reading the system area.
1934 This way we can store the mounts read in the appropriate place when
1935 they are written back to the new registry layout. */
1938 mount_info::read_v1_mounts (reg_key r, unsigned which)
1940 unsigned mountflags = 0;
1942 /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
1943 for (int i = 0; i < 30; i++)
1946 char win32path[MAX_PATH];
1947 char unixpath[MAX_PATH];
1949 __small_sprintf (key_name, "%02x", i);
1951 reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
1953 /* The registry names are historical but useful so are left alone. */
1954 k.get_string ("native", win32path, sizeof (win32path), "");
1955 k.get_string ("unix", unixpath, sizeof (unixpath), "");
1957 /* Does this entry contain something? */
1958 if (*win32path != 0)
1962 if (k.get_int ("fbinary", 0))
1963 mountflags |= MOUNT_BINARY;
1965 /* Or in zero or MOUNT_SYSTEM depending on which table
1967 mountflags |= which;
1969 int res = cygwin_shared->mount.add_item (win32path, unixpath, mountflags, TRUE);
1970 if (res && get_errno () == EMFILE)
1971 break; /* The number of entries exceeds MAX_MOUNTS */
1976 /* import_v1_mounts: If v1 mounts are present, load them and write
1977 the new entries to the new registry area. */
1980 mount_info::import_v1_mounts ()
1982 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
1992 /* First read mounts from user's table. */
1993 read_v1_mounts (r, 0);
1995 /* Then read mounts from system-wide mount table. */
1996 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
2003 read_v1_mounts (r1, MOUNT_SYSTEM);
2006 /************************* mount_item class ****************************/
2009 mount_item::getmntent ()
2012 struct mntent &ret=_reent_winsup()->_ret;
2014 static NO_COPY struct mntent ret;
2017 /* Pass back pointers to mount_info strings reserved for use by
2018 getmntent rather than pointers to strings in the internal mount
2019 table because the mount table might change, causing weird effects
2020 from the getmntent user's point of view. */
2022 strcpy (cygwin_shared->mount.mnt_fsname, native_path);
2023 ret.mnt_fsname = cygwin_shared->mount.mnt_fsname;
2024 strcpy (cygwin_shared->mount.mnt_dir, posix_path);
2025 ret.mnt_dir = cygwin_shared->mount.mnt_dir;
2027 if (!(flags & MOUNT_SYSTEM)) /* user mount */
2028 strcpy (cygwin_shared->mount.mnt_type, (char *) "user");
2029 else /* system mount */
2030 strcpy (cygwin_shared->mount.mnt_type, (char *) "system");
2032 if ((flags & MOUNT_AUTO)) /* cygdrive */
2033 strcat (cygwin_shared->mount.mnt_type, (char *) ",auto");
2035 ret.mnt_type = cygwin_shared->mount.mnt_type;
2037 /* mnt_opts is a string that details mount params such as
2038 binary or textmode, or exec. We don't print
2039 `silent' here; it's a magic internal thing. */
2041 if (! (flags & MOUNT_BINARY))
2042 strcpy (cygwin_shared->mount.mnt_opts, (char *) "textmode");
2044 strcpy (cygwin_shared->mount.mnt_opts, (char *) "binmode");
2046 if (flags & MOUNT_CYGWIN_EXEC)
2047 strcat (cygwin_shared->mount.mnt_opts, (char *) ",cygexec");
2048 else if (flags & MOUNT_EXEC)
2049 strcat (cygwin_shared->mount.mnt_opts, (char *) ",exec");
2052 ret.mnt_opts = cygwin_shared->mount.mnt_opts;
2059 /* Fill in the fields of a mount table entry. */
2062 mount_item::init (const char *native, const char *posix, unsigned mountflags)
2064 strcpy ((char *) native_path, native);
2065 strcpy ((char *) posix_path, posix);
2067 native_pathlen = strlen (native_path);
2068 posix_pathlen = strlen (posix_path);
2073 /********************** Mount System Calls **************************/
2075 /* Mount table system calls.
2076 Note that these are exported to the application. */
2078 /* mount: Add a mount to the mount table in memory and to the registry
2079 that will cause paths under win32_path to be translated to paths
2080 under posix_path. */
2084 mount (const char *win32_path, const char *posix_path, unsigned flags)
2088 if (flags & MOUNT_AUTO) /* normal mount */
2090 /* When flags include MOUNT_AUTO, take this to mean that
2091 we actually want to change the cygdrive prefix and flags
2092 without actually mounting anything. */
2093 res = cygwin_shared->mount.write_cygdrive_info_to_registry (posix_path, flags);
2098 if (iscygdrive (posix_path))
2101 return res; /* Don't try to add cygdrive prefix. */
2104 res = cygwin_shared->mount.add_item (win32_path, posix_path, flags, TRUE);
2107 syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
2111 /* umount: The standard umount call only has a path parameter. Since
2112 it is not possible for this call to specify whether to remove the
2113 mount from the user or global mount registry table, assume the user
2118 umount (const char *path)
2120 return cygwin_umount (path, 0);
2123 /* cygwin_umount: This is like umount but takes an additional flags
2124 parameter that specifies whether to umount from the user or system-wide
2129 cygwin_umount (const char *path, unsigned flags)
2133 if (flags & MOUNT_AUTO)
2135 /* When flags include MOUNT_AUTO, take this to mean that we actually want
2136 to remove the cygdrive prefix and flags without actually unmounting
2138 res = cygwin_shared->mount.remove_cygdrive_info_from_registry (path, flags);
2142 res = cygwin_shared->mount.del_item (path, flags, TRUE);
2145 syscall_printf ("%d = cygwin_umount (%s, %d)", res, path, flags);
2150 #define iteration _reent_winsup()->_iteration
2152 static int iteration;
2157 setmntent (const char *filep, const char *)
2160 return (FILE *) filep;
2167 return cygwin_shared->mount.getmntent (iteration++);
2177 /********************** Symbolic Link Support **************************/
2179 /* Create a symlink from FROMPATH to TOPATH. */
2183 symlink (const char *topath, const char *frompath)
2188 path_conv win32_path (frompath, PC_SYM_NOFOLLOW);
2189 if (win32_path.error)
2191 set_errno (win32_path.error);
2195 syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
2202 if (strlen (topath) >= MAX_PATH)
2204 set_errno (ENAMETOOLONG);
2208 if (win32_path.is_device () ||
2209 win32_path.file_attributes () != (DWORD) -1)
2215 h = CreateFileA(win32_path.get_win32 (), GENERIC_WRITE, 0, &sec_none_nih,
2216 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
2217 if (h == INVALID_HANDLE_VALUE)
2221 char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10];
2223 __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
2224 DWORD len = strlen (buf) + 1;
2226 /* Note that the terminating nul is written. */
2228 if (!WriteFile (h, buf, len, &written, NULL) || written != len)
2232 DeleteFileA (win32_path.get_win32 ());
2237 set_file_attribute (win32_path.has_acls (),
2238 win32_path.get_win32 (),
2239 S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
2240 SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_SYSTEM);
2246 syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath);
2250 static __inline char *
2251 has_suffix (const char *path, const suffix_info *suffixes)
2253 char *ext = strrchr (path, '.');
2255 for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
2256 if (strcasematch (ext, ex->name))
2261 static __inline__ int
2262 next_suffix (char *ext_here, const suffix_info *&suffixes)
2267 while (suffixes && suffixes->name)
2268 if (!suffixes->addon)
2272 strcpy (ext_here, suffixes->name);
2279 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2281 If PATH is a symlink, put the value of the symlink--the file to
2282 which it points--into BUF. The value stored in BUF is not
2283 necessarily null terminated. BUFLEN is the length of BUF; only up
2284 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2285 which case nothing will be stored.
2287 Set *SYML if PATH is a symlink.
2289 Set *EXEC if PATH appears to be executable. This is an efficiency
2290 hack because we sometimes have to open the file anyhow. *EXEC will
2291 not be set for every executable file.
2293 Return -1 on error, 0 if PATH is not a symlink, or the length
2294 stored into BUF if PATH is a symlink. */
2297 symlink_info::check (const char *in_path, const suffix_info *suffixes)
2301 char extbuf[MAX_PATH + 5];
2302 const char *path = in_path;
2306 else if ((known_suffix = has_suffix (in_path, suffixes)) != NULL)
2313 path = strcpy (extbuf, in_path);
2314 ext_here = strchr (path, '\0');
2322 if (!next_suffix (ext_here, suffixes))
2325 fileattr = GetFileAttributesA (path);
2326 if (fileattr == (DWORD) -1)
2328 /* The GetFileAttributesA call can fail for reasons that don't
2329 matter, so we just return 0. For example, getting the
2330 attributes of \\HOST will typically fail. */
2331 debug_printf ("GetFileAttributesA (%s) failed", path);
2332 error = geterrno_from_win_error (GetLastError (), EACCES);
2336 /* Windows allows path\. even when `path' isn't a directory.
2337 Detect this scenario and disallow it, since it is non-UNIX like.
2338 FIXME: This code actually checks for things like foo/ and foo/..
2339 even though those usages have already been (erroneously?) eaten
2340 by cygwin_shared->mount.conv_to_win32_path in path_conv::check. */
2342 char *p = strrchr (path, '\\');
2343 if (p && !(fileattr & FILE_ATTRIBUTE_DIRECTORY) &&
2344 (*++p == '\0' || (*p == '.' && (*++p == '\0' || (*p == '.' && p[1] == '\0')))))
2346 debug_printf ("%s is a non-directory", path);
2348 goto file_not_symlink;
2351 /* A symlink will have the `system' file attribute. */
2352 /* Only files can be symlinks (which can be symlinks to directories). */
2353 if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))
2354 goto file_not_symlink;
2356 /* Open the file. */
2358 h = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
2359 FILE_ATTRIBUTE_NORMAL, 0);
2361 if (h == INVALID_HANDLE_VALUE)
2362 goto file_not_symlink;
2365 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2368 if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
2370 else if (got == sizeof (cookie_buf)
2371 && memcmp (cookie_buf, SYMLINK_COOKIE,
2372 sizeof (cookie_buf)) == 0)
2374 /* It's a symlink. */
2375 pflags = PATH_SYMLINK;
2377 res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2382 /* Versions prior to b16 stored several trailing
2383 NULs with the path (to fill the path out to 1024
2384 chars). Current versions only store one trailing
2385 NUL. The length returned is the path without
2386 *any* trailing NULs. We also have to handle (or
2387 at least not die from) corrupted paths. */
2388 if (memchr (contents, 0, got) != NULL)
2389 res = strlen (contents);
2394 else if (got == sizeof (cookie_buf)
2395 && memcmp (cookie_buf, SOCKET_COOKIE,
2396 sizeof (cookie_buf)) == 0)
2398 pflags |= PATH_SOCKET;
2399 goto close_and_return;
2403 /* Not a symlink, see if executable. */
2404 if (!(pflags & (PATH_EXEC | PATH_CYGWIN_EXEC)) && got >= 2 &&
2405 ((cookie_buf[0] == '#' && cookie_buf[1] == '!') ||
2406 (cookie_buf[0] == ':' && cookie_buf[1] == '\n')))
2407 pflags |= PATH_EXEC;
2410 goto file_not_symlink;
2422 syscall_printf ("not a symlink");
2426 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2427 res, path, contents, pflags);
2432 /* readlink system call */
2436 readlink (const char *path, char *buf, int buflen)
2438 extern suffix_info stat_suffixes[];
2439 path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2443 set_errno (pathbuf.error);
2444 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2448 if (!pathbuf.issymlink ())
2450 if (pathbuf.fileattr != (DWORD) -1)
2455 int len = strlen (pathbuf.get_win32 ());
2456 if (len > (buflen - 1))
2458 set_errno (ENAMETOOLONG);
2461 memcpy (buf, pathbuf.get_win32 (), len);
2464 /* errno set by symlink.check if error */
2468 /* Some programs rely on st_dev/st_ino being unique for each file.
2469 Hash the path name and hope for the best. The hash arg is not
2470 always initialized to zero since readdir needs to compute the
2471 dirent ino_t based on a combination of the hash of the directory
2472 done during the opendir call and the hash or the filename within
2473 the directory. FIXME: Not bullet-proof. */
2474 /* Cygwin internal */
2476 unsigned long __stdcall
2477 hash_path_name (unsigned long hash, const char *name)
2482 /* Perform some initial permutations on the pathname if this is
2486 /* Simplistic handling of drives. If there is a drive specified,
2487 make sure that the initial letter is upper case. If there is
2488 no \ after the ':' assume access through the root directory
2490 FIXME: Should really honor MS-Windows convention of using
2491 the environment to track current directory on various drives. */
2494 char *nn, *newname = (char *) alloca (strlen (name) + 2);
2495 nn = strncpy (newname, name, 2);
2497 *newname = toupper (*nn);
2510 /* Fill out the hashed path name with the current working directory if
2511 this is not an absolute path and there is no pre-specified hash value.
2512 Otherwise the inodes same will differ depending on whether a file is
2513 referenced with an absolute value or relatively. */
2515 if (*name != '\\' && (cwd_win32 (TMPCWD) == NULL || get_cwd_win32 ()))
2518 if (name[0] == '.' && name[1] == '\0')
2520 hash = hash_path_name (hash, "\\");
2525 /* Build up hash. Ignore single trailing slash or \a\b\ != \a\b or
2526 \a\b\. but allow a single \ if that's all there is. */
2529 hash += *name + (*name << 17);
2532 while (*++name != '\0' &&
2533 !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
2542 cwd.lock->acquire ();
2543 for (dlen = 256; ; dlen *= 2)
2545 cwd.win32 = (char *) crealloc (cwd.win32, dlen + 2);
2546 if ((len = GetCurrentDirectoryA (dlen, cwd.win32)) < dlen)
2553 cwd.hash = hash_path_name (0, cwd.win32);
2555 cwd.lock->release ();
2562 getcwd_inner (char *buf, size_t ulen, int posix_p, int with_chroot)
2564 char *resbuf = NULL;
2567 if (cwd_win32 (TMPCWD) == NULL && !get_cwd_win32 ())
2570 char *cwd_win32_now = cwd_win32 (TMPCWD);
2571 char *cwd_posix_now = cwd_posix (TMPCWD);
2574 if (strlen (cwd_win32_now) >= len)
2578 strcpy (buf, cwd_win32_now);
2582 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, win32) (cached)",
2583 resbuf, resbuf ? resbuf : "", buf, len);
2586 else if (cwd_posix_now != NULL)
2588 debug_printf("myself->root: %s, cwd_posix: %s", myself->root, cwd_posix_now);
2589 if (strlen (cwd_posix_now) >= len)
2591 else if (with_chroot && ischrootpath(cwd_posix_now))
2593 strcpy (buf, cwd_posix_now + myself->rootlen);
2600 strcpy (buf, cwd_posix_now);
2604 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, posix) (cached)",
2605 resbuf, resbuf ? resbuf : "", buf, len);
2609 /* posix_p required and cwd_posix == NULL */
2611 char temp[MAX_PATH];
2613 /* Turn from Win32 style to our style. */
2614 cygwin_shared->mount.conv_to_posix_path (cwd_win32_now, temp, 0);
2616 size_t tlen = strlen (temp);
2618 if (with_chroot && ischrootpath (temp))
2619 tlen -= myself->rootlen;
2621 cwd.lock->acquire ();
2622 cwd.posix = (char *) crealloc (cwd.posix, tlen + 1);
2623 if (cwd.posix != NULL)
2624 if (with_chroot && ischrootpath (temp))
2626 strcpy (cwd.posix, temp + myself->rootlen);
2631 strcpy (cwd.posix, temp);
2633 cwd.lock->release ();
2636 set_errno (ERANGE); /* len was too small */
2643 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, %s)",
2644 resbuf, resbuf ? resbuf : "",
2645 buf, len, posix_p ? "posix" : "win32");
2650 getcwd (char *buf, size_t ulen)
2654 if (buf == NULL || ulen == 0)
2656 buf = (char *) alloca (MAX_PATH);
2657 res = getcwd_inner (buf, MAX_PATH, 1, 1);
2662 res = getcwd_inner (buf, ulen, 1, 1);
2668 /* getwd: standards? */
2673 return getcwd (buf, MAX_PATH);
2676 /* chdir: POSIX 5.2.1.1 */
2679 chdir (const char *dir)
2681 syscall_printf ("dir %s", dir);
2682 path_conv path (dir);
2686 set_errno (path.error);
2687 syscall_printf ("-1 = chdir (%s)", dir);
2691 char *native_dir = path.get_win32 ();
2693 /* Check to see if path translates to something like C:.
2694 If it does, append a \ to the native directory specification to
2695 defeat the Windows 95 (i.e. MS-DOS) tendency of returning to
2696 the last directory visited on the given drive. */
2697 if (isdrive (native_dir) && !native_dir[2])
2699 native_dir[2] = '\\';
2700 native_dir[3] = '\0';
2702 int res = SetCurrentDirectoryA (native_dir) ? 0 : -1;
2707 cwd.lock->acquire ();
2708 /* Store new cache information */
2710 cwd.win32 = cstrdup (path);
2712 char pathbuf[MAX_PATH];
2713 (void) normalize_posix_path (cwd.posix, dir, pathbuf);
2714 /* Look for trailing path component consisting entirely of dots. This
2715 is needed only in case of chdir since Windows simply ignores count
2716 of dots > 2 here instead of returning an error code. Counts of dots
2717 <= 2 are already eliminated by normalize_posix_path. */
2718 char *last_slash = strrchr (pathbuf, '/');
2719 if (last_slash > pathbuf && strspn (last_slash + 1, ".") == strlen (last_slash + 1))
2722 cwd.posix = cstrdup (pathbuf);
2723 cwd.lock->release ();
2726 syscall_printf ("%d = chdir() cwd.posix '%s' native '%s'", res, cwd.posix, native_dir);
2730 /******************** Exported Path Routines *********************/
2732 /* Cover functions to the path conversion routines.
2733 These are exported to the world as cygwin_foo by cygwin.din. */
2737 cygwin_conv_to_win32_path (const char *path, char *win32_path)
2739 path_conv p (path, PC_SYM_FOLLOW);
2742 set_errno (p.error);
2746 strcpy (win32_path, p.get_win32 ());
2752 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
2754 path_conv p (path, PC_SYM_FOLLOW | PC_FULL);
2757 set_errno (p.error);
2761 strcpy (win32_path, p.get_win32 ());
2765 /* This is exported to the world as cygwin_foo by cygwin.din. */
2769 cygwin_conv_to_posix_path (const char *path, char *posix_path)
2771 if (check_null_empty_path_errno (path))
2773 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 1);
2779 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
2781 if (check_null_empty_path_errno (path))
2783 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 0);
2787 /* The realpath function is supported on some UNIX systems. */
2791 realpath (const char *path, char *resolved)
2795 path_conv real_path (path, PC_SYM_FOLLOW | PC_FULL);
2797 if (real_path.error)
2798 err = real_path.error;
2801 err = cygwin_shared->mount.conv_to_posix_path (real_path.get_win32 (), resolved, 0);
2806 /* FIXME: on error, we are supposed to put the name of the path
2807 component which could not be resolved into RESOLVED. */
2814 /* Return non-zero if path is a POSIX path list.
2815 This is exported to the world as cygwin_foo by cygwin.din.
2818 <sect1 id="add-func-cygwin-posix-path-list-p">
2819 <para>Rather than use a mode to say what the "proper" path list
2820 format is, we allow any, and give apps the tools they need to
2821 convert between the two. If a ';' is present in the path list it's
2822 a Win32 path list. Otherwise, if the first path begins with
2823 [letter]: (in which case it can be the only element since if it
2824 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
2825 it's a POSIX path list.</para>
2832 cygwin_posix_path_list_p (const char *path)
2834 int posix_p = ! (strchr (path, ';') || isdrive (path));
2838 /* These are used for apps that need to convert env vars like PATH back and
2839 forth. The conversion is a two step process. First, an upper bound on the
2840 size of the buffer needed is computed. Then the conversion is done. This
2841 allows the caller to use alloca if it wants. */
2844 conv_path_list_buf_size (const char *path_list, int to_posix_p)
2846 int i, num_elms, max_mount_path_len, size;
2849 /* The theory is that an upper bound is
2850 current_size + (num_elms * max_mount_path_len) */
2852 char delim = to_posix_p ? ';' : ':';
2854 for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms)
2857 /* 7: strlen ("//c") + slop, a conservative initial value */
2858 for (max_mount_path_len = 7, i = 0; i < cygwin_shared->mount.nmounts; ++i)
2860 int mount_len = (to_posix_p
2861 ? cygwin_shared->mount.mount[i].posix_pathlen
2862 : cygwin_shared->mount.mount[i].native_pathlen);
2863 if (max_mount_path_len < mount_len)
2864 max_mount_path_len = mount_len;
2868 size = strlen (path_list) + (num_elms * max_mount_path_len) + 100;
2874 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
2876 return conv_path_list_buf_size (path_list, 1);
2881 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
2883 return conv_path_list_buf_size (path_list, 0);
2888 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
2890 conv_path_list (win32, posix, 1);
2896 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
2898 conv_path_list (posix, win32, 0);
2902 /* cygwin_split_path: Split a path into directory and file name parts.
2903 Buffers DIR and FILE are assumed to be big enough.
2905 Examples (path -> `dir' / `file'):
2908 . -> `.' / `.' (FIXME: should this be `.' / `'?)
2909 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
2911 foo/bar -> `foo' / `bar'
2912 foo/bar/ -> `foo' / `bar'
2914 /foo/bar -> `/foo' / `bar'
2917 c:foo -> `c:/' / `foo'
2918 c:/foo -> `c:/' / `foo'
2923 cygwin_split_path (const char *path, char *dir, char *file)
2925 int dir_started_p = 0;
2927 /* Deal with drives.
2928 Remember that c:foo <==> c:/foo. */
2940 if (SLASH_P (*path))
2945 /* Determine if there are trailing slashes and "delete" them if present.
2946 We pretend as if they don't exist. */
2947 const char *end = path + strlen (path);
2948 /* path + 1: keep leading slash. */
2949 while (end > path + 1 && SLASH_P (end[-1]))
2952 /* At this point, END points to one beyond the last character
2953 (with trailing slashes "deleted"). */
2955 /* Point LAST_SLASH at the last slash (duh...). */
2956 const char *last_slash;
2957 for (last_slash = end - 1; last_slash >= path; --last_slash)
2958 if (SLASH_P (*last_slash))
2961 if (last_slash == path)
2966 else if (last_slash > path)
2968 memcpy (dir, path, last_slash - path);
2969 dir[last_slash - path] = 0;
2974 ; /* nothing to do */
2980 memcpy (file, last_slash + 1, end - last_slash - 1);
2981 file[end - last_slash - 1] = 0;
2984 /********************** String Helper Functions ************************/
2986 #define CHXOR ('a' ^ 'A')
2987 #define ch_case_eq(ch1, ch2) \
2990 !((x = ((unsigned char)ch1 ^ (unsigned char)ch2)) && \
2991 (x != CHXOR || !isalpha (ch1))); \
2994 /* Return TRUE if two strings match up to length n */
2996 strncasematch (const char *s1, const char *s2, size_t n)
3004 if (!ch_case_eq (*s1, *s2))
3008 return !n || *s2 == '\0';
3011 /* Return TRUE if two strings match */
3013 strcasematch (const char *s1, const char *s2)
3020 if (!ch_case_eq (*s1, *s2))
3028 strcasestr (const char *searchee, const char *lookfor)
3034 return (char *) searchee;
3042 if (lookfor[i] == 0)
3043 return (char *) searchee;
3045 if (!ch_case_eq (lookfor[i], searchee[i]))
3056 check_null_empty_path (const char *name)
3058 MEMORY_BASIC_INFORMATION m;
3059 if (!name || !VirtualQuery (name, &m, sizeof (m)) || (m.State != MEM_COMMIT))