1 /* path.cc: path support.
3 Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 /* This module's job is to
12 - convert between POSIX and Win32 style filenames,
13 - support the `mount' functionality,
14 - support symlinks for files and directories
16 Pathnames are handled as follows:
18 - / is equivalent to \
19 - Paths beginning with // (or \\) are not translated (i.e. looked
20 up in the mount table) and are assumed to be UNC path names.
21 - Paths containing a : are not translated (paths like
22 /foo/bar/baz:qux: don't make much sense but having the rule written
23 this way allows one to use strchr).
25 The goal in the above set of rules is to allow both POSIX and Win32
26 flavors of pathnames without either interfering. The rules are
27 intended to be as close to a superset of both as possible.
29 A possible future enhancement would be to allow people to
30 disable/enable the mount table handling to support pure Win32
31 pathnames. Hopefully this won't be needed. The suggested way to
32 do this would be an environment variable because
33 a) we need something that is inherited from parent to child,
34 b) environment variables can be passed from the DOS shell to a
36 c) it allows disabling the feature on an app by app basis within
37 the same session (whereas playing about with the registry wouldn't
38 -- without getting too complicated). Example:
39 CYGWIN=pathrules[=@]{win32,posix}. If CYGWIN=pathrules=win32,
40 mount table handling is disabled. [The intent is to have CYGWIN be
41 a catchall for tweaking various cygwin.dll features].
43 Note that you can have more than one path to a file. The mount
44 table is always prefered when translating Win32 paths to POSIX
45 paths. Win32 paths in mount table entries may be UNC paths or
46 standard Win32 paths starting with <drive-letter>:
48 Text vs Binary issues are not considered here in path style
51 / and \ are treated as equivalent. One or the other is prefered in
52 certain situations (e.g. / is preferred in result of getcwd, \ is
53 preferred in arguments to Win32 api calls), but this code will
54 translate as necessary.
56 Apps wishing to translate to/from pure Win32 and POSIX-like
57 pathnames can use cygwin_foo.
59 Removing mounted filesystem support would simplify things greatly,
60 but having it gives us a mechanism of treating disk that lives on a
61 UNIX machine as having UNIX semantics [it allows one to edit a text
62 file on that disk and not have cr's magically appear and perhaps
63 break apps running on UNIX boxes]. It also useful to be able to
64 layout a hierarchy without changing the underlying directories.
66 The semantics of mounting file systems is not intended to precisely
67 follow normal UNIX systems.
69 Each DOS drive is defined to have a current directory. Supporting
70 this would complicate things so for now things are defined so that
76 #include <sys/mount.h>
84 static int normalize_win32_path (const char *cwd, const char *src, char *dst);
85 static char *getcwd_inner (char *buf, size_t ulen, int posix_p);
86 static void slashify (const char *src, char *dst, int trailing_slash_p);
87 static void backslashify (const char *src, char *dst, int trailing_slash_p);
88 static int path_prefix_p_ (const char *path1, const char *path2, int len1);
89 static int get_current_directory_name ();
91 static NO_COPY const char escape_char = '^';
95 char buf[3 + MAX_PATH * 3];
102 symlink_info (): known_suffix (NULL), contents (buf + MAX_PATH + 1) {}
103 int check (const char *path, const suffix_info *suffixes);
106 /********************** Path Helper Functions *************************/
108 #define path_prefix_p(p1, p2, l1) \
109 ((tolower(*(p1))==tolower(*(p2))) && \
110 path_prefix_p_(p1, p2, l1))
112 #define SYMLINKATTR(x) \
113 (((x) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) == \
114 FILE_ATTRIBUTE_SYSTEM)
116 /* Return non-zero if PATH1 is a prefix of PATH2.
117 Both are assumed to be of the same path style and / vs \ usage.
119 LEN1 = strlen (PATH1). It's passed because often it's already known.
122 /foo/ is a prefix of /foo <-- may seem odd, but desired
123 /foo is a prefix of /foo/
124 / is a prefix of /foo/bar
125 / is not a prefix of foo/bar
126 foo/ is a prefix foo/bar
127 /foo is not a prefix of /foobar
130 /* Determine if path prefix matches current cygdrive */
131 #define iscygdrive(path) \
132 (path_prefix_p (cygwin_shared->mount.cygdrive, (path), cygwin_shared->mount.cygdrive_len))
134 #define iscygdrive_device(path) \
135 (iscygdrive(path) && isalpha(path[cygwin_shared->mount.cygdrive_len]) && \
136 (isdirsep(path[cygwin_shared->mount.cygdrive_len + 1]) || \
137 !path[cygwin_shared->mount.cygdrive_len + 1]))
139 /******************** Directory-related Support **************************/
141 /* Cache getcwd value. FIXME: We need a lock for these in order to
142 support multiple threads. */
145 #define current_directory_name _reent_winsup()->_current_directory_name
146 #define current_directory_posix_name _reent_winsup()->_current_directory_posix_name
147 #define current_directory_hash _reent_winsup()->_current_directory_hash
149 static char *current_directory_name;
150 static char *current_directory_posix_name;
151 static unsigned long current_directory_hash;
155 path_prefix_p_ (const char *path1, const char *path2, int len1)
157 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
158 if (len1 > 0 && SLASH_P (path1[len1 - 1]))
162 return SLASH_P (path2[0]) && !SLASH_P (path2[1]);
164 if (!strncasematch (path1, path2, len1))
167 return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
170 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
171 passing to Win32 API routines.
173 If an error occurs, `error' is set to the errno value.
174 Otherwise it is set to 0.
177 SYMLINK_FOLLOW - convert to PATH symlink points to
178 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
179 SYMLINK_IGNORE - do not check PATH for symlinks
180 SYMLINK_CONTENTS - just return symlink contents
184 path_conv::check (const char *src, symlink_follow follow_mode,
185 int use_full_path, const suffix_info *suffixes)
187 /* This array is used when expanding symlinks. It is MAX_PATH * 2
188 in length so that we can hold the expanded symlink plus a
190 char path_buf[MAX_PATH];
191 char path_copy[MAX_PATH];
192 char tmp_buf[MAX_PATH];
195 char *rel_path, *full_path;
197 if ((error = check_null_empty_path (src)))
201 rel_path = path_buf, full_path = this->path;
203 rel_path = this->path, full_path = path_buf;
205 /* This loop handles symlink expansion. */
209 fileattr = (DWORD) -1;
213 /* Must look up path in mount table, etc. */
214 error = cygwin_shared->mount.conv_to_win32_path (src, rel_path,
216 devn, unit, &path_flags);
226 /* Eat trailing slashes */
227 char *tail = strchr (full_path, '\0');
228 /* If path is only a drivename, Windows interprets it as
229 the current working directory on this drive instead of
230 the root dir which is what we want. So we need
231 the trailing backslash in this case. */
232 while (tail > full_path + 3 && (*--tail == '\\'))
234 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
235 strcat (full_path, "\\");
237 if (follow_mode == SYMLINK_IGNORE)
239 fileattr = GetFileAttributesA (path);
243 /* Make a copy of the path that we can munge up */
244 strcpy (path_copy, full_path);
246 tail = path_copy + 1 + (tail - full_path); // Point to end of copy
248 /* Scan path_copy from right to left looking either for a symlink
249 or an actual existing file. If an existing file is found, just
250 return. If a symlink is found exit the for loop.
251 Also: be careful to preserve the errno returned from
252 symlink.check as the caller may need it. */
253 /* FIXME: Do we have to worry about multiple \'s here? */
254 int component = 0; // Number of translated components
255 sym.contents[0] = '\0';
260 const suffix_info *suff;
262 /* Don't allow symlink.check to set anything in the path_conv
263 class if we're working on an inner component of the path */
272 sym.pflags = path_flags;
275 int len = sym.check (path_copy, suff);
278 path_flags = sym.pflags;
280 /* If symlink.check found an existing non-symlink file, then
281 it returns a length of 0 and sets errno to EINVAL. It also sets
282 any suffix found into `ext_here'. */
283 if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
287 fileattr = sym.fileattr;
290 goto out; // file found
292 /* Found a symlink if len > 0. If component == 0, then the
293 src path itself was a symlink. If !follow_mode then
294 we're done. Otherwise we have to insert the path found
295 into the full path that we are building and perform all of
296 these operations again on the newly derived path. */
299 if (component == 0 && follow_mode != SYMLINK_FOLLOW)
301 set_symlink (); // last component of path is a symlink.
302 fileattr = sym.fileattr;
303 if (follow_mode == SYMLINK_CONTENTS)
304 strcpy (path, sym.contents);
310 /* No existing file found. */
311 s.reset (); // remember errno from symlink.check
313 if (!(tail = strrchr (path_copy, '\\')) ||
314 (tail > path_copy && tail[-1] == ':'))
315 goto out; // all done
317 /* Haven't found a valid pathname component yet.
318 Pinch off the tail and try again. */
323 /* Arrive here if above loop detected a symlink. */
324 if (++loop > MAX_LINK_DEPTH)
326 error = ELOOP; // Eep.
331 tail = full_path + (tail - path_copy);
332 int taillen = strlen (tail);
333 int buflen = strlen (sym.contents);
334 if (buflen + taillen > MAX_PATH)
336 error = ENAMETOOLONG;
337 strcpy (path, "::ENAMETOOLONG::");
341 /* Copy tail of full_path to discovered symlink. */
343 for (p = sym.contents + buflen; *tail; tail++)
344 *p++ = *tail == '\\' ? '/' : *tail;
347 /* If symlink referred to an absolute path, then we
348 just use sym.contents and loop. Otherwise tack the head of
349 path_copy before sym.contents and translate it back from a
350 Win32-style path to a POSIX-style one. */
351 if (isabspath (sym.contents))
353 else if (!(tail = strrchr (path_copy, '\\')))
354 system_printf ("problem parsing %s - '%s'", src, full_path);
357 int headlen = 1 + tail - path_copy;
358 p = sym.contents - headlen;
359 memcpy (p, path_copy, headlen);
361 error = cygwin_shared->mount.conv_to_posix_path (p, tmp_buf, 1);
370 if (sym.known_suffix)
371 known_suffix = this->path + (sym.known_suffix - path_copy);
372 else if (sym.ext_here && follow_mode != SYMLINK_CONTENTS)
374 known_suffix = strchr (this->path, '\0');
375 strcpy (known_suffix, sym.ext_here);
379 DWORD serial, volflags;
381 strcpy (tmp_buf, full_path);
382 if (!rootdir (tmp_buf) ||
383 !GetVolumeInformation (tmp_buf, NULL, 0, &serial, NULL, &volflags, NULL, 0))
385 debug_printf ("GetVolumeInformation(%s) = ERR, full_path(%s), set_has_acls(FALSE)",
386 tmp_buf, full_path, GetLastError ());
387 set_has_acls (FALSE);
391 debug_printf ("GetVolumeInformation(%s) = OK, full_path(%s), set_has_acls(%d)",
392 tmp_buf, full_path, volflags & FS_PERSISTENT_ACLS);
393 set_has_acls (volflags & FS_PERSISTENT_ACLS);
397 #define deveq(s) (strcasematch (name, (s)))
398 #define deveqn(s, n) (strncasematch (name, (s), (n)))
401 digits (const char *name)
404 int n = strtol(name, &p, 10);
406 return p > name && !*p ? n : -1;
409 const char *windows_device_names[] =
436 get_raw_device_number (const char *uxname, const char *w32path, int &unit)
440 if (strncasecmp (w32path, "\\\\.\\tape", 8) == 0)
443 unit = digits (w32path + 8);
444 // norewind tape devices have leading n in name
445 if (! strncasecmp (uxname, "/dev/n", 6))
448 else if (isdrive (w32path + 4))
451 unit = tolower (w32path[4]) - 'a';
453 else if (strncasecmp (w32path, "\\\\.\\physicaldrive", 17) == 0)
456 unit = digits (w32path + 17) + 128;
462 get_device_number (const char *name, int &unit, BOOL from_conv)
467 if ((*name == '/' && deveqn ("/dev/", 5)) ||
468 (*name == '\\' && deveqn ("\\dev\\", 5)))
473 if (tty_attached (myself))
478 else if (myself->ctty > 0)
481 else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
483 else if (deveq ("ttym"))
485 else if (deveq ("ptmx"))
487 else if (deveq ("windows"))
489 else if (deveq ("conin"))
491 else if (deveq ("conout"))
493 else if (deveq ("null"))
495 else if (deveq ("zero"))
497 else if (deveq ("random") || deveq ("urandom"))
500 unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
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 if (devn == FH_RANDOM)
538 __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
540 __small_sprintf (win32_path, devfmt, unit);
544 /* Normalize a POSIX path.
545 \'s are converted to /'s in the process.
546 All duplicate /'s, except for 2 leading /'s, are deleted.
547 The result is 0 for success, or an errno error value. */
549 #define isslash(c) ((c) == '/')
552 normalize_posix_path (const char *cwd, const char *src, char *dst)
554 const char *src_start = src;
555 char *dst_start = dst;
557 if (!isslash (src[0]))
559 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
561 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
565 dst = strchr (dst, '\0');
568 if (dst == dst_start + 1)
572 if (dst > dst_start && !isslash (dst[-1]))
575 /* Two leading /'s? If so, preserve them. */
576 else if (isslash (src[1]))
582 { /* Starts with three or more slashes - reset. */
591 /* Strip runs of /'s. */
598 while (isslash (*src))
607 if ((src[1] && !isslash (src[1])))
612 if (src[2] && !isslash (src[2]))
614 while (dst > dst_start && !isslash (*--dst))
625 if (--dst > dst_start && isslash (*dst))
628 debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start);
632 /* Normalize a Win32 path.
633 /'s are converted to \'s in the process.
634 All duplicate \'s, except for 2 leading \'s, are deleted.
636 The result is 0 for success, or an errno error value.
637 FIXME: A lot of this should be mergeable with the POSIX critter. */
640 normalize_win32_path (const char *cwd, const char *src, char *dst)
642 const char *src_start = src;
643 char *dst_start = dst;
645 if (!SLASH_P (src[0]) && strchr (src, ':') == NULL)
647 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
649 debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
654 if (!*cwd || !SLASH_P (dst[-1]))
657 /* Two leading \'s? If so, preserve them. */
658 else if (SLASH_P (src[0]) && SLASH_P (src[1]))
666 /* Strip duplicate /'s. */
667 if (SLASH_P (src[0]) && SLASH_P (src[1]))
670 else if (src[0] == '.' && SLASH_P (src[1])
671 && (src == src_start || SLASH_P (src[-1])))
676 /* Backup if "..". */
677 else if (src[0] == '.' && src[1] == '.'
678 /* dst must be greater than dst_start */
680 && (SLASH_P (src[2]) || src[2] == 0))
682 /* Back up over /, but not if it's the first one. */
683 if (dst > dst_start + 1)
685 /* Now back up to the next /. */
686 while (dst > dst_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
692 /* Otherwise, add char to result. */
703 debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
708 /* Various utilities. */
710 /* slashify: Convert all back slashes in src path to forward slashes
711 in dst path. Add a trailing slash to dst when trailing_slash_p arg
715 slashify (const char *src, char *dst, int trailing_slash_p)
717 const char *start = src;
729 && !isdirsep (src[-1]))
734 /* backslashify: Convert all forward slashes in src path to back slashes
735 in dst path. Add a trailing slash to dst when trailing_slash_p arg
739 backslashify (const char *src, char *dst, int trailing_slash_p)
741 const char *start = src;
753 && !isdirsep (src[-1]))
758 /* nofinalslash: Remove trailing / and \ from SRC (except for the
759 first one). It is ok for src == dst. */
762 nofinalslash (const char *src, char *dst)
764 int len = strlen (src);
766 memcpy (dst, src, len + 1);
767 while (len > 1 && SLASH_P (dst[--len]))
771 /* slash_drive_prefix_p: Return non-zero if PATH begins with
775 slash_drive_prefix_p (const char *path)
777 return (isdirsep(path[0])
780 && (path[3] == 0 || path[3] == '/'));
783 /* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
786 slash_unc_prefix_p (const char *path)
789 int ret = (isdirsep (path[0])
790 && isdirsep (path[1])
793 && !isdirsep (path[3])
794 && ((p = strchr(&path[3], '/')) != NULL));
795 if (!ret || p == NULL)
797 return ret && isalnum (p[1]);
800 /* conv_path_list: Convert a list of path names to/from Win32/POSIX.
802 SRC is not a const char * because we temporarily modify it to ease
805 I believe Win32 always has '.' in $PATH. POSIX obviously doesn't.
806 We certainly don't want to handle that here, but it is something for
807 the caller to think about. */
810 conv_path_list (const char *src, char *dst, int to_posix_p)
814 char src_delim = to_posix_p ? ';' : ':';
815 char dst_delim = to_posix_p ? ':' : ';';
816 int (*conv_fn) (const char *, char *) = (to_posix_p
817 ? cygwin_conv_to_posix_path
818 : cygwin_conv_to_win32_path);
822 s = strchr (src, src_delim);
826 (*conv_fn) (src[0] != 0 ? src : ".", d);
835 (*conv_fn) (src[0] != 0 ? src : ".", d);
841 /************************* mount_info class ****************************/
843 /* init: Initialize the mount table. */
851 had_to_create_mount_areas = 0;
853 /* Fetch the mount table and cygdrive-related information from
857 /* If slash isn't already mounted, mount system directory as slash. */
859 for (int i = 0; i < nmounts; i++)
861 if (strcmp (mount[i].posix_path, "/") == 0)
872 /* mount_slash: mount the system partition as slash. */
875 mount_info::mount_slash ()
877 char drivestring[MAX_PATH];
878 GetSystemDirectory (drivestring, MAX_PATH);
879 drivestring[2] = 0; /* truncate path to "<drive>:" */
881 if (add_reg_mount (drivestring, "/", 0) == 0)
882 add_item (drivestring, "/", 0);
885 /* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
886 the result in win32_path.
888 If win32_path != NULL, the relative path, if possible to keep, is
889 stored in win32_path. If the relative path isn't possible to keep,
890 the full path is stored.
892 If full_win32_path != NULL, the full path is stored there.
894 The result is zero for success, or an errno value.
896 {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */
899 mount_info::conv_to_win32_path (const char *src_path, char *win32_path,
900 char *full_win32_path, DWORD &devn, int &unit,
903 int src_path_len = strlen (src_path);
904 int trailing_slash_p = (src_path_len > 0
905 && SLASH_P (src_path[src_path_len - 1]));
908 unsigned dummy_flags;
914 flags = &dummy_flags;
917 debug_printf ("conv_to_win32_path (%s)", src_path);
919 if (src_path_len >= MAX_PATH)
921 debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path);
927 mount_item *mi = NULL; /* initialized to avoid compiler warning */
928 char pathbuf[MAX_PATH];
931 getcwd_inner (cwd, MAX_PATH, TRUE); /* FIXME: check rc */
933 /* Determine where the destination should be placed. */
934 if (full_win32_path != NULL)
935 dst = full_win32_path;
936 else if (win32_path != NULL)
940 goto out; /* Sanity check. */
942 /* An MS-DOS spec has either a : or a \. If this is found, short
943 circuit most of the rest of this function. */
944 if (strpbrk (src_path, ":\\") != NULL)
946 debug_printf ("%s already win32", src_path);
947 rc = normalize_win32_path (current_directory_name, src_path, dst);
950 debug_printf ("normalize_win32_path failed, rc %d", rc);
953 isrelpath = !isabspath (src_path);
954 *flags = set_flags_from_win32_path (dst);
958 /* Normalize the path, taking out ../../ stuff, we need to do this
959 so that we can move from one mounted directory to another with relative
962 eg mounting c:/foo /foo
968 should look in c:/foo, not d:/foo.
970 We do this by first getting an absolute UNIX-style path and then
971 converting it to a DOS-style path, looking up the appropriate drive
972 in the mount table. */
974 /* No need to fetch cwd if path is absolute. */
975 isrelpath = !isslash (*src_path);
977 rc = normalize_posix_path (cwd, src_path, pathbuf);
981 debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
986 /* See if this is a cygwin "device" */
987 if (win32_device_name (pathbuf, dst, devn, unit))
989 *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */
993 /* Check if the cygdrive prefix was specified. If so, just strip
994 off the prefix and transform it into an MS-DOS path. */
996 if (iscygdrive_device (pathbuf))
998 if (!cygdrive_win32_path (pathbuf, dst, trailing_slash_p))
1000 *flags = cygdrive_flags;
1004 /* Check the mount table for prefix matches. */
1005 for (i = 0; i < nmounts; i++)
1007 mi = mount + posix_sorted[i];
1008 if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen))
1014 if (slash_drive_prefix_p (pathbuf))
1015 slash_drive_to_win32_path (pathbuf, dst, trailing_slash_p);
1017 backslashify (pathbuf, dst, trailing_slash_p); /* just convert */
1022 int n = mi->native_pathlen;
1023 memcpy (dst, mi->native_path, n + 1);
1024 char *p = pathbuf + mi->posix_pathlen;
1025 if (!trailing_slash_p && !*p)
1027 if (isdrive (dst) && !dst[2])
1033 /* Do not add trailing \ to UNC device names like \\.\a: */
1034 if (*p != '/' && /* FIXME: this test seems wrong. */
1035 (strncmp (mi->native_path, "\\\\.\\", 4) != 0 ||
1036 strncmp (mi->native_path + 4, "UNC\\", 4) == 0))
1038 strcpy (dst + n, p);
1040 backslashify (dst, dst, trailing_slash_p);
1045 /* Compute relative path if asked to and able to. */
1047 cwdlen = 0; /* avoid a (hopefully) bogus compiler warning */
1048 if (win32_path == NULL)
1049 /* nothing to do */;
1050 else if (isrelpath &&
1051 path_prefix_p (current_directory_name, dst,
1052 cwdlen = strlen (current_directory_name)))
1054 size_t n = strlen (dst);
1056 strcpy (win32_path, dst);
1062 dst += isdirsep (current_directory_name[cwdlen - 1]) ? cwdlen : cwdlen + 1;
1064 memmove (win32_path, dst, strlen (dst) + 1);
1067 strcpy (win32_path, ".");
1068 if (trailing_slash_p)
1069 strcat (win32_path, "\\");
1073 else if (win32_path != dst)
1074 strcpy (win32_path, dst);
1078 debug_printf ("%s(rel), %s(abs) %p(flags) = conv_to_win32_path (%s)",
1079 win32_path, full_win32_path, *flags,
1084 /* Convert PATH (for which slash_drive_prefix_p returns 1) to WIN32 form. */
1087 mount_info::slash_drive_to_win32_path (const char *path, char *buf,
1088 int trailing_slash_p)
1093 strcpy (buf + 2, "\\");
1095 backslashify (path + 3, buf + 2, trailing_slash_p);
1098 /* cygdrive_posix_path: Build POSIX path used as the
1099 mount point for cygdrives created when there is no other way to
1100 obtain a POSIX path from a Win32 one. */
1103 mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
1105 int len = cygdrive_len;
1107 memcpy (dst, cygdrive, len + 1);
1109 /* Now finish the path off with the drive letter to be used.
1110 The cygdrive prefix always ends with a trailing slash so
1111 the drive letter is added after the path. */
1112 dst[len++] = tolower (src[0]);
1113 if (!src[2] || (SLASH_P (src[2]) && !src[3]))
1114 dst[len++] = '\000';
1118 strcpy (dst + len, src + 3);
1120 slashify (dst, dst, trailing_slash_p);
1124 mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
1126 const char *p = src + cygdrive_len;
1127 if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
1131 strcpy (dst + 2, p + 1);
1132 backslashify (dst, dst, trailing_slash_p || !dst[2]);
1133 debug_printf ("src '%s', dst '%s'", src, dst);
1137 /* conv_to_posix_path: Ensure src_path is a POSIX path.
1139 The result is zero for success, or an errno value.
1140 posix_path must have sufficient space (i.e. MAX_PATH bytes).
1141 If keep_rel_p is non-zero, relative paths stay that way. */
1144 mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
1147 int src_path_len = strlen (src_path);
1148 int relative_path_p = !isabspath (src_path);
1149 int trailing_slash_p;
1151 if (src_path_len <= 1)
1152 trailing_slash_p = 0;
1155 const char *lastchar = src_path + src_path_len - 1;
1156 trailing_slash_p = SLASH_P (*lastchar) && lastchar[-1] != ':';
1159 debug_printf ("conv_to_posix_path (%s, %s, %s)", src_path,
1160 keep_rel_p ? "keep-rel" : "no-keep-rel",
1161 trailing_slash_p ? "add-slash" : "no-add-slash");
1164 if (src_path_len >= MAX_PATH)
1166 debug_printf ("ENAMETOOLONG");
1167 return ENAMETOOLONG;
1170 /* FIXME: For now, if the path is relative and it's supposed to stay
1171 that way, skip mount table processing. */
1173 if (keep_rel_p && relative_path_p)
1175 slashify (src_path, posix_path, 0);
1176 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1180 char pathbuf[MAX_PATH];
1183 /* No need to fetch cwd if path is absolute. */
1184 if (relative_path_p)
1185 getcwd_inner (cwd, MAX_PATH, 0); /* FIXME: check rc */
1187 strcpy (cwd, "/"); /* some innocuous value */
1189 int rc = normalize_win32_path (cwd, src_path, pathbuf);
1192 debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1196 int pathbuflen = strlen (pathbuf);
1197 for (int i = 0; i < nmounts; ++i)
1199 mount_item &mi = mount[native_sorted[i]];
1200 if (! path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1203 /* SRC_PATH is in the mount table. */
1205 const char *p = pathbuf + mi.native_pathlen;
1209 else if (isdirsep (*p))
1214 int addslash = nextchar > 0 ? 1 : 0;
1215 if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH)
1216 return ENAMETOOLONG;
1217 strcpy (posix_path, mi.posix_path);
1219 strcat (posix_path, "/");
1222 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
1227 /* Not in the database. This should [theoretically] only happen if either
1228 the path begins with //, or / isn't mounted, or the path has a drive
1229 letter not covered by the mount table. If it's a relative path then the
1230 caller must want an absolute path (otherwise we would have returned
1231 above). So we always return an absolute path at this point. */
1232 if (isdrive (pathbuf))
1233 cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p);
1236 /* The use of src_path and not pathbuf here is intentional.
1237 We couldn't translate the path, so just ensure no \'s are present. */
1238 slashify (src_path, posix_path, trailing_slash_p);
1242 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1247 /* Return flags associated with a mount point given the win32 path. */
1250 mount_info::set_flags_from_win32_path (const char *p)
1252 for (int i = 0; i < nmounts; i++)
1254 mount_item &mi = mount[native_sorted[i]];
1255 if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
1261 /* read_mounts: Given a specific regkey, read mounts from under its
1265 mount_info::read_mounts (reg_key& r)
1267 char posix_path[MAX_PATH];
1268 HKEY key = r.get_key ();
1269 DWORD i, posix_path_size;
1274 posix_path_size = MAX_PATH;
1275 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1278 if (err != ERROR_SUCCESS)
1281 if (iscygdrive (posix_path))
1283 /* This shouldn't be in the mount table. */
1284 (void) r.kill (posix_path);
1289 /* Loop through subkeys */
1290 /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
1291 shared area is currently statically allocated so we can't have an
1292 arbitrarily large number of mounts. */
1293 for (DWORD i = 0; i < MAX_MOUNTS; i++)
1295 char native_path[MAX_PATH];
1298 posix_path_size = MAX_PATH;
1299 /* FIXME: if maximum posix_path_size is 256, we're going to
1300 run into problems if we ever try to store a mount point that's
1301 over 256 but is under MAX_PATH! */
1302 LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1305 if (err == ERROR_NO_MORE_ITEMS)
1307 else if (err != ERROR_SUCCESS)
1309 debug_printf ("RegEnumKeyEx failed, error %d!\n", err);
1313 if (iscygdrive (posix_path))
1315 /* This shouldn't be in the mount table. */
1316 // (void) r.kill (posix_path);
1320 /* Get a reg_key based on i. */
1321 reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1323 /* Check the mount table for prefix matches. */
1324 for (int j = 0; j < nmounts; j++)
1325 if (strcasematch (mount[j].posix_path, posix_path))
1326 goto next; /* Can't have more than one */
1328 /* Fetch info from the subkey. */
1329 subkey.get_string ("native", native_path, sizeof (native_path), "");
1330 mount_flags = subkey.get_int ("flags", 0);
1332 /* Add mount_item corresponding to registry mount point. */
1333 cygwin_shared->mount.add_item (native_path, posix_path, mount_flags);
1339 /* from_registry: Build the entire mount table from the registry. Also,
1340 read in cygdrive-related information from its registry location. */
1343 mount_info::from_registry ()
1345 /* Use current mount areas if either user or system mount areas
1346 already exist. Otherwise, import old mounts. */
1350 /* Retrieve cygdrive-related information. */
1351 read_cygdrive_info_from_registry ();
1355 /* First read mounts from user's table. */
1358 /* Then read mounts from system-wide mount table. */
1359 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1360 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1361 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1362 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1366 /* If we had to create both user and system mount areas, import
1368 if (had_to_create_mount_areas == 2)
1369 import_v1_mounts ();
1374 /* add_reg_mount: Add mount item to registry. Return zero on success,
1375 non-zero on failure. */
1376 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1379 mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1381 /* Add the mount to the right registry location, depending on
1382 whether MOUNT_SYSTEM is set in the mount flags. */
1383 if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
1385 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1388 /* Start by deleting existing mount if one exists. */
1389 reg_user.kill (posix_path);
1391 /* Create the new mount. */
1392 reg_key subkey = reg_key (reg_user.get_key (),
1395 subkey.set_string ("native", native_path);
1396 subkey.set_int ("flags", mountflags);
1398 else /* local_machine mount */
1400 /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
1401 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1402 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1403 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1404 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1407 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1413 /* Start by deleting existing mount if one exists. */
1414 reg_sys.kill (posix_path);
1416 /* Create the new mount. */
1417 reg_key subkey = reg_key (reg_sys.get_key (),
1420 subkey.set_string ("native", native_path);
1421 subkey.set_int ("flags", mountflags);
1424 return 0; /* Success! */
1427 /* del_reg_mount: delete mount item from registry indicated in flags.
1428 Return zero on success, non-zero on failure.*/
1429 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1432 mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1436 if ((flags & MOUNT_SYSTEM) == 0) /* Delete from user registry */
1438 reg_key reg_user (KEY_ALL_ACCESS,
1439 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
1440 killres = reg_user.kill (posix_path);
1442 else /* Delete from system registry */
1444 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1445 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1446 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1447 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1450 if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1456 killres = reg_sys.kill (posix_path);
1459 if (killres != ERROR_SUCCESS)
1461 __seterrno_from_win_error (killres);
1465 return 0; /* Success! */
1468 /* read_cygdrive_info_from_registry: Read the default prefix and flags
1469 to use when creating cygdrives from the special user registry
1470 location used to store cygdrive information. */
1473 mount_info::read_cygdrive_info_from_registry ()
1475 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1478 if (r.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1480 /* Didn't find it so write the default to the registry and use it. */
1481 write_cygdrive_info_to_registry ("/cygdrive", MOUNT_AUTO);
1485 /* Fetch cygdrive_flags from registry; returns MOUNT_AUTO on error. */
1486 cygdrive_flags = r.get_int ("cygdrive flags", MOUNT_AUTO);
1487 slashify (cygdrive, cygdrive, 1);
1488 cygdrive_len = strlen(cygdrive);
1492 /* write_cygdrive_info_to_registry: Write the default prefix and flags
1493 to use when creating cygdrives to the special user registry
1494 location used to store cygdrive information. */
1497 mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1499 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1502 /* Verify cygdrive prefix starts with a forward slash and if there's
1503 another character, it's not a slash. */
1504 if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
1505 (!isslash (cygdrive_prefix[0])) ||
1506 ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
1512 char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1];
1513 /* Ensure that there is never a final slash */
1514 nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
1516 r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
1517 r.set_int ("cygdrive flags", flags);
1519 /* This also needs to go in the in-memory copy of "cygdrive" */
1520 slashify (cygdrive_prefix, cygwin_shared->mount.cygdrive, 1);
1521 cygwin_shared->mount.cygdrive_flags = flags;
1522 cygwin_shared->mount.cygdrive_len = strlen(cygwin_shared->mount.cygdrive);
1528 mount_info::getmntent (int x)
1530 if (x < 0 || x >= nmounts)
1533 return mount[native_sorted[x]].getmntent ();
1536 static mount_item *mounts_for_sort;
1538 /* sort_by_posix_name: qsort callback to sort the mount entries. Sort
1539 user mounts ahead of system mounts to the same POSIX path. */
1540 /* FIXME: should the user should be able to choose whether to
1541 prefer user or system mounts??? */
1543 sort_by_posix_name (const void *a, const void *b)
1545 mount_item *ap = mounts_for_sort + (*((int*) a));
1546 mount_item *bp = mounts_for_sort + (*((int*) b));
1548 /* Base weighting on longest posix path first so that the most
1549 obvious path will be chosen. */
1550 size_t alen = strlen (ap->posix_path);
1551 size_t blen = strlen (bp->posix_path);
1553 int res = blen - alen;
1556 return res; /* Path lengths differed */
1558 /* The two paths were the same length, so just determine normal
1559 lexical sorted order. */
1560 res = strcmp (ap->posix_path, bp->posix_path);
1564 /* need to select between user and system mount to same POSIX path */
1565 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1574 /* sort_by_native_name: qsort callback to sort the mount entries. Sort
1575 user mounts ahead of system mounts to the same POSIX path. */
1576 /* FIXME: should the user should be able to choose whether to
1577 prefer user or system mounts??? */
1579 sort_by_native_name (const void *a, const void *b)
1581 mount_item *ap = mounts_for_sort + (*((int*) a));
1582 mount_item *bp = mounts_for_sort + (*((int*) b));
1584 /* Base weighting on longest win32 path first so that the most
1585 obvious path will be chosen. */
1586 size_t alen = strlen (ap->native_path);
1587 size_t blen = strlen (bp->native_path);
1589 int res = blen - alen;
1592 return res; /* Path lengths differed */
1594 /* The two paths were the same length, so just determine normal
1595 lexical sorted order. */
1596 res = strcasecmp (ap->posix_path, bp->posix_path);
1600 /* need to select between user and system mount to same POSIX path */
1601 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1613 for (int i = 0; i < nmounts; i++)
1614 native_sorted[i] = posix_sorted[i] = i;
1615 /* Sort them into reverse length order, otherwise we won't
1616 be able to look for /foo in /. */
1617 mounts_for_sort = mount; /* ouch. */
1618 qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
1619 qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
1622 /* Add an entry to the in-memory mount table.
1623 Returns 0 on success, -1 on failure and errno is set.
1625 This is where all argument validation is done. It may not make sense to
1626 do this when called internally, but it's cleaner to keep it all here. */
1629 mount_info::add_item (const char *native, const char *posix, unsigned mountflags)
1631 /* Can't add more than MAX_MOUNTS. */
1632 if (nmounts == MAX_MOUNTS)
1638 /* Something's wrong if either path is NULL or empty, or if it's
1639 not a UNC or absolute path. */
1641 if ((native == NULL) || (*native == 0) ||
1642 (posix == NULL) || (*posix == 0) ||
1643 (!slash_unc_prefix_p (native) && !isabspath (native)))
1649 /* Make sure both paths do not end in /. */
1650 char nativetmp[MAX_PATH];
1651 char posixtmp[MAX_PATH];
1653 if (slash_drive_prefix_p (native))
1654 slash_drive_to_win32_path (native, nativetmp, 0);
1657 backslashify (native, nativetmp, 0);
1658 nofinalslash (nativetmp, nativetmp);
1661 slashify (posix, posixtmp, 0);
1662 nofinalslash (posixtmp, posixtmp);
1664 debug_printf ("%s[%s], %s[%s], %p",
1665 native, nativetmp, posix, posixtmp, mountflags);
1667 /* Duplicate /'s in path are an error. */
1668 for (char *p = posixtmp + 1; *p; ++p)
1670 if (p[-1] == '/' && p[0] == '/')
1677 /* Write over an existing mount item with the same POSIX path if
1678 it exists and is from the same registry area. */
1679 for (int i = 0; i < nmounts; i++)
1681 if ((strcmp (mount[i].posix_path, posixtmp) == 0) &&
1682 ((mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM)))
1684 /* replace existing mount item */
1685 mount[i].init (nativetmp, posixtmp, mountflags);
1690 mount[nmounts++].init (nativetmp, posixtmp, mountflags);
1698 /* Delete a mount table entry where path is either a Win32 or POSIX
1699 path. Since the mount table is really just a table of aliases,
1700 deleting / is ok (although running without a slash mount is
1701 strongly discouraged because some programs may run erratically
1702 without one). If MOUNT_SYSTEM is set in flags, remove from system
1703 registry, otherwise remove the user registry mount.
1707 mount_info::del_item (const char *path, unsigned flags)
1709 char pathtmp[MAX_PATH];
1711 /* Something's wrong if path is NULL or empty. */
1712 if ((path == NULL) || (*path == 0))
1718 slashify (path, pathtmp, 0);
1719 nofinalslash (pathtmp, pathtmp);
1721 debug_printf ("%s[%s]", path, pathtmp);
1723 for (int i = 0; i < nmounts; i++)
1725 /* Delete if paths and mount locations match. */
1726 if (((strcmp (mount[i].posix_path, pathtmp) == 0
1727 || strcmp (mount[i].native_path, pathtmp) == 0)) &&
1728 ((mount[i].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM)))
1730 nmounts--; /* One less mount table entry */
1731 /* Fill in the hole if not at the end of the table */
1733 memcpy (mount + i, mount + i + 1,
1734 sizeof (mount[i]) * (nmounts - i));
1735 sort (); /* Resort the table */
1743 /* read_v1_mounts: Given a reg_key to an old mount table registry area,
1744 read in the mounts. The "which" arg contains zero if we're reading
1745 the user area and MOUNT_SYSTEM if we're reading the system area.
1746 This way we can store the mounts read in the appropriate place when
1747 they are written back to the new registry layout. */
1750 mount_info::read_v1_mounts (reg_key r, unsigned which)
1752 unsigned mountflags = 0;
1754 /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
1755 for (int i = 0; i < 30; i++)
1758 char win32path[MAX_PATH];
1759 char unixpath[MAX_PATH];
1761 __small_sprintf (key_name, "%02x", i);
1763 reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
1765 /* The registry names are historical but useful so are left alone. */
1766 k.get_string ("native", win32path, sizeof (win32path), "");
1767 k.get_string ("unix", unixpath, sizeof (unixpath), "");
1769 /* Does this entry contain something? */
1770 if (*win32path != 0)
1774 if (k.get_int ("fbinary", 0))
1775 mountflags |= MOUNT_BINARY;
1777 /* Or in zero or MOUNT_SYSTEM depending on which table
1779 mountflags |= which;
1781 cygwin_shared->mount.add_item (win32path, unixpath, mountflags);
1786 /* from_v1_registry: Build the entire mount table from the old v1 registry
1790 mount_info::from_v1_registry ()
1792 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
1802 /* First read mounts from user's table. */
1803 read_v1_mounts (r, 0);
1805 /* Then read mounts from system-wide mount table. */
1806 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
1813 read_v1_mounts (r1, MOUNT_SYSTEM);
1815 /* Note: we don't need to sort internal table here since it is
1816 done in main from_registry call after this function would be
1820 /* import_v1_mounts: If v1 mounts are present, load them and write
1821 the new entries to the new registry area. */
1824 mount_info::import_v1_mounts ()
1826 /* Read in old mounts into memory. */
1827 from_v1_registry ();
1829 /* Write all mounts to the new registry. */
1833 /* to_registry: For every mount point in memory, add a corresponding
1834 registry mount point. */
1837 mount_info::to_registry ()
1839 for (int i = 0; i < MAX_MOUNTS; i++)
1843 mount_item *p = mount + i;
1845 add_reg_mount (p->native_path, p->posix_path, p->flags);
1847 debug_printf ("%02x: %s, %s, %d",
1848 i, p->native_path, p->posix_path, p->flags);
1853 /************************* mount_item class ****************************/
1856 mount_item::getmntent ()
1859 struct mntent &ret=_reent_winsup()->_ret;
1861 static NO_COPY struct mntent ret;
1864 /* Pass back pointers to mount_info strings reserved for use by
1865 getmntent rather than pointers to strings in the internal mount
1866 table because the mount table might change, causing weird effects
1867 from the getmntent user's point of view. */
1869 strcpy (cygwin_shared->mount.mnt_fsname, native_path);
1870 ret.mnt_fsname = cygwin_shared->mount.mnt_fsname;
1871 strcpy (cygwin_shared->mount.mnt_dir, posix_path);
1872 ret.mnt_dir = cygwin_shared->mount.mnt_dir;
1874 if (!(flags & MOUNT_SYSTEM)) /* user mount */
1875 strcpy (cygwin_shared->mount.mnt_type, (char *) "user");
1876 else /* system mount */
1877 strcpy (cygwin_shared->mount.mnt_type, (char *) "system");
1879 if ((flags & MOUNT_AUTO)) /* cygdrive */
1880 strcat (cygwin_shared->mount.mnt_type, (char *) ",auto");
1882 ret.mnt_type = cygwin_shared->mount.mnt_type;
1884 /* mnt_opts is a string that details mount params such as
1885 binary or textmode, or exec. We don't print
1886 `silent' here; it's a magic internal thing. */
1888 if (! (flags & MOUNT_BINARY))
1889 strcpy (cygwin_shared->mount.mnt_opts, (char *) "textmode");
1891 strcpy (cygwin_shared->mount.mnt_opts, (char *) "binmode");
1893 if (flags & MOUNT_CYGWIN_EXEC)
1894 strcat (cygwin_shared->mount.mnt_opts, (char *) ",cygexec");
1895 else if (flags & MOUNT_EXEC)
1896 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 /* Open the file. */
2193 h = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
2194 FILE_ATTRIBUTE_NORMAL, 0);
2196 if (h == INVALID_HANDLE_VALUE)
2197 goto file_not_symlink;
2200 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2203 if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
2205 else if (got == sizeof (cookie_buf)
2206 && memcmp (cookie_buf, SYMLINK_COOKIE,
2207 sizeof (cookie_buf)) == 0)
2209 /* It's a symlink. */
2210 pflags = PATH_SYMLINK;
2212 res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2217 /* Versions prior to b16 stored several trailing
2218 NULs with the path (to fill the path out to 1024
2219 chars). Current versions only store one trailing
2220 NUL. The length returned is the path without
2221 *any* trailing NULs. We also have to handle (or
2222 at least not die from) corrupted paths. */
2223 if (memchr (contents, 0, got) != NULL)
2224 res = strlen (contents);
2229 else if (got == sizeof (cookie_buf)
2230 && memcmp (cookie_buf, SOCKET_COOKIE,
2231 sizeof (cookie_buf)) == 0)
2233 pflags |= PATH_SOCKET;
2234 goto close_and_return;
2238 /* Not a symlink, see if executable. */
2239 if (!(pflags & (PATH_EXEC | PATH_CYGWIN_EXEC)) && got >= 2 &&
2240 ((cookie_buf[0] == '#' && cookie_buf[1] == '!') ||
2241 (cookie_buf[0] == ':' && cookie_buf[1] == '\n')))
2242 pflags |= PATH_EXEC;
2245 goto file_not_symlink;
2258 syscall_printf ("not a symlink");
2262 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2263 res, path, contents, pflags);
2268 /* readlink system call */
2272 readlink (const char *path, char *buf, int buflen)
2274 extern suffix_info stat_suffixes[];
2275 path_conv pathbuf (path, SYMLINK_CONTENTS, 0, stat_suffixes);
2279 set_errno (pathbuf.error);
2280 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2284 if (!pathbuf.issymlink ())
2286 if (pathbuf.fileattr != (DWORD) -1)
2291 int len = strlen (pathbuf.get_win32 ());
2292 if (len > (buflen - 1))
2294 set_errno (ENAMETOOLONG);
2297 memcpy (buf, pathbuf.get_win32 (), len);
2300 /* errno set by symlink.check if error */
2304 /* Some programs rely on st_dev/st_ino being unique for each file.
2305 Hash the path name and hope for the best. The hash arg is not
2306 always initialized to zero since readdir needs to compute the
2307 dirent ino_t based on a combination of the hash of the directory
2308 done during the opendir call and the hash or the filename within
2309 the directory. FIXME: Not bullet-proof. */
2310 /* Cygwin internal */
2312 unsigned long __stdcall
2313 hash_path_name (unsigned long hash, const char *name)
2318 /* Perform some initial permutations on the pathname if this is
2322 /* Simplistic handling of drives. If there is a drive specified,
2323 make sure that the initial letter is upper case. If there is
2324 no \ after the ':' assume access through the root directory
2326 FIXME: Should really honor MS-Windows convention of using
2327 the environment to track current directory on various drives. */
2330 char *nn, *newname = (char *) alloca (strlen (name) + 2);
2331 nn = strncpy (newname, name, 2);
2333 *newname = toupper (*nn);
2346 /* Fill out the hashed path name with the current working directory if
2347 this is not an absolute path and there is no pre-specified hash value.
2348 Otherwise the inodes same will differ depending on whether a file is
2349 referenced with an absolute value or relatively. */
2351 if (*name != '\\' && (current_directory_name == NULL ||
2352 get_current_directory_name ()))
2354 hash = current_directory_hash;
2355 if (name[0] == '.' && name[1] == '\0')
2357 hash = hash_path_name (hash, "\\");
2362 /* Build up hash. Ignore single trailing slash or \a\b\ != \a\b or
2363 \a\b\. but allow a single \ if that's all there is. */
2366 hash += *name + (*name << 17);
2369 while (*++name != '\0' &&
2370 !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
2375 get_current_directory_name ()
2379 for (dlen = 256; ; dlen *= 2)
2381 current_directory_name = (char *) realloc (current_directory_name, dlen + 2);
2382 if ((len = GetCurrentDirectoryA (dlen, current_directory_name)) < dlen)
2389 current_directory_hash = hash_path_name (0, current_directory_name);
2397 getcwd_inner (char *buf, size_t ulen, int posix_p)
2399 char *resbuf = NULL;
2402 if (current_directory_name == NULL && !get_current_directory_name ())
2407 if (strlen (current_directory_name) >= len)
2411 strcpy (buf, current_directory_name);
2415 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, win32) (cached)",
2416 resbuf, resbuf ? resbuf : "", buf, len);
2419 else if (current_directory_posix_name != NULL)
2421 if (strlen (current_directory_posix_name) >= len)
2425 strcpy (buf, current_directory_posix_name);
2429 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, posix) (cached)",
2430 resbuf, resbuf ? resbuf : "", buf, len);
2434 /* posix_p required and current_directory_posix_name == NULL */
2436 char temp[MAX_PATH];
2438 /* Turn from Win32 style to our style. */
2439 cygwin_shared->mount.conv_to_posix_path (current_directory_name, temp, 0);
2441 size_t tlen = strlen (temp);
2443 current_directory_posix_name = (char *) realloc (
2444 current_directory_posix_name, tlen + 1);
2445 if (current_directory_posix_name != NULL)
2446 strcpy (current_directory_posix_name, temp);
2450 /* len was too small */
2459 syscall_printf ("%p (%s) = getcwd_inner (%p, %d, %s)",
2460 resbuf, resbuf ? resbuf : "",
2461 buf, len, posix_p ? "posix" : "win32");
2466 getcwd (char *buf, size_t ulen)
2470 if (buf == NULL || ulen == 0)
2472 buf = (char *) alloca (MAX_PATH);
2473 res = getcwd_inner (buf, MAX_PATH, 1);
2478 res = getcwd_inner (buf, ulen, 1);
2484 /* getwd: standards? */
2489 return getcwd (buf, MAX_PATH);
2492 /* chdir: POSIX 5.2.1.1 */
2495 chdir (const char *dir)
2497 path_conv path (dir);
2501 set_errno (path.error);
2502 syscall_printf ("-1 = chdir (%s)", dir);
2506 char *native_dir = path.get_win32 ();
2508 /* Check to see if path translates to something like C:.
2509 If it does, append a \ to the native directory specification to
2510 defeat the Windows 95 (i.e. MS-DOS) tendency of returning to
2511 the last directory visited on the given drive. */
2512 if (isdrive (native_dir) && !native_dir[2])
2514 native_dir[2] = '\\';
2515 native_dir[3] = '\0';
2517 int res = SetCurrentDirectoryA (native_dir) ? 0 : -1;
2521 /* Clear the cache until we need to retrieve the directory again. */
2522 if (current_directory_name != NULL)
2524 free (current_directory_name);
2525 current_directory_name = NULL;
2527 if (current_directory_posix_name != NULL)
2529 free (current_directory_posix_name);
2530 current_directory_posix_name = NULL;
2533 syscall_printf ("%d = chdir (%s) (dos %s)", res, dir, native_dir);
2537 /******************** Exported Path Routines *********************/
2539 /* Cover functions to the path conversion routines.
2540 These are exported to the world as cygwin_foo by cygwin.din. */
2544 cygwin_conv_to_win32_path (const char *path, char *win32_path)
2546 path_conv p (path, SYMLINK_FOLLOW, 0);
2549 set_errno (p.error);
2553 strcpy (win32_path, p.get_win32 ());
2559 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
2561 path_conv p (path, SYMLINK_FOLLOW, 1);
2564 set_errno (p.error);
2568 strcpy (win32_path, p.get_win32 ());
2572 /* This is exported to the world as cygwin_foo by cygwin.din. */
2576 cygwin_conv_to_posix_path (const char *path, char *posix_path)
2578 if (check_null_empty_path_errno (path))
2580 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 1);
2586 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
2588 if (check_null_empty_path_errno (path))
2590 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 0);
2594 /* The realpath function is supported on some UNIX systems. */
2598 realpath (const char *path, char *resolved)
2602 path_conv real_path (path, SYMLINK_FOLLOW, 1);
2604 if (real_path.error)
2605 err = real_path.error;
2608 err = cygwin_shared->mount.conv_to_posix_path (real_path.get_win32 (), resolved, 0);
2613 /* FIXME: on error, we are supposed to put the name of the path
2614 component which could not be resolved into RESOLVED. */
2621 /* Return non-zero if path is a POSIX path list.
2622 This is exported to the world as cygwin_foo by cygwin.din.
2625 <sect1 id="add-func-cygwin-posix-path-list-p">
2626 <para>Rather than use a mode to say what the "proper" path list
2627 format is, we allow any, and give apps the tools they need to
2628 convert between the two. If a ';' is present in the path list it's
2629 a Win32 path list. Otherwise, if the first path begins with
2630 [letter]: (in which case it can be the only element since if it
2631 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
2632 it's a POSIX path list.</para>
2639 cygwin_posix_path_list_p (const char *path)
2641 int posix_p = ! (strchr (path, ';') || isdrive (path));
2645 /* These are used for apps that need to convert env vars like PATH back and
2646 forth. The conversion is a two step process. First, an upper bound on the
2647 size of the buffer needed is computed. Then the conversion is done. This
2648 allows the caller to use alloca if it wants. */
2651 conv_path_list_buf_size (const char *path_list, int to_posix_p)
2653 int i, num_elms, max_mount_path_len, size;
2656 /* The theory is that an upper bound is
2657 current_size + (num_elms * max_mount_path_len) */
2659 char delim = to_posix_p ? ';' : ':';
2661 for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms)
2664 /* 7: strlen ("//c") + slop, a conservative initial value */
2665 for (max_mount_path_len = 7, i = 0; i < cygwin_shared->mount.nmounts; ++i)
2667 int mount_len = (to_posix_p
2668 ? cygwin_shared->mount.mount[i].posix_pathlen
2669 : cygwin_shared->mount.mount[i].native_pathlen);
2670 if (max_mount_path_len < mount_len)
2671 max_mount_path_len = mount_len;
2675 size = strlen (path_list) + (num_elms * max_mount_path_len) + 100;
2681 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
2683 return conv_path_list_buf_size (path_list, 1);
2688 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
2690 return conv_path_list_buf_size (path_list, 0);
2695 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
2697 conv_path_list (win32, posix, 1);
2703 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
2705 conv_path_list (posix, win32, 0);
2709 /* cygwin_split_path: Split a path into directory and file name parts.
2710 Buffers DIR and FILE are assumed to be big enough.
2712 Examples (path -> `dir' / `file'):
2715 . -> `.' / `.' (FIXME: should this be `.' / `'?)
2716 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
2718 foo/bar -> `foo' / `bar'
2719 foo/bar/ -> `foo' / `bar'
2721 /foo/bar -> `/foo' / `bar'
2724 c:foo -> `c:/' / `foo'
2725 c:/foo -> `c:/' / `foo'
2730 cygwin_split_path (const char *path, char *dir, char *file)
2732 int dir_started_p = 0;
2734 /* Deal with drives.
2735 Remember that c:foo <==> c:/foo. */
2747 if (SLASH_P (*path))
2752 /* Determine if there are trailing slashes and "delete" them if present.
2753 We pretend as if they don't exist. */
2754 const char *end = path + strlen (path);
2755 /* path + 1: keep leading slash. */
2756 while (end > path + 1 && SLASH_P (end[-1]))
2759 /* At this point, END points to one beyond the last character
2760 (with trailing slashes "deleted"). */
2762 /* Point LAST_SLASH at the last slash (duh...). */
2763 const char *last_slash;
2764 for (last_slash = end - 1; last_slash >= path; --last_slash)
2765 if (SLASH_P (*last_slash))
2768 if (last_slash == path)
2773 else if (last_slash > path)
2775 memcpy (dir, path, last_slash - path);
2776 dir[last_slash - path] = 0;
2781 ; /* nothing to do */
2787 memcpy (file, last_slash + 1, end - last_slash - 1);
2788 file[end - last_slash - 1] = 0;
2791 /********************** String Helper Functions ************************/
2793 #define CHXOR ('a' ^ 'A')
2794 #define ch_case_eq(ch1, ch2) \
2797 !((x = ((unsigned char)ch1 ^ (unsigned char)ch2)) && \
2798 (x != CHXOR || !isalpha (ch1))); \
2802 strncasematch (const char *s1, const char *s2, size_t n)
2810 if (!ch_case_eq (*s1, *s2))
2814 return !n || *s2 == '\0';
2818 strcasematch (const char *s1, const char *s2)
2825 if (!ch_case_eq (*s1, *s2))
2833 strcasestr (const char *searchee, const char *lookfor)
2839 return (char *) searchee;
2847 if (lookfor[i] == 0)
2848 return (char *) searchee;
2850 if (!ch_case_eq (lookfor[i], searchee[i]))