1 /* path.cc: path support.
3 Copyright 1996, 1997, 1998, 1999, 2000 Red Hat, Inc.
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 - A \ or : in a path denotes a pure windows spec.
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.
22 The goal in the above set of rules is to allow both POSIX and Win32
23 flavors of pathnames without either interfering. The rules are
24 intended to be as close to a superset of both as possible.
26 Note that you can have more than one path to a file. The mount
27 table is always prefered when translating Win32 paths to POSIX
28 paths. Win32 paths in mount table entries may be UNC paths or
29 standard Win32 paths starting with <drive-letter>:
31 Text vs Binary issues are not considered here in path style
32 decisions, although the appropriate flags are retrieved and
33 stored in various structures.
35 Removing mounted filesystem support would simplify things greatly,
36 but having it gives us a mechanism of treating disk that lives on a
37 UNIX machine as having UNIX semantics [it allows one to edit a text
38 file on that disk and not have cr's magically appear and perhaps
39 break apps running on UNIX boxes]. It also useful to be able to
40 layout a hierarchy without changing the underlying directories.
42 The semantics of mounting file systems is not intended to precisely
43 follow normal UNIX systems.
45 Each DOS drive is defined to have a current directory. Supporting
46 this would complicate things so for now things are defined so that
47 c: means c:\. FIXME: Is this still true?
53 #include <sys/mount.h>
60 #include <sys/cygwin.h>
61 #include <cygwin/version.h>
70 #include "shared_info.h"
74 static int normalize_win32_path (const char *src, char *dst);
75 static void slashify (const char *src, char *dst, int trailing_slash_p);
76 static void backslashify (const char *src, char *dst, int trailing_slash_p);
77 static int path_prefix_p_ (const char *path1, const char *path2, int len1);
81 char buf[3 + MAX_PATH * 3];
89 symlink_info (): known_suffix (NULL), contents (buf + MAX_PATH + 1) {}
90 int check (const char *path, const suffix_info *suffixes);
93 cwdstuff cygcwd; /* The current working directory. */
95 #define path_prefix_p(p1, p2, l1) \
96 ((tolower(*(p1))==tolower(*(p2))) && \
97 path_prefix_p_(p1, p2, l1))
99 #define SYMLINKATTR(x) \
100 (((x) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) == \
101 FILE_ATTRIBUTE_SYSTEM)
103 /* Determine if path prefix matches current cygdrive */
104 #define iscygdrive(path) \
105 (path_prefix_p (cygwin_shared->mount.cygdrive, (path), cygwin_shared->mount.cygdrive_len))
107 #define iscygdrive_device(path) \
108 (iscygdrive(path) && isalpha(path[cygwin_shared->mount.cygdrive_len]) && \
109 (isdirsep(path[cygwin_shared->mount.cygdrive_len + 1]) || \
110 !path[cygwin_shared->mount.cygdrive_len + 1]))
112 #define ischrootpath(path) \
113 (myself->rootlen && \
114 strncasematch (myself->root, path, myself->rootlen) && \
115 (path[myself->rootlen] == '/' || path[myself->rootlen] == '\0'))
117 /* Return non-zero if PATH1 is a prefix of PATH2.
118 Both are assumed to be of the same path style and / vs \ usage.
120 LEN1 = strlen (PATH1). It's passed because often it's already known.
123 /foo/ is a prefix of /foo <-- may seem odd, but desired
124 /foo is a prefix of /foo/
125 / is a prefix of /foo/bar
126 / is not a prefix of foo/bar
127 foo/ is a prefix foo/bar
128 /foo is not a prefix of /foobar
132 path_prefix_p_ (const char *path1, const char *path2, int len1)
134 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
135 if (len1 > 0 && SLASH_P (path1[len1 - 1]))
139 return SLASH_P (path2[0]) && !SLASH_P (path2[1]);
141 if (!strncasematch (path1, path2, len1))
144 return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
147 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
148 passing to Win32 API routines.
150 If an error occurs, `error' is set to the errno value.
151 Otherwise it is set to 0.
154 SYMLINK_FOLLOW - convert to PATH symlink points to
155 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
156 SYMLINK_IGNORE - do not check PATH for symlinks
157 SYMLINK_CONTENTS - just return symlink contents
161 path_conv::check (const char *src, unsigned opt,
162 const suffix_info *suffixes)
164 /* This array is used when expanding symlinks. It is MAX_PATH * 2
165 in length so that we can hold the expanded symlink plus a
167 char path_buf[MAX_PATH];
168 char path_copy[MAX_PATH];
169 char tmp_buf[MAX_PATH];
172 char *rel_path, *full_path;
174 if (!(opt & PC_NULLEMPTY))
176 else if ((error = check_null_empty_path (src)))
180 rel_path = path_buf, full_path = this->path;
182 rel_path = this->path, full_path = path_buf;
184 /* This loop handles symlink expansion. */
188 fileattr = (DWORD) -1;
192 DWORD need_directory = 0;
193 char *p = strrchr (src, '/');
196 if (strcmp (p, "/") == 0 || strcmp (p, "/.") == 0)
197 need_directory = PATH_NEEDDIR;
199 else if ((p = strrchr (src, '\\')) &&
200 (strcmp (p, "\\") == 0 || strcmp (p, "\\.") == 0))
201 need_directory = PATH_NEEDDIR;
202 /* Must look up path in mount table, etc. */
203 error = cygwin_shared->mount.conv_to_win32_path (src, rel_path,
205 devn, unit, &path_flags);
215 /* Eat trailing slashes */
216 char *tail = strchr (full_path, '\0');
217 /* If path is only a drivename, Windows interprets it as
218 the current working directory on this drive instead of
219 the root dir which is what we want. So we need
220 the trailing backslash in this case. */
221 while (tail > full_path + 3 && (*--tail == '\\'))
223 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
224 strcat (full_path, "\\");
226 if (opt & PC_SYM_IGNORE)
228 fileattr = GetFileAttributesA (path);
232 /* Make a copy of the path that we can munge up */
233 strcpy (path_copy, full_path);
235 tail = path_copy + 1 + (tail - full_path); // Point to end of copy
237 /* Scan path_copy from right to left looking either for a symlink
238 or an actual existing file. If an existing file is found, just
239 return. If a symlink is found exit the for loop.
240 Also: be careful to preserve the errno returned from
241 symlink.check as the caller may need it. */
242 /* FIXME: Do we have to worry about multiple \'s here? */
243 int component = 0; // Number of translated components
244 sym.contents[0] = '\0';
248 const suffix_info *suff;
250 /* Don't allow symlink.check to set anything in the path_conv
251 class if we're working on an inner component of the path */
260 sym.pflags = path_flags | need_directory;
263 int len = sym.check (path_copy, suff);
266 path_flags = sym.pflags;
268 /* If symlink.check found an existing non-symlink file, then
269 it sets the appropriate flag. It also sets any suffix found
271 if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
276 fileattr = sym.fileattr;
279 goto out; // file found
281 /* Found a symlink if len > 0. If component == 0, then the
282 src path itself was a symlink. If !follow_mode then
283 we're done. Otherwise we have to insert the path found
284 into the full path that we are building and perform all of
285 these operations again on the newly derived path. */
288 if (component == 0 && !(opt & PC_SYM_FOLLOW))
290 set_symlink (); // last component of path is a symlink.
291 fileattr = sym.fileattr;
292 if (opt & PC_SYM_CONTENTS)
293 strcpy (path, sym.contents);
299 /* No existing file found. */
301 if (!(tail = strrchr (path_copy, '\\')) ||
302 (tail > path_copy && tail[-1] == ':'))
303 goto out; // all done
305 /* Haven't found a valid pathname component yet.
306 Pinch off the tail and try again. */
311 /* Arrive here if above loop detected a symlink. */
312 if (++loop > MAX_LINK_DEPTH)
314 error = ELOOP; // Eep.
319 tail = full_path + (tail - path_copy);
320 int taillen = strlen (tail);
321 int buflen = strlen (sym.contents);
322 if (buflen + taillen > MAX_PATH)
324 error = ENAMETOOLONG;
325 strcpy (path, "::ENAMETOOLONG::");
329 /* Copy tail of full_path to discovered symlink. */
330 for (p = sym.contents + buflen; *tail; tail++)
331 *p++ = *tail == '\\' ? '/' : *tail;
334 /* If symlink referred to an absolute path, then we
335 just use sym.contents and loop. Otherwise tack the head of
336 path_copy before sym.contents and translate it back from a
337 Win32-style path to a POSIX-style one. */
338 if (isabspath (sym.contents))
340 else if (!(tail = strrchr (path_copy, '\\')))
341 system_printf ("problem parsing %s - '%s'", src, full_path);
344 int headlen = 1 + tail - path_copy;
345 p = sym.contents - headlen;
346 memcpy (p, path_copy, headlen);
348 error = cygwin_shared->mount.conv_to_posix_path (p, tmp_buf, 1);
357 if (sym.known_suffix)
358 known_suffix = this->path + (sym.known_suffix - path_copy);
359 else if (sym.ext_here && !(opt & PC_SYM_CONTENTS))
361 known_suffix = strchr (this->path, '\0');
362 strcpy (known_suffix, sym.ext_here);
366 DWORD serial, volflags;
368 strcpy (tmp_buf, full_path);
369 if (!rootdir (tmp_buf) ||
370 !GetVolumeInformation (tmp_buf, NULL, 0, &serial, NULL, &volflags, NULL, 0))
372 debug_printf ("GetVolumeInformation(%s) = ERR, full_path(%s), set_has_acls(FALSE)",
373 tmp_buf, full_path, GetLastError ());
374 set_has_acls (FALSE);
378 debug_printf ("GetVolumeInformation(%s) = OK, full_path(%s), set_has_acls(%d)",
379 tmp_buf, full_path, volflags & FS_PERSISTENT_ACLS);
380 set_has_acls (volflags & FS_PERSISTENT_ACLS);
384 #define deveq(s) (strcasematch (name, (s)))
385 #define deveqn(s, n) (strncasematch (name, (s), (n)))
388 digits (const char *name)
391 int n = strtol(name, &p, 10);
393 return p > name && !*p ? n : -1;
396 const char *windows_device_names[] =
423 get_raw_device_number (const char *uxname, const char *w32path, int &unit)
427 if (strncasematch (w32path, "\\\\.\\tape", 8))
430 unit = digits (w32path + 8);
431 // norewind tape devices have leading n in name
432 if (strncasematch (uxname, "/dev/n", 6))
435 else if (isdrive (w32path + 4))
438 unit = tolower (w32path[4]) - 'a';
440 else if (strncasematch (w32path, "\\\\.\\physicaldrive", 17))
443 unit = digits (w32path + 17) + 128;
449 get_device_number (const char *name, int &unit, BOOL from_conv)
454 if ((*name == '/' && deveqn ("/dev/", 5)) ||
455 (*name == '\\' && deveqn ("\\dev\\", 5)))
460 if (tty_attached (myself))
465 else if (myself->ctty > 0)
468 else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
470 else if (deveq ("ttym"))
472 else if (deveq ("ptmx"))
474 else if (deveq ("windows"))
476 else if (deveq ("conin"))
478 else if (deveq ("conout"))
480 else if (deveq ("null"))
482 else if (deveq ("zero"))
484 else if (deveq ("random") || deveq ("urandom"))
487 unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
489 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
491 else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew"))
493 else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket")
494 || deveq ("dgsocket"))
496 else if (! from_conv)
497 devn = get_raw_device_number (name - 5,
499 PC_SYM_IGNORE).get_win32 (),
502 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
508 /* Return TRUE if src_path is a Win32 device name, filling out the device
509 name in win32_path */
512 win32_device_name (const char *src_path, char *win32_path,
513 DWORD &devn, int &unit)
517 devn = get_device_number (src_path, unit, TRUE);
522 if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL)
524 if (devn == FH_RANDOM)
525 __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
527 __small_sprintf (win32_path, devfmt, unit);
531 /* Normalize a POSIX path.
532 \'s are converted to /'s in the process.
533 All duplicate /'s, except for 2 leading /'s, are deleted.
534 The result is 0 for success, or an errno error value. */
536 #define isslash(c) ((c) == '/')
539 normalize_posix_path (const char *src, char *dst)
541 const char *src_start = src;
542 char *dst_start = dst;
544 syscall_printf ("src %s", src);
545 if (isdrive (src) || strpbrk (src, "\\:"))
547 cygwin_conv_to_full_posix_path (src, dst);
550 if (!isslash (src[0]))
553 if (!cygcwd.get (cwd))
555 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
557 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
561 dst = strchr (dst, '\0');
564 if (dst > dst_start && !isslash (dst[-1]))
567 /* Two leading /'s? If so, preserve them. */
568 else if (isslash (src[1]))
572 debug_printf ("ENOENT = normalize_posix_path (%s)", src);
579 { /* Starts with three or more slashes - reset. */
585 /* Exactly one leading slash. Absolute path. Check for chroot. */
586 else if (myself->rootlen)
588 strcpy (dst, myself->root);
589 dst += myself->rootlen;
594 /* Strip runs of /'s. */
612 if (dst == dst_start)
616 if (!isslash (src[1]))
619 else if (src[2] && !isslash (src[2]))
623 if (!ischrootpath (dst_start) ||
624 dst - dst_start != (int) myself->rootlen)
625 while (dst > dst_start && !isslash (*--dst))
637 if (--dst > dst_start && isslash (*dst))
640 debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start);
644 /* Normalize a Win32 path.
645 /'s are converted to \'s in the process.
646 All duplicate \'s, except for 2 leading \'s, are deleted.
648 The result is 0 for success, or an errno error value.
649 FIXME: A lot of this should be mergeable with the POSIX critter. */
651 normalize_win32_path (const char *src, char *dst)
653 const char *src_start = src;
654 char *dst_start = dst;
655 char *dst_root_start = dst;
657 if (!SLASH_P (src[0]) && strchr (src, ':') == NULL)
660 if (!cygcwd.get (cwd, 0))
662 if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
664 debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
669 if (!*cwd || !SLASH_P (dst[-1]))
672 /* Two leading \'s? If so, preserve them. */
673 else if (SLASH_P (src[0]) && SLASH_P (src[1]))
677 debug_printf ("ENOENT = normalize_win32_path (%s)", src);
683 /* If absolute path, care for chroot. */
684 else if (SLASH_P (src[0]) && !SLASH_P (src[1]) && myself->rootlen)
686 strcpy (dst, myself->root);
688 while ((c = strchr (dst, '/')) != NULL)
690 dst += myself->rootlen;
691 dst_root_start = dst;
697 /* Strip duplicate /'s. */
698 if (SLASH_P (src[0]) && SLASH_P (src[1]))
701 else if (src[0] == '.' && SLASH_P (src[1])
702 && (src == src_start || SLASH_P (src[-1])))
707 /* Backup if "..". */
708 else if (src[0] == '.' && src[1] == '.'
709 /* dst must be greater than dst_start */
711 && (SLASH_P (src[2]) || src[2] == 0))
713 /* Back up over /, but not if it's the first one. */
714 if (dst > dst_root_start + 1)
716 /* Now back up to the next /. */
717 while (dst > dst_root_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
723 /* Otherwise, add char to result. */
734 debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
739 /* Various utilities. */
741 /* slashify: Convert all back slashes in src path to forward slashes
742 in dst path. Add a trailing slash to dst when trailing_slash_p arg
746 slashify (const char *src, char *dst, int trailing_slash_p)
748 const char *start = src;
760 && !isdirsep (src[-1]))
765 /* backslashify: Convert all forward slashes in src path to back slashes
766 in dst path. Add a trailing slash to dst when trailing_slash_p arg
770 backslashify (const char *src, char *dst, int trailing_slash_p)
772 const char *start = src;
784 && !isdirsep (src[-1]))
789 /* nofinalslash: Remove trailing / and \ from SRC (except for the
790 first one). It is ok for src == dst. */
793 nofinalslash (const char *src, char *dst)
795 int len = strlen (src);
797 memcpy (dst, src, len + 1);
798 while (len > 1 && SLASH_P (dst[--len]))
802 /* slash_drive_prefix_p: Return non-zero if PATH begins with
806 slash_drive_prefix_p (const char *path)
808 return (isdirsep(path[0])
811 && (path[3] == 0 || path[3] == '/'));
814 /* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
817 slash_unc_prefix_p (const char *path)
820 int ret = (isdirsep (path[0])
821 && isdirsep (path[1])
824 && !isdirsep (path[3])
825 && ((p = strchr(&path[3], '/')) != NULL));
826 if (!ret || p == NULL)
828 return ret && isalnum (p[1]);
831 /* conv_path_list: Convert a list of path names to/from Win32/POSIX.
833 SRC is not a const char * because we temporarily modify it to ease
836 I believe Win32 always has '.' in $PATH. POSIX obviously doesn't.
837 We certainly don't want to handle that here, but it is something for
838 the caller to think about. */
841 conv_path_list (const char *src, char *dst, int to_posix_p)
845 char src_delim = to_posix_p ? ';' : ':';
846 char dst_delim = to_posix_p ? ':' : ';';
847 int (*conv_fn) (const char *, char *) = (to_posix_p
848 ? cygwin_conv_to_posix_path
849 : cygwin_conv_to_win32_path);
853 s = strchr (src, src_delim);
857 (*conv_fn) (src[0] != 0 ? src : ".", d);
866 (*conv_fn) (src[0] != 0 ? src : ".", d);
872 /************************* mount_info class ****************************/
874 /* init: Initialize the mount table. */
880 had_to_create_mount_areas = 0;
882 /* Fetch the mount table and cygdrive-related information from
887 /* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
888 the result in win32_path.
890 If win32_path != NULL, the relative path, if possible to keep, is
891 stored in win32_path. If the relative path isn't possible to keep,
892 the full path is stored.
894 If full_win32_path != NULL, the full path is stored there.
896 The result is zero for success, or an errno value.
898 {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */
901 mount_info::conv_to_win32_path (const char *src_path, char *win32_path,
902 char *full_win32_path, DWORD &devn, int &unit,
905 int src_path_len = strlen (src_path);
906 int trailing_slash_p = (src_path_len > 1
907 && SLASH_P (src_path[src_path_len - 1]));
910 unsigned dummy_flags;
916 flags = &dummy_flags;
919 debug_printf ("conv_to_win32_path (%s)", src_path);
921 if (src_path_len >= MAX_PATH)
923 debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path);
929 mount_item *mi = NULL; /* initialized to avoid compiler warning */
930 char pathbuf[MAX_PATH];
932 /* Determine where the destination should be placed. */
933 if (full_win32_path != NULL)
934 dst = full_win32_path;
935 else if (win32_path != NULL)
939 goto out; /* Sanity check. */
941 /* An MS-DOS spec has either a : or a \. If this is found, short
942 circuit most of the rest of this function. */
943 if (strpbrk (src_path, ":\\") != NULL)
945 debug_printf ("%s already win32", src_path);
946 rc = normalize_win32_path (src_path, dst);
949 debug_printf ("normalize_win32_path failed, rc %d", rc);
952 isrelpath = !isabspath (src_path);
953 *flags = set_flags_from_win32_path (dst);
954 if (myself->rootlen && dst[0] && dst[1] == ':')
956 char posix_path[MAX_PATH + 1];
958 rc = cygwin_shared->mount.conv_to_posix_path (dst, posix_path, 0);
961 debug_printf ("conv_to_posix_path failed, rc %d", rc);
964 if (!ischrootpath (posix_path))
966 debug_printf ("ischrootpath failed");
973 /* Normalize the path, taking out ../../ stuff, we need to do this
974 so that we can move from one mounted directory to another with relative
977 eg mounting c:/foo /foo
983 should look in c:/foo, not d:/foo.
985 We do this by first getting an absolute UNIX-style path and then
986 converting it to a DOS-style path, looking up the appropriate drive
987 in the mount table. */
989 rc = normalize_posix_path (src_path, pathbuf);
993 debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
998 isrelpath = !isslash (*src_path);
1000 /* See if this is a cygwin "device" */
1001 if (win32_device_name (pathbuf, dst, devn, unit))
1003 *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */
1007 /* Check if the cygdrive prefix was specified. If so, just strip
1008 off the prefix and transform it into an MS-DOS path. */
1010 if (iscygdrive_device (pathbuf))
1012 if (!cygdrive_win32_path (pathbuf, dst, trailing_slash_p))
1014 *flags = cygdrive_flags;
1018 /* Check the mount table for prefix matches. */
1019 for (i = 0; i < nmounts; i++)
1021 mi = mount + posix_sorted[i];
1022 if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen))
1028 if (slash_drive_prefix_p (pathbuf))
1029 slash_drive_to_win32_path (pathbuf, dst, trailing_slash_p);
1031 backslashify (pathbuf, dst, trailing_slash_p); /* just convert */
1036 int n = mi->native_pathlen;
1037 memcpy (dst, mi->native_path, n + 1);
1038 char *p = pathbuf + mi->posix_pathlen;
1039 if (!trailing_slash_p && !*p)
1041 if (isdrive (dst) && !dst[2])
1047 /* Do not add trailing \ to UNC device names like \\.\a: */
1048 if (*p != '/' && /* FIXME: this test seems wrong. */
1049 (strncmp (mi->native_path, "\\\\.\\", 4) != 0 ||
1050 strncmp (mi->native_path + 4, "UNC\\", 4) == 0))
1052 strcpy (dst + n, p);
1054 backslashify (dst, dst, trailing_slash_p);
1059 /* Compute relative path if asked to and able to. */
1060 if (win32_path == NULL)
1061 /* nothing to do */;
1064 char cwd_win32[MAX_PATH];
1065 if (!cygcwd.get (cwd_win32, 0))
1066 return get_errno ();
1067 unsigned cwdlen = strlen (cwd_win32);
1068 if (!path_prefix_p (cwd_win32, dst, cwdlen))
1069 strcpy (win32_path, dst);
1072 size_t n = strlen (dst);
1074 strcpy (win32_path, dst);
1080 dst += isdirsep (cwd_win32[cwdlen - 1]) ? cwdlen : cwdlen + 1;
1082 memmove (win32_path, dst, strlen (dst) + 1);
1085 strcpy (win32_path, ".");
1086 if (trailing_slash_p)
1087 strcat (win32_path, "\\");
1092 else if (win32_path != dst)
1093 strcpy (win32_path, dst);
1097 debug_printf ("%s(rel), %s(abs) %p(flags) = conv_to_win32_path (%s)",
1098 win32_path, full_win32_path, *flags,
1103 /* Convert PATH (for which slash_drive_prefix_p returns 1) to WIN32 form. */
1106 mount_info::slash_drive_to_win32_path (const char *path, char *buf,
1107 int trailing_slash_p)
1112 strcpy (buf + 2, "\\");
1114 backslashify (path + 3, buf + 2, trailing_slash_p);
1117 /* cygdrive_posix_path: Build POSIX path used as the
1118 mount point for cygdrives created when there is no other way to
1119 obtain a POSIX path from a Win32 one. */
1122 mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
1124 int len = cygdrive_len;
1126 memcpy (dst, cygdrive, len + 1);
1128 /* Now finish the path off with the drive letter to be used.
1129 The cygdrive prefix always ends with a trailing slash so
1130 the drive letter is added after the path. */
1131 dst[len++] = tolower (src[0]);
1132 if (!src[2] || (SLASH_P (src[2]) && !src[3]))
1133 dst[len++] = '\000';
1137 strcpy (dst + len, src + 3);
1139 slashify (dst, dst, trailing_slash_p);
1143 mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
1145 const char *p = src + cygdrive_len;
1146 if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
1150 strcpy (dst + 2, p + 1);
1151 backslashify (dst, dst, trailing_slash_p || !dst[2]);
1152 debug_printf ("src '%s', dst '%s'", src, dst);
1156 /* conv_to_posix_path: Ensure src_path is a POSIX path.
1158 The result is zero for success, or an errno value.
1159 posix_path must have sufficient space (i.e. MAX_PATH bytes).
1160 If keep_rel_p is non-zero, relative paths stay that way. */
1163 mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
1166 int src_path_len = strlen (src_path);
1167 int relative_path_p = !isabspath (src_path);
1168 int trailing_slash_p;
1170 if (src_path_len <= 1)
1171 trailing_slash_p = 0;
1174 const char *lastchar = src_path + src_path_len - 1;
1175 trailing_slash_p = SLASH_P (*lastchar) && lastchar[-1] != ':';
1178 debug_printf ("conv_to_posix_path (%s, %s, %s)", src_path,
1179 keep_rel_p ? "keep-rel" : "no-keep-rel",
1180 trailing_slash_p ? "add-slash" : "no-add-slash");
1183 if (src_path_len >= MAX_PATH)
1185 debug_printf ("ENAMETOOLONG");
1186 return ENAMETOOLONG;
1189 /* FIXME: For now, if the path is relative and it's supposed to stay
1190 that way, skip mount table processing. */
1192 if (keep_rel_p && relative_path_p)
1194 slashify (src_path, posix_path, 0);
1195 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1199 char pathbuf[MAX_PATH];
1200 int rc = normalize_win32_path (src_path, pathbuf);
1203 debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1207 int pathbuflen = strlen (pathbuf);
1208 for (int i = 0; i < nmounts; ++i)
1210 mount_item &mi = mount[native_sorted[i]];
1211 if (! path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1214 /* SRC_PATH is in the mount table. */
1216 const char *p = pathbuf + mi.native_pathlen;
1220 else if (isdirsep (*p))
1225 int addslash = nextchar > 0 ? 1 : 0;
1226 if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH)
1227 return ENAMETOOLONG;
1228 strcpy (posix_path, mi.posix_path);
1230 strcat (posix_path, "/");
1233 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
1238 /* Not in the database. This should [theoretically] only happen if either
1239 the path begins with //, or / isn't mounted, or the path has a drive
1240 letter not covered by the mount table. If it's a relative path then the
1241 caller must want an absolute path (otherwise we would have returned
1242 above). So we always return an absolute path at this point. */
1243 if (isdrive (pathbuf))
1244 cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p);
1247 /* The use of src_path and not pathbuf here is intentional.
1248 We couldn't translate the path, so just ensure no \'s are present. */
1249 slashify (src_path, posix_path, trailing_slash_p);
1253 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1258 /* Return flags associated with a mount point given the win32 path. */
1261 mount_info::set_flags_from_win32_path (const char *p)
1263 for (int i = 0; i < nmounts; i++)
1265 mount_item &mi = mount[native_sorted[i]];
1266 if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
1272 /* read_mounts: Given a specific regkey, read mounts from under its
1276 mount_info::read_mounts (reg_key& r)
1278 char posix_path[MAX_PATH];
1279 HKEY key = r.get_key ();
1280 DWORD i, posix_path_size;
1283 /* Loop through subkeys */
1284 /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
1285 shared area is currently statically allocated so we can't have an
1286 arbitrarily large number of mounts. */
1289 char native_path[MAX_PATH];
1292 posix_path_size = MAX_PATH;
1293 /* FIXME: if maximum posix_path_size is 256, we're going to
1294 run into problems if we ever try to store a mount point that's
1295 over 256 but is under MAX_PATH! */
1296 res = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1299 if (res == ERROR_NO_MORE_ITEMS)
1301 else if (res != ERROR_SUCCESS)
1303 debug_printf ("RegEnumKeyEx failed, error %d!\n", res);
1307 /* Get a reg_key based on i. */
1308 reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1310 /* Fetch info from the subkey. */
1311 subkey.get_string ("native", native_path, sizeof (native_path), "");
1312 mount_flags = subkey.get_int ("flags", 0);
1314 /* Add mount_item corresponding to registry mount point. */
1315 res = cygwin_shared->mount.add_item (native_path, posix_path, mount_flags, FALSE);
1316 if (res && get_errno () == EMFILE)
1317 break; /* The number of entries exceeds MAX_MOUNTS */
1321 /* from_registry: Build the entire mount table from the registry. Also,
1322 read in cygdrive-related information from its registry location. */
1325 mount_info::from_registry ()
1327 /* Use current mount areas if either user or system mount areas
1328 already exist. Otherwise, import old mounts. */
1332 /* Retrieve cygdrive-related information. */
1333 read_cygdrive_info_from_registry ();
1337 /* First read mounts from user's table. */
1340 /* Then read mounts from system-wide mount table. */
1341 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1342 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1343 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1344 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1348 /* If we had to create both user and system mount areas, import
1350 if (had_to_create_mount_areas == 2)
1351 import_v1_mounts ();
1354 /* add_reg_mount: Add mount item to registry. Return zero on success,
1355 non-zero on failure. */
1356 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1359 mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1363 /* Add the mount to the right registry location, depending on
1364 whether MOUNT_SYSTEM is set in the mount flags. */
1365 if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
1367 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1370 /* Start by deleting existing mount if one exists. */
1371 res = reg_user.kill (posix_path);
1372 if (res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND)
1375 /* Create the new mount. */
1376 reg_key subkey = reg_key (reg_user.get_key (),
1379 res = subkey.set_string ("native", native_path);
1380 if (res != ERROR_SUCCESS)
1382 res = subkey.set_int ("flags", mountflags);
1384 else /* local_machine mount */
1386 /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
1387 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1388 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1389 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1390 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1393 /* Start by deleting existing mount if one exists. */
1394 res = reg_sys.kill (posix_path);
1395 if (res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND)
1398 /* Create the new mount. */
1399 reg_key subkey = reg_key (reg_sys.get_key (),
1402 res = subkey.set_string ("native", native_path);
1403 if (res != ERROR_SUCCESS)
1405 res = subkey.set_int ("flags", mountflags);
1408 return 0; /* Success! */
1410 __seterrno_from_win_error (res);
1414 /* del_reg_mount: delete mount item from registry indicated in flags.
1415 Return zero on success, non-zero on failure.*/
1416 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1419 mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1423 if ((flags & MOUNT_SYSTEM) == 0) /* Delete from user registry */
1425 reg_key reg_user (KEY_ALL_ACCESS,
1426 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
1427 res = reg_user.kill (posix_path);
1429 else /* Delete from system registry */
1431 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1432 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1433 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1434 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1436 res = reg_sys.kill (posix_path);
1439 if (res != ERROR_SUCCESS)
1441 __seterrno_from_win_error (res);
1445 return 0; /* Success! */
1448 /* read_cygdrive_info_from_registry: Read the default prefix and flags
1449 to use when creating cygdrives from the special user registry
1450 location used to store cygdrive information. */
1453 mount_info::read_cygdrive_info_from_registry ()
1455 /* reg_key for user path prefix in HKEY_CURRENT_USER. */
1458 if (r.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1460 /* Didn't find the user path prefix so check the system path prefix. */
1462 /* reg_key for system path prefix in HKEY_LOCAL_MACHINE. */
1463 reg_key r2 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1464 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1465 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1466 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1469 if (r2.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1471 /* Didn't find either so write the default to the registry and use it.
1472 NOTE: We are writing and using the user path prefix. */
1473 write_cygdrive_info_to_registry ("/cygdrive", MOUNT_AUTO);
1477 /* Fetch system cygdrive_flags from registry; returns MOUNT_AUTO on
1479 cygdrive_flags = r2.get_int ("cygdrive flags", MOUNT_AUTO);
1480 slashify (cygdrive, cygdrive, 1);
1481 cygdrive_len = strlen(cygdrive);
1486 /* Fetch user cygdrive_flags from registry; returns MOUNT_AUTO on
1488 cygdrive_flags = r.get_int ("cygdrive flags", MOUNT_AUTO);
1489 slashify (cygdrive, cygdrive, 1);
1490 cygdrive_len = strlen(cygdrive);
1494 /* write_cygdrive_info_to_registry: Write the default prefix and flags
1495 to use when creating cygdrives to the special user registry
1496 location used to store cygdrive information. */
1499 mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1501 /* Determine whether to modify user or system cygdrive path prefix. */
1502 HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1504 /* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
1505 HKEY_LOCAL_MACHINE. */
1506 reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
1507 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1508 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1509 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1512 /* Verify cygdrive prefix starts with a forward slash and if there's
1513 another character, it's not a slash. */
1514 if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
1515 (!isslash (cygdrive_prefix[0])) ||
1516 ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
1522 char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1];
1523 /* Ensure that there is never a final slash */
1524 nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
1527 res = r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
1528 if (res != ERROR_SUCCESS)
1530 __seterrno_from_win_error (res);
1533 r.set_int ("cygdrive flags", flags);
1535 /* This also needs to go in the in-memory copy of "cygdrive", but only if
1537 1. setting user path prefix, or
1538 2. overwriting (a previous) system path prefix */
1539 if ((flags & MOUNT_SYSTEM) == 0 ||
1540 (cygwin_shared->mount.cygdrive_flags & MOUNT_SYSTEM) != 0)
1542 slashify (cygdrive_prefix, cygwin_shared->mount.cygdrive, 1);
1543 cygwin_shared->mount.cygdrive_flags = flags;
1544 cygwin_shared->mount.cygdrive_len = strlen(cygwin_shared->mount.cygdrive);
1551 mount_info::remove_cygdrive_info_from_registry (const char *cygdrive_prefix, unsigned flags)
1553 /* Determine whether to modify user or system cygdrive path prefix. */
1554 HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1556 /* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
1557 HKEY_LOCAL_MACHINE. */
1558 reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
1559 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1560 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1561 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1564 /* Delete cygdrive prefix and flags. */
1565 int res = r.killvalue ("cygdrive prefix");
1566 int res2 = r.killvalue ("cygdrive flags");
1568 /* Reinitialize the cygdrive path prefix to reflect to removal from the
1570 read_cygdrive_info_from_registry ();
1572 return (res != ERROR_SUCCESS) ? res : res2;
1576 mount_info::get_cygdrive_prefixes (char *user, char *system)
1578 /* Get the user path prefix from HKEY_CURRENT_USER. */
1580 int res = r.get_string ("cygdrive prefix", user, MAX_PATH, "");
1582 /* Get the system path prefix from HKEY_LOCAL_MACHINE. */
1583 reg_key r2 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1584 CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1585 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1586 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1588 int res2 = r2.get_string ("cygdrive prefix", system, MAX_PATH, "");
1590 return (res != ERROR_SUCCESS) ? res : res2;
1594 mount_info::getmntent (int x)
1596 if (x < 0 || x >= nmounts)
1599 return mount[native_sorted[x]].getmntent ();
1602 static mount_item *mounts_for_sort;
1604 /* sort_by_posix_name: qsort callback to sort the mount entries. Sort
1605 user mounts ahead of system mounts to the same POSIX path. */
1606 /* FIXME: should the user should be able to choose whether to
1607 prefer user or system mounts??? */
1609 sort_by_posix_name (const void *a, const void *b)
1611 mount_item *ap = mounts_for_sort + (*((int*) a));
1612 mount_item *bp = mounts_for_sort + (*((int*) b));
1614 /* Base weighting on longest posix path first so that the most
1615 obvious path will be chosen. */
1616 size_t alen = strlen (ap->posix_path);
1617 size_t blen = strlen (bp->posix_path);
1619 int res = blen - alen;
1622 return res; /* Path lengths differed */
1624 /* The two paths were the same length, so just determine normal
1625 lexical sorted order. */
1626 res = strcmp (ap->posix_path, bp->posix_path);
1630 /* need to select between user and system mount to same POSIX path */
1631 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1640 /* sort_by_native_name: qsort callback to sort the mount entries. Sort
1641 user mounts ahead of system mounts to the same POSIX path. */
1642 /* FIXME: should the user should be able to choose whether to
1643 prefer user or system mounts??? */
1645 sort_by_native_name (const void *a, const void *b)
1647 mount_item *ap = mounts_for_sort + (*((int*) a));
1648 mount_item *bp = mounts_for_sort + (*((int*) b));
1650 /* Base weighting on longest win32 path first so that the most
1651 obvious path will be chosen. */
1652 size_t alen = strlen (ap->native_path);
1653 size_t blen = strlen (bp->native_path);
1655 int res = blen - alen;
1658 return res; /* Path lengths differed */
1660 /* The two paths were the same length, so just determine normal
1661 lexical sorted order. */
1662 res = strcmp (ap->native_path, bp->native_path);
1666 /* need to select between user and system mount to same POSIX path */
1667 if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1679 for (int i = 0; i < nmounts; i++)
1680 native_sorted[i] = posix_sorted[i] = i;
1681 /* Sort them into reverse length order, otherwise we won't
1682 be able to look for /foo in /. */
1683 mounts_for_sort = mount; /* ouch. */
1684 qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
1685 qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
1688 /* Add an entry to the mount table.
1689 Returns 0 on success, -1 on failure and errno is set.
1691 This is where all argument validation is done. It may not make sense to
1692 do this when called internally, but it's cleaner to keep it all here. */
1695 mount_info::add_item (const char *native, const char *posix, unsigned mountflags, int reg_p)
1697 /* Something's wrong if either path is NULL or empty, or if it's
1698 not a UNC or absolute path. */
1700 if ((native == NULL) || (*native == 0) ||
1701 (posix == NULL) || (*posix == 0) ||
1702 !isabspath (native) || !isabspath (posix) ||
1703 slash_unc_prefix_p (posix) || isdrive (posix))
1709 /* Make sure both paths do not end in /. */
1710 char nativetmp[MAX_PATH];
1711 char posixtmp[MAX_PATH];
1713 if (slash_drive_prefix_p (native))
1714 slash_drive_to_win32_path (native, nativetmp, 0);
1716 backslashify (native, nativetmp, 0);
1717 nofinalslash (nativetmp, nativetmp);
1719 slashify (posix, posixtmp, 0);
1720 nofinalslash (posixtmp, posixtmp);
1722 debug_printf ("%s[%s], %s[%s], %p",
1723 native, nativetmp, posix, posixtmp, mountflags);
1725 /* Duplicate /'s in path are an error. */
1726 for (char *p = posixtmp + 1; *p; ++p)
1728 if (p[-1] == '/' && p[0] == '/')
1735 /* Write over an existing mount item with the same POSIX path if
1736 it exists and is from the same registry area. */
1738 for (i = 0; i < nmounts; i++)
1740 if (strcasematch (mount[i].posix_path, posixtmp) &&
1741 (mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM))
1745 if (i == nmounts && nmounts == MAX_MOUNTS)
1751 if (reg_p && add_reg_mount (nativetmp, posixtmp, mountflags))
1756 mount[i].init (nativetmp, posixtmp, mountflags);
1762 /* Delete a mount table entry where path is either a Win32 or POSIX
1763 path. Since the mount table is really just a table of aliases,
1764 deleting / is ok (although running without a slash mount is
1765 strongly discouraged because some programs may run erratically
1766 without one). If MOUNT_SYSTEM is set in flags, remove from system
1767 registry, otherwise remove the user registry mount.
1771 mount_info::del_item (const char *path, unsigned flags, int reg_p)
1773 char pathtmp[MAX_PATH];
1774 int posix_path_p = FALSE;
1776 /* Something's wrong if path is NULL or empty. */
1777 if (path == NULL || *path == 0 || !isabspath (path))
1783 if (slash_drive_prefix_p (path))
1784 slash_drive_to_win32_path (path, pathtmp, 0);
1785 else if (slash_unc_prefix_p (path) || strpbrk (path, ":\\"))
1786 backslashify (path, pathtmp, 0);
1789 slashify (path, pathtmp, 0);
1790 posix_path_p = TRUE;
1792 nofinalslash (pathtmp, pathtmp);
1794 if (reg_p && posix_path_p &&
1795 del_reg_mount (pathtmp, flags) &&
1796 del_reg_mount (path, flags)) /* for old irregular entries */
1799 for (int i = 0; i < nmounts; i++)
1801 int ent = native_sorted[i]; /* in the same order as getmntent() */
1803 ? strcasematch (mount[ent].posix_path, pathtmp)
1804 : strcasematch (mount[ent].native_path, pathtmp)) &&
1805 (mount[ent].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM))
1807 if (!posix_path_p &&
1808 reg_p && del_reg_mount (mount[ent].posix_path, flags))
1811 nmounts--; /* One less mount table entry */
1812 /* Fill in the hole if not at the end of the table */
1814 memmove (mount + ent, mount + ent + 1,
1815 sizeof (mount[ent]) * (nmounts - ent));
1816 sort (); /* Resort the table */
1824 /* read_v1_mounts: Given a reg_key to an old mount table registry area,
1825 read in the mounts. The "which" arg contains zero if we're reading
1826 the user area and MOUNT_SYSTEM if we're reading the system area.
1827 This way we can store the mounts read in the appropriate place when
1828 they are written back to the new registry layout. */
1831 mount_info::read_v1_mounts (reg_key r, unsigned which)
1833 unsigned mountflags = 0;
1835 /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
1836 for (int i = 0; i < 30; i++)
1839 char win32path[MAX_PATH];
1840 char unixpath[MAX_PATH];
1842 __small_sprintf (key_name, "%02x", i);
1844 reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
1846 /* The registry names are historical but useful so are left alone. */
1847 k.get_string ("native", win32path, sizeof (win32path), "");
1848 k.get_string ("unix", unixpath, sizeof (unixpath), "");
1850 /* Does this entry contain something? */
1851 if (*win32path != 0)
1855 if (k.get_int ("fbinary", 0))
1856 mountflags |= MOUNT_BINARY;
1858 /* Or in zero or MOUNT_SYSTEM depending on which table
1860 mountflags |= which;
1862 int res = cygwin_shared->mount.add_item (win32path, unixpath, mountflags, TRUE);
1863 if (res && get_errno () == EMFILE)
1864 break; /* The number of entries exceeds MAX_MOUNTS */
1869 /* import_v1_mounts: If v1 mounts are present, load them and write
1870 the new entries to the new registry area. */
1873 mount_info::import_v1_mounts ()
1875 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
1885 /* First read mounts from user's table. */
1886 read_v1_mounts (r, 0);
1888 /* Then read mounts from system-wide mount table. */
1889 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
1896 read_v1_mounts (r1, MOUNT_SYSTEM);
1899 /************************* mount_item class ****************************/
1902 mount_item::getmntent ()
1905 struct mntent &ret=_reent_winsup()->_ret;
1907 static NO_COPY struct mntent ret;
1910 /* Pass back pointers to mount_info strings reserved for use by
1911 getmntent rather than pointers to strings in the internal mount
1912 table because the mount table might change, causing weird effects
1913 from the getmntent user's point of view. */
1915 strcpy (cygwin_shared->mount.mnt_fsname, native_path);
1916 ret.mnt_fsname = cygwin_shared->mount.mnt_fsname;
1917 strcpy (cygwin_shared->mount.mnt_dir, posix_path);
1918 ret.mnt_dir = cygwin_shared->mount.mnt_dir;
1920 if (!(flags & MOUNT_SYSTEM)) /* user mount */
1921 strcpy (cygwin_shared->mount.mnt_type, (char *) "user");
1922 else /* system mount */
1923 strcpy (cygwin_shared->mount.mnt_type, (char *) "system");
1925 if ((flags & MOUNT_AUTO)) /* cygdrive */
1926 strcat (cygwin_shared->mount.mnt_type, (char *) ",auto");
1928 ret.mnt_type = cygwin_shared->mount.mnt_type;
1930 /* mnt_opts is a string that details mount params such as
1931 binary or textmode, or exec. We don't print
1932 `silent' here; it's a magic internal thing. */
1934 if (! (flags & MOUNT_BINARY))
1935 strcpy (cygwin_shared->mount.mnt_opts, (char *) "textmode");
1937 strcpy (cygwin_shared->mount.mnt_opts, (char *) "binmode");
1939 if (flags & MOUNT_CYGWIN_EXEC)
1940 strcat (cygwin_shared->mount.mnt_opts, (char *) ",cygexec");
1941 else if (flags & MOUNT_EXEC)
1942 strcat (cygwin_shared->mount.mnt_opts, (char *) ",exec");
1945 ret.mnt_opts = cygwin_shared->mount.mnt_opts;
1952 /* Fill in the fields of a mount table entry. */
1955 mount_item::init (const char *native, const char *posix, unsigned mountflags)
1957 strcpy ((char *) native_path, native);
1958 strcpy ((char *) posix_path, posix);
1960 native_pathlen = strlen (native_path);
1961 posix_pathlen = strlen (posix_path);
1966 /********************** Mount System Calls **************************/
1968 /* Mount table system calls.
1969 Note that these are exported to the application. */
1971 /* mount: Add a mount to the mount table in memory and to the registry
1972 that will cause paths under win32_path to be translated to paths
1973 under posix_path. */
1977 mount (const char *win32_path, const char *posix_path, unsigned flags)
1981 if (flags & MOUNT_AUTO) /* normal mount */
1983 /* When flags include MOUNT_AUTO, take this to mean that
1984 we actually want to change the cygdrive prefix and flags
1985 without actually mounting anything. */
1986 res = cygwin_shared->mount.write_cygdrive_info_to_registry (posix_path, flags);
1990 res = cygwin_shared->mount.add_item (win32_path, posix_path, flags, TRUE);
1992 syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
1996 /* umount: The standard umount call only has a path parameter. Since
1997 it is not possible for this call to specify whether to remove the
1998 mount from the user or global mount registry table, assume the user
2003 umount (const char *path)
2005 return cygwin_umount (path, 0);
2008 /* cygwin_umount: This is like umount but takes an additional flags
2009 parameter that specifies whether to umount from the user or system-wide
2014 cygwin_umount (const char *path, unsigned flags)
2018 if (flags & MOUNT_AUTO)
2020 /* When flags include MOUNT_AUTO, take this to mean that we actually want
2021 to remove the cygdrive prefix and flags without actually unmounting
2023 res = cygwin_shared->mount.remove_cygdrive_info_from_registry (path, flags);
2027 res = cygwin_shared->mount.del_item (path, flags, TRUE);
2030 syscall_printf ("%d = cygwin_umount (%s, %d)", res, path, flags);
2035 #define iteration _reent_winsup()->_iteration
2037 static int iteration;
2042 setmntent (const char *filep, const char *)
2045 return (FILE *) filep;
2052 return cygwin_shared->mount.getmntent (iteration++);
2062 /********************** Symbolic Link Support **************************/
2064 /* Create a symlink from FROMPATH to TOPATH. */
2068 symlink (const char *topath, const char *frompath)
2073 path_conv win32_path (frompath, PC_SYM_NOFOLLOW);
2074 if (win32_path.error)
2076 set_errno (win32_path.error);
2080 syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
2087 if (strlen (topath) >= MAX_PATH)
2089 set_errno (ENAMETOOLONG);
2093 if (win32_path.is_device () ||
2094 win32_path.file_attributes () != (DWORD) -1)
2100 h = CreateFileA(win32_path.get_win32 (), GENERIC_WRITE, 0, &sec_none_nih,
2101 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
2102 if (h == INVALID_HANDLE_VALUE)
2106 char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10];
2108 __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
2109 DWORD len = strlen (buf) + 1;
2111 /* Note that the terminating nul is written. */
2113 if (!WriteFile (h, buf, len, &written, NULL) || written != len)
2117 DeleteFileA (win32_path.get_win32 ());
2122 set_file_attribute (win32_path.has_acls (),
2123 win32_path.get_win32 (),
2124 S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
2125 SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_SYSTEM);
2131 syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath);
2135 static __inline char *
2136 has_suffix (const char *path, const suffix_info *suffixes)
2138 char *ext = strrchr (path, '.');
2140 for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
2141 if (strcasematch (ext, ex->name))
2146 static __inline__ int
2147 next_suffix (char *ext_here, const suffix_info *&suffixes)
2152 while (suffixes && suffixes->name)
2153 if (!suffixes->addon)
2157 strcpy (ext_here, suffixes->name);
2164 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2166 If PATH is a symlink, put the value of the symlink--the file to
2167 which it points--into BUF. The value stored in BUF is not
2168 necessarily null terminated. BUFLEN is the length of BUF; only up
2169 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2170 which case nothing will be stored.
2172 Set *SYML if PATH is a symlink.
2174 Set *EXEC if PATH appears to be executable. This is an efficiency
2175 hack because we sometimes have to open the file anyhow. *EXEC will
2176 not be set for every executable file.
2178 Return -1 on error, 0 if PATH is not a symlink, or the length
2179 stored into BUF if PATH is a symlink. */
2182 symlink_info::check (const char *in_path, const suffix_info *suffixes)
2186 char extbuf[MAX_PATH + 5];
2188 const char *path = in_path;
2192 else if ((known_suffix = has_suffix (in_path, suffixes)) != NULL)
2199 path = strcpy (extbuf, in_path);
2200 ext_here = strchr (path, '\0');
2206 if (!(pflags & PATH_NEEDDIR))
2210 pflags &= ~PATH_NEEDDIR;
2215 if (!next_suffix (ext_here, suffixes))
2218 fileattr = GetFileAttributesA (path);
2219 if (fileattr == (DWORD) -1)
2221 /* The GetFileAttributesA call can fail for reasons that don't
2222 matter, so we just return 0. For example, getting the
2223 attributes of \\HOST will typically fail. */
2224 debug_printf ("GetFileAttributesA (%s) failed", path);
2225 error = geterrno_from_win_error (GetLastError (), EACCES);
2229 /* Windows allows path\. even when `path' isn't a directory.
2230 Detect this scenario and disallow it, since it is non-UNIX like.
2231 FIXME: This code actually checks for things like foo/ and foo/..
2232 even though those usages have already been (erroneously?) eaten
2233 by cygwin_shared->mount.conv_to_win32_path in path_conv::check. */
2235 char *p = strrchr (path, '\\');
2236 if (p && !(fileattr & FILE_ATTRIBUTE_DIRECTORY) &&
2237 (needdir || *++p == '\0' ||
2238 (*p == '.' && (*++p == '\0' || (*p == '.' && p[1] == '\0')))))
2240 debug_printf ("%s is a non-directory", path);
2242 goto file_not_symlink;
2245 /* A symlink will have the `system' file attribute. */
2246 /* Only files can be symlinks (which can be symlinks to directories). */
2247 if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))
2248 goto file_not_symlink;
2250 /* Open the file. */
2252 h = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
2253 FILE_ATTRIBUTE_NORMAL, 0);
2255 if (h == INVALID_HANDLE_VALUE)
2256 goto file_not_symlink;
2259 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2262 if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
2264 else if (got == sizeof (cookie_buf)
2265 && memcmp (cookie_buf, SYMLINK_COOKIE,
2266 sizeof (cookie_buf)) == 0)
2268 /* It's a symlink. */
2269 pflags = PATH_SYMLINK;
2271 res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2276 /* Versions prior to b16 stored several trailing
2277 NULs with the path (to fill the path out to 1024
2278 chars). Current versions only store one trailing
2279 NUL. The length returned is the path without
2280 *any* trailing NULs. We also have to handle (or
2281 at least not die from) corrupted paths. */
2282 if (memchr (contents, 0, got) != NULL)
2283 res = strlen (contents);
2288 else if (got == sizeof (cookie_buf)
2289 && memcmp (cookie_buf, SOCKET_COOKIE,
2290 sizeof (cookie_buf)) == 0)
2292 pflags |= PATH_SOCKET;
2293 goto close_and_return;
2297 /* Not a symlink, see if executable. */
2298 if (!(pflags & (PATH_EXEC | PATH_CYGWIN_EXEC)) && got >= 2 &&
2299 ((cookie_buf[0] == '#' && cookie_buf[1] == '!') ||
2300 (cookie_buf[0] == ':' && cookie_buf[1] == '\n')))
2301 pflags |= PATH_EXEC;
2304 goto file_not_symlink;
2316 syscall_printf ("not a symlink");
2320 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2321 res, path, contents, pflags);
2326 /* readlink system call */
2330 readlink (const char *path, char *buf, int buflen)
2332 extern suffix_info stat_suffixes[];
2336 set_errno (ENAMETOOLONG);
2340 path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2344 set_errno (pathbuf.error);
2345 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2349 if (!pathbuf.issymlink ())
2351 if (pathbuf.fileattr != (DWORD) -1)
2356 int len = min (buflen, (int) strlen (pathbuf.get_win32 ()));
2357 memcpy (buf, pathbuf.get_win32 (), len);
2359 /* errno set by symlink.check if error */
2363 /* Some programs rely on st_dev/st_ino being unique for each file.
2364 Hash the path name and hope for the best. The hash arg is not
2365 always initialized to zero since readdir needs to compute the
2366 dirent ino_t based on a combination of the hash of the directory
2367 done during the opendir call and the hash or the filename within
2368 the directory. FIXME: Not bullet-proof. */
2369 /* Cygwin internal */
2371 unsigned long __stdcall
2372 hash_path_name (unsigned long hash, const char *name)
2377 /* Perform some initial permutations on the pathname if this is
2381 /* Simplistic handling of drives. If there is a drive specified,
2382 make sure that the initial letter is upper case. If there is
2383 no \ after the ':' assume access through the root directory
2385 FIXME: Should really honor MS-Windows convention of using
2386 the environment to track current directory on various drives. */
2389 char *nn, *newname = (char *) alloca (strlen (name) + 2);
2390 nn = strncpy (newname, name, 2);
2392 *newname = toupper (*nn);
2405 /* Fill out the hashed path name with the current working directory if
2406 this is not an absolute path and there is no pre-specified hash value.
2407 Otherwise the inodes same will differ depending on whether a file is
2408 referenced with an absolute value or relatively. */
2412 hash = cygcwd.get_hash ();
2413 if (name[0] == '.' && name[1] == '\0')
2415 hash = hash_path_name (hash, "\\");
2420 /* Build up hash. Ignore single trailing slash or \a\b\ != \a\b or
2421 \a\b\. but allow a single \ if that's all there is. */
2424 hash += *name + (*name << 17);
2427 while (*++name != '\0' &&
2428 !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
2433 getcwd (char *buf, size_t ulen)
2436 char *usebuf, uselen;
2450 ulen = MAX_PATH + 1;
2453 usebuf = (char *) malloc (ulen);
2454 usebuf [ulen - 1] = '\0';
2457 res = cygcwd.get (usebuf, 1, 1, ulen);
2460 usebuf = (char *) realloc (usebuf, strlen (usebuf) + 1);
2461 else if (!res && buf == NULL)
2467 /* getwd: standards? */
2472 return getcwd (buf, MAX_PATH);
2475 /* chdir: POSIX 5.2.1.1 */
2478 chdir (const char *dir)
2480 syscall_printf ("dir %s", dir);
2481 path_conv path (dir, PC_FULL | PC_SYM_FOLLOW);
2485 set_errno (path.error);
2486 syscall_printf ("-1 = chdir (%s)", dir);
2490 /* Look for trailing path component consisting entirely of dots. This
2491 is needed only in case of chdir since Windows simply ignores count
2492 of dots > 2 here instead of returning an error code. Counts of dots
2493 <= 2 are already eliminated by normalize_posix_path. */
2494 const char *p = strrchr (dir, '/');
2500 size_t len = strlen (p);
2501 if (len > 2 && strspn (p, ".") == len)
2507 char *native_dir = path.get_win32 ();
2509 /* Check to see if path translates to something like C:.
2510 If it does, append a \ to the native directory specification to
2511 defeat the Windows 95 (i.e. MS-DOS) tendency of returning to
2512 the last directory visited on the given drive. */
2513 if (isdrive (native_dir) && !native_dir[2])
2515 native_dir[2] = '\\';
2516 native_dir[3] = '\0';
2518 int res = SetCurrentDirectoryA (native_dir) ? 0 : -1;
2522 cygcwd.set (path, dir);
2524 /* Note that we're accessing cwd.posix without a lock here. I didn't think
2525 it was worth locking just for strace. */
2526 syscall_printf ("%d = chdir() cygcwd.posix '%s' native '%s'", res,
2527 cygcwd.posix, native_dir);
2531 /******************** Exported Path Routines *********************/
2533 /* Cover functions to the path conversion routines.
2534 These are exported to the world as cygwin_foo by cygwin.din. */
2538 cygwin_conv_to_win32_path (const char *path, char *win32_path)
2540 path_conv p (path, PC_SYM_FOLLOW);
2543 set_errno (p.error);
2547 strcpy (win32_path, p.get_win32 ());
2553 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
2555 path_conv p (path, PC_SYM_FOLLOW | PC_FULL);
2558 set_errno (p.error);
2562 strcpy (win32_path, p.get_win32 ());
2566 /* This is exported to the world as cygwin_foo by cygwin.din. */
2570 cygwin_conv_to_posix_path (const char *path, char *posix_path)
2572 if (check_null_empty_path_errno (path))
2574 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 1);
2580 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
2582 if (check_null_empty_path_errno (path))
2584 cygwin_shared->mount.conv_to_posix_path (path, posix_path, 0);
2588 /* The realpath function is supported on some UNIX systems. */
2592 realpath (const char *path, char *resolved)
2596 path_conv real_path (path, PC_SYM_FOLLOW | PC_FULL);
2598 if (real_path.error)
2599 err = real_path.error;
2602 err = cygwin_shared->mount.conv_to_posix_path (real_path.get_win32 (), resolved, 0);
2607 /* FIXME: on error, we are supposed to put the name of the path
2608 component which could not be resolved into RESOLVED. */
2615 /* Return non-zero if path is a POSIX path list.
2616 This is exported to the world as cygwin_foo by cygwin.din.
2619 <sect1 id="add-func-cygwin-posix-path-list-p">
2620 <para>Rather than use a mode to say what the "proper" path list
2621 format is, we allow any, and give apps the tools they need to
2622 convert between the two. If a ';' is present in the path list it's
2623 a Win32 path list. Otherwise, if the first path begins with
2624 [letter]: (in which case it can be the only element since if it
2625 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
2626 it's a POSIX path list.</para>
2633 cygwin_posix_path_list_p (const char *path)
2635 int posix_p = ! (strchr (path, ';') || isdrive (path));
2639 /* These are used for apps that need to convert env vars like PATH back and
2640 forth. The conversion is a two step process. First, an upper bound on the
2641 size of the buffer needed is computed. Then the conversion is done. This
2642 allows the caller to use alloca if it wants. */
2645 conv_path_list_buf_size (const char *path_list, int to_posix_p)
2647 int i, num_elms, max_mount_path_len, size;
2650 /* The theory is that an upper bound is
2651 current_size + (num_elms * max_mount_path_len) */
2653 char delim = to_posix_p ? ';' : ':';
2655 for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms)
2658 /* 7: strlen ("//c") + slop, a conservative initial value */
2659 for (max_mount_path_len = 7, i = 0; i < cygwin_shared->mount.nmounts; ++i)
2661 int mount_len = (to_posix_p
2662 ? cygwin_shared->mount.mount[i].posix_pathlen
2663 : cygwin_shared->mount.mount[i].native_pathlen);
2664 if (max_mount_path_len < mount_len)
2665 max_mount_path_len = mount_len;
2669 size = strlen (path_list) + (num_elms * max_mount_path_len) + 100;
2675 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
2677 return conv_path_list_buf_size (path_list, 1);
2682 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
2684 return conv_path_list_buf_size (path_list, 0);
2689 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
2691 conv_path_list (win32, posix, 1);
2697 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
2699 conv_path_list (posix, win32, 0);
2703 /* cygwin_split_path: Split a path into directory and file name parts.
2704 Buffers DIR and FILE are assumed to be big enough.
2706 Examples (path -> `dir' / `file'):
2709 . -> `.' / `.' (FIXME: should this be `.' / `'?)
2710 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
2712 foo/bar -> `foo' / `bar'
2713 foo/bar/ -> `foo' / `bar'
2715 /foo/bar -> `/foo' / `bar'
2718 c:foo -> `c:/' / `foo'
2719 c:/foo -> `c:/' / `foo'
2724 cygwin_split_path (const char *path, char *dir, char *file)
2726 int dir_started_p = 0;
2728 /* Deal with drives.
2729 Remember that c:foo <==> c:/foo. */
2741 if (SLASH_P (*path))
2746 /* Determine if there are trailing slashes and "delete" them if present.
2747 We pretend as if they don't exist. */
2748 const char *end = path + strlen (path);
2749 /* path + 1: keep leading slash. */
2750 while (end > path + 1 && SLASH_P (end[-1]))
2753 /* At this point, END points to one beyond the last character
2754 (with trailing slashes "deleted"). */
2756 /* Point LAST_SLASH at the last slash (duh...). */
2757 const char *last_slash;
2758 for (last_slash = end - 1; last_slash >= path; --last_slash)
2759 if (SLASH_P (*last_slash))
2762 if (last_slash == path)
2767 else if (last_slash > path)
2769 memcpy (dir, path, last_slash - path);
2770 dir[last_slash - path] = 0;
2775 ; /* nothing to do */
2781 memcpy (file, last_slash + 1, end - last_slash - 1);
2782 file[end - last_slash - 1] = 0;
2785 /********************** String Helper Functions ************************/
2787 #define CHXOR ('a' ^ 'A')
2788 #define ch_case_eq(ch1, ch2) \
2791 !((x = ((unsigned char)ch1 ^ (unsigned char)ch2)) && \
2792 (x != CHXOR || !isalpha (ch1))); \
2795 /* Return TRUE if two strings match up to length n */
2797 strncasematch (const char *s1, const char *s2, size_t n)
2805 if (!ch_case_eq (*s1, *s2))
2809 return !n || *s2 == '\0';
2812 /* Return TRUE if two strings match */
2814 strcasematch (const char *s1, const char *s2)
2821 if (!ch_case_eq (*s1, *s2))
2829 strcasestr (const char *searchee, const char *lookfor)
2835 return (char *) searchee;
2843 if (lookfor[i] == 0)
2844 return (char *) searchee;
2846 if (!ch_case_eq (lookfor[i], searchee[i]))
2857 check_null_empty_path (const char *name)
2859 MEMORY_BASIC_INFORMATION m;
2860 if (!name || !VirtualQuery (name, &m, sizeof (m)) || (m.State != MEM_COMMIT))
2869 /* Return the hash value for the current win32 value.
2870 This is used when constructing inodes. */
2872 cwdstuff::get_hash ()
2881 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
2885 lock = new_muto (FALSE, "cwd");
2888 /* Called to fill in cwd values after an exec. */
2890 cwdstuff::fixup_after_exec (char *win32_cwd, char *posix_cwd, DWORD hash_cwd)
2897 /* Get initial cwd. Should only be called once in a
2900 cwdstuff::get_initial ()
2908 for (i = 0, dlen = MAX_PATH, len = 0; i < 3; dlen *= 2, i++)
2910 win32 = (char *) crealloc (win32, dlen + 2);
2911 if ((len = GetCurrentDirectoryA (dlen, win32)) < dlen)
2919 debug_printf ("get_initial_cwd failed, %E");
2923 return 1; /* Leaves cwd lock unreleased */
2926 /* Fill out the elements of a cwdstuff struct.
2927 It is assumed that the lock for the cwd is acquired if
2928 win32_cwd == NULL. */
2930 cwdstuff::set (const char *win32_cwd, const char *posix_cwd)
2932 char pathbuf[MAX_PATH];
2937 win32 = (char *) crealloc (win32, strlen (win32_cwd) + 1);
2938 strcpy (win32, win32_cwd);
2942 cygwin_shared->mount.conv_to_posix_path (win32, pathbuf, 0);
2944 (void) normalize_posix_path (posix_cwd, pathbuf);
2946 posix = (char *) crealloc (posix, strlen (pathbuf) + 1);
2947 strcpy (posix, pathbuf);
2949 hash = hash_path_name (0, win32);
2957 /* Copy the value for either the posix or the win32 cwd into a buffer. */
2959 cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
2963 if (!get_initial ()) /* Get initial cwd and set cwd lock */
2970 tocopy = with_chroot && ischrootpath(posix) ?
2971 posix + myself->rootlen : posix;
2973 debug_printf("myself->root: %s, posix: %s", myself->root, posix);
2974 if (strlen (tocopy) >= ulen)
2981 strcpy (buf, tocopy);
2982 if (!buf[0]) /* Should only happen when chroot */
2987 syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d)",
2988 buf, buf, len, need_posix, with_chroot);
2992 /* Get copies of all cwdstuff elements. Used by spawn_guts. */
2994 cwdstuff::copy (char * &posix_cwd, char * &win32_cwd, DWORD hash_cwd)
2997 get_initial (); /* FIXME: Check return someday */
2998 posix_cwd = cstrdup (posix);
2999 win32_cwd = cstrdup (win32);