OSDN Git Service

* Makefile.in: Add cygheap.o.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / path.cc
1 /* path.cc: path support.
2
3    Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
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
15
16    Pathnames are handled as follows:
17
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).
24
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.
28
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
35    cygwin app,
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].
42
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>:
47
48    Text vs Binary issues are not considered here in path style
49    decisions.
50
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.
55
56    Apps wishing to translate to/from pure Win32 and POSIX-like
57    pathnames can use cygwin_foo.
58
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.
65
66    The semantics of mounting file systems is not intended to precisely
67    follow normal UNIX systems.
68
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
71    c: means c:\.
72 */
73
74 #include "winsup.h"
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <sys/mount.h>
78 #include <mntent.h>
79 #include <fcntl.h>
80 #include <unistd.h>
81 #include <errno.h>
82 #include <ctype.h>
83 #include <winioctl.h>
84 #include "cygerrno.h"
85 #include "fhandler.h"
86 #include "path.h"
87 #include "thread.h"
88 #include "sync.h"
89 #include "sigproc.h"
90 #include "pinfo.h"
91 #include "cygheap.h"
92
93 static int normalize_win32_path (const char *cwd, const char *src, char *dst);
94 static char *getcwd_inner (char *buf, size_t ulen, int posix_p, int with_chroot);
95 static void slashify (const char *src, char *dst, int trailing_slash_p);
96 static void backslashify (const char *src, char *dst, int trailing_slash_p);
97 static int path_prefix_p_ (const char *path1, const char *path2, int len1);
98 static int get_cwd_win32 ();
99
100 static NO_COPY const char escape_char = '^';
101
102 struct symlink_info
103 {
104   char buf[3 + MAX_PATH * 3];
105   char *known_suffix;
106   char *ext_here;
107   char *contents;
108   unsigned pflags;
109   DWORD fileattr;
110   int is_symlink;
111   int error;
112   symlink_info (): known_suffix (NULL), contents (buf + MAX_PATH + 1) {}
113   int check (const char *path, const suffix_info *suffixes);
114 };
115
116 /********************** Path Helper Functions *************************/
117
118 #define path_prefix_p(p1, p2, l1) \
119        ((tolower(*(p1))==tolower(*(p2))) && \
120        path_prefix_p_(p1, p2, l1))
121
122 #define SYMLINKATTR(x) \
123   (((x) & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) == \
124    FILE_ATTRIBUTE_SYSTEM)
125
126 /* Return non-zero if PATH1 is a prefix of PATH2.
127    Both are assumed to be of the same path style and / vs \ usage.
128    Neither may be "".
129    LEN1 = strlen (PATH1).  It's passed because often it's already known.
130
131    Examples:
132    /foo/ is a prefix of /foo  <-- may seem odd, but desired
133    /foo is a prefix of /foo/
134    / is a prefix of /foo/bar
135    / is not a prefix of foo/bar
136    foo/ is a prefix foo/bar
137    /foo is not a prefix of /foobar
138 */
139
140 /* Determine if path prefix matches current cygdrive */
141 #define iscygdrive(path) \
142   (path_prefix_p (cygwin_shared->mount.cygdrive, (path), cygwin_shared->mount.cygdrive_len))
143
144 #define iscygdrive_device(path) \
145   (iscygdrive(path) && isalpha(path[cygwin_shared->mount.cygdrive_len]) && \
146    (isdirsep(path[cygwin_shared->mount.cygdrive_len + 1]) || \
147     !path[cygwin_shared->mount.cygdrive_len + 1]))
148
149 /******************** Directory-related Support **************************/
150
151 /* Cache getcwd value.  FIXME: We need a lock for these in order to
152    support multiple threads.  */
153
154 #define TMPCWD  ((char *) alloca (MAX_PATH + 1))
155
156 struct cwdstuff
157 {
158   char *posix;
159   char *win32;
160   DWORD hash;
161   muto *lock;
162 };
163
164 cwdstuff cwd;
165
166 char * __stdcall
167 cwd_win32 (char *buf)
168 {
169   char *ret;
170   cwd.lock->acquire ();
171   if (cwd.win32 == NULL)
172     ret = NULL;
173   else if (buf == NULL)
174     ret = cwd.win32;
175   else
176     ret = strcpy (buf, cwd.win32);
177   cwd.lock->release ();
178   return ret;
179 }
180
181 char * __stdcall
182 cwd_posix (char *buf)
183 {
184   char *ret;
185   cwd.lock->acquire ();
186   if (cwd.posix == NULL)
187     ret = NULL;
188   else if (buf == NULL)
189     ret = cwd.posix;
190   else
191     ret = strcpy (buf, cwd.posix);
192   cwd.lock->release ();
193   return ret;
194 }
195
196 DWORD __stdcall
197 cwd_hash ()
198 {
199   DWORD hashnow;
200   cwd.lock->acquire ();
201   hashnow = cwd.hash;
202   cwd.lock->release ();
203   return hashnow;
204 }
205
206 void __stdcall
207 cwd_init ()
208 {
209   cwd.lock = new_muto (FALSE, "cwd");
210 }
211
212 void __stdcall
213 cwd_fixup_after_exec (char *win32, char *posix, DWORD hash)
214 {
215   cwd.win32 = win32;
216   cwd.posix = posix;
217   cwd.hash = hash;
218 }
219
220 #define ischrootpath(path) \
221         (myself->rootlen && \
222          strncasematch (myself->root, path, myself->rootlen) && \
223          (path[myself->rootlen] == '/' || path[myself->rootlen] == '\0'))
224
225 static int
226 path_prefix_p_ (const char *path1, const char *path2, int len1)
227 {
228   /* Handle case where PATH1 has trailing '/' and when it doesn't.  */
229   if (len1 > 0 && SLASH_P (path1[len1 - 1]))
230     len1--;
231
232   if (len1 == 0)
233     return SLASH_P (path2[0]) && !SLASH_P (path2[1]);
234
235   if (!strncasematch (path1, path2, len1))
236     return 0;
237
238   return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
239 }
240
241 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
242    passing to Win32 API routines.
243
244    If an error occurs, `error' is set to the errno value.
245    Otherwise it is set to 0.
246
247    follow_mode values:
248         SYMLINK_FOLLOW      - convert to PATH symlink points to
249         SYMLINK_NOFOLLOW    - convert to PATH of symlink itself
250         SYMLINK_IGNORE      - do not check PATH for symlinks
251         SYMLINK_CONTENTS    - just return symlink contents
252 */
253
254 void
255 path_conv::check (const char *src, unsigned opt,
256                   const suffix_info *suffixes)
257 {
258   /* This array is used when expanding symlinks.  It is MAX_PATH * 2
259      in length so that we can hold the expanded symlink plus a
260      trailer.  */
261   char path_buf[MAX_PATH];
262   char path_copy[MAX_PATH];
263   char tmp_buf[MAX_PATH];
264   symlink_info sym;
265
266   char *rel_path, *full_path;
267
268   if (!(opt & PC_NULLEMPTY))
269     error = 0;
270   else if ((error = check_null_empty_path (src)))
271     return;
272
273   if (opt & PC_FULL)
274     rel_path = path_buf, full_path = this->path;
275   else
276     rel_path = this->path, full_path = path_buf;
277
278   /* This loop handles symlink expansion.  */
279   int loop = 0;
280   path_flags = 0;
281   known_suffix = NULL;
282   fileattr = (DWORD) -1;
283   for (;;)
284     {
285       MALLOC_CHECK;
286       /* Must look up path in mount table, etc.  */
287       error = cygwin_shared->mount.conv_to_win32_path (src, rel_path,
288                                                        full_path,
289                                                        devn, unit, &path_flags);
290       MALLOC_CHECK;
291       if (error)
292         return;
293       if (devn != FH_BAD)
294         {
295           fileattr = 0;
296           return;
297         }
298
299       /* Eat trailing slashes */
300       char *tail = strchr (full_path, '\0');
301       /* If path is only a drivename, Windows interprets it as
302          the current working directory on this drive instead of
303          the root dir which is what we want. So we need
304          the trailing backslash in this case. */
305       while (tail > full_path + 3 && (*--tail == '\\'))
306         *tail = '\0';
307       if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
308         strcat (full_path, "\\");
309
310       if (opt & PC_SYM_IGNORE)
311         {
312           fileattr = GetFileAttributesA (path);
313           goto out;
314         }
315
316       /* Make a copy of the path that we can munge up */
317       strcpy (path_copy, full_path);
318
319       tail = path_copy + 1 + (tail - full_path);   // Point to end of copy
320
321       /* Scan path_copy from right to left looking either for a symlink
322          or an actual existing file.  If an existing file is found, just
323          return.  If a symlink is found exit the for loop.
324          Also: be careful to preserve the errno returned from
325          symlink.check as the caller may need it. */
326       /* FIXME: Do we have to worry about multiple \'s here? */
327       int component = 0;                // Number of translated components
328       sym.contents[0] = '\0';
329
330       for (;;)
331         {
332           const suffix_info *suff;
333
334           /* Don't allow symlink.check to set anything in the path_conv
335              class if we're working on an inner component of the path */
336           if (component)
337             {
338               suff = NULL;
339               sym.pflags = 0;
340             }
341           else
342             {
343               suff = suffixes;
344               sym.pflags = path_flags;
345             }
346
347           int len = sym.check (path_copy, suff);
348
349           if (!component)
350             path_flags = sym.pflags;
351
352           /* If symlink.check found an existing non-symlink file, then
353              it sets the appropriate flag.  It also sets any suffix found
354              into `ext_here'. */
355           if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
356             {
357               error = sym.error;
358               if (component == 0)
359                 {
360                   fileattr = sym.fileattr;
361                   goto fillin;
362                 }
363               goto out; // file found
364             }
365           /* Found a symlink if len > 0.  If component == 0, then the
366              src path itself was a symlink.  If !follow_mode then
367              we're done.  Otherwise we have to insert the path found
368              into the full path that we are building and perform all of
369              these operations again on the newly derived path. */
370           else if (len > 0)
371             {
372               if (component == 0 && !(opt & PC_SYM_FOLLOW))
373                 {
374                   set_symlink (); // last component of path is a symlink.
375                   fileattr = sym.fileattr;
376                   if (opt & PC_SYM_CONTENTS)
377                       strcpy (path, sym.contents);
378                   goto fillin;
379                 }
380               break;
381             }
382
383           /* No existing file found. */
384
385           if (!(tail = strrchr (path_copy, '\\')) ||
386               (tail > path_copy && tail[-1] == ':'))
387             goto out;   // all done
388
389           /* Haven't found a valid pathname component yet.
390              Pinch off the tail and try again. */
391           *tail = '\0';
392           component++;
393         }
394
395       /* Arrive here if above loop detected a symlink. */
396       if (++loop > MAX_LINK_DEPTH)
397         {
398           error = ELOOP;   // Eep.
399           return;
400         }
401       MALLOC_CHECK;
402
403       tail = full_path + (tail - path_copy);
404       int taillen = strlen (tail);
405       int buflen = strlen (sym.contents);
406       if (buflen + taillen > MAX_PATH)
407           {
408             error = ENAMETOOLONG;
409             strcpy (path, "::ENAMETOOLONG::");
410             return;
411           }
412
413       /* Copy tail of full_path to discovered symlink. */
414       char *p;
415       for (p = sym.contents + buflen; *tail; tail++)
416         *p++ = *tail == '\\' ? '/' : *tail;
417       *p = '\0';
418
419       /* If symlink referred to an absolute path, then we
420          just use sym.contents and loop.  Otherwise tack the head of
421          path_copy before sym.contents and translate it back from a
422          Win32-style path to a POSIX-style one. */
423       if (isabspath (sym.contents))
424         src = sym.contents;
425       else if (!(tail = strrchr (path_copy, '\\')))
426         system_printf ("problem parsing %s - '%s'", src, full_path);
427       else
428         {
429           int headlen = 1 + tail - path_copy;
430           p = sym.contents - headlen;
431           memcpy (p, path_copy, headlen);
432           MALLOC_CHECK;
433           error = cygwin_shared->mount.conv_to_posix_path (p, tmp_buf, 1);
434           MALLOC_CHECK;
435           if (error)
436             return;
437           src = tmp_buf;
438         }
439     }
440
441 fillin:
442   if (sym.known_suffix)
443     known_suffix = this->path + (sym.known_suffix - path_copy);
444   else if (sym.ext_here && !(opt & PC_SYM_CONTENTS))
445     {
446       known_suffix = strchr (this->path, '\0');
447       strcpy (known_suffix, sym.ext_here);
448     }
449
450 out:
451   DWORD serial, volflags;
452
453   strcpy (tmp_buf, full_path);
454   if (!rootdir (tmp_buf) ||
455       !GetVolumeInformation (tmp_buf, NULL, 0, &serial, NULL, &volflags, NULL, 0))
456     {
457       debug_printf ("GetVolumeInformation(%s) = ERR, full_path(%s), set_has_acls(FALSE)",
458                     tmp_buf, full_path, GetLastError ());
459       set_has_acls (FALSE);
460     }
461   else
462     {
463       debug_printf ("GetVolumeInformation(%s) = OK, full_path(%s), set_has_acls(%d)",
464                     tmp_buf, full_path, volflags & FS_PERSISTENT_ACLS);
465       set_has_acls (volflags & FS_PERSISTENT_ACLS);
466     }
467 }
468
469 #define deveq(s) (strcasematch (name, (s)))
470 #define deveqn(s, n) (strncasematch (name, (s), (n)))
471
472 static __inline int
473 digits (const char *name)
474 {
475   char *p;
476   int n = strtol(name, &p, 10);
477
478   return p > name && !*p ? n : -1;
479 }
480
481 const char *windows_device_names[] =
482 {
483   NULL,
484   "\\dev\\console",
485   "conin",
486   "conout",
487   "\\dev\\ttym",
488   "\\dev\\tty%d",
489   "\\dev\\ptym",
490   "\\\\.\\com%d",
491   "\\dev\\pipe",
492   "\\dev\\piper",
493   "\\dev\\pipew",
494   "\\dev\\socket",
495   "\\dev\\windows",
496
497   NULL, NULL, NULL,
498
499   "\\dev\\disk",
500   "\\dev\\fd%d",
501   "\\dev\\st%d",
502   "nul",
503   "\\dev\\zero",
504   "\\dev\\%srandom",
505 };
506
507 static int
508 get_raw_device_number (const char *uxname, const char *w32path, int &unit)
509 {
510   DWORD devn = FH_BAD;
511
512   if (strncasematch (w32path, "\\\\.\\tape", 8))
513     {
514       devn = FH_TAPE;
515       unit = digits (w32path + 8);
516       // norewind tape devices have leading n in name
517       if (strncasematch (uxname, "/dev/n", 6))
518         unit += 128;
519     }
520   else if (isdrive (w32path + 4))
521     {
522       devn = FH_FLOPPY;
523       unit = tolower (w32path[4]) - 'a';
524     }
525   else if (strncasematch (w32path, "\\\\.\\physicaldrive", 17))
526     {
527       devn = FH_FLOPPY;
528       unit = digits (w32path + 17) + 128;
529     }
530   return devn;
531 }
532
533 int __stdcall
534 get_device_number (const char *name, int &unit, BOOL from_conv)
535 {
536   DWORD devn = FH_BAD;
537   unit = 0;
538
539   if ((*name == '/' && deveqn ("/dev/", 5)) ||
540       (*name == '\\' && deveqn ("\\dev\\", 5)))
541     {
542       name += 5;
543       if (deveq ("tty"))
544         {
545           if (tty_attached (myself))
546             {
547               unit = myself->ctty;
548               devn = FH_TTYS;
549             }
550           else if (myself->ctty > 0)
551             devn = FH_CONSOLE;
552         }
553       else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
554         devn = FH_TTYS;
555       else if (deveq ("ttym"))
556         devn = FH_TTYM;
557       else if (deveq ("ptmx"))
558         devn = FH_PTYM;
559       else if (deveq ("windows"))
560         devn = FH_WINDOWS;
561       else if (deveq ("conin"))
562         devn = FH_CONIN;
563       else if (deveq ("conout"))
564         devn = FH_CONOUT;
565       else if (deveq ("null"))
566         devn = FH_NULL;
567       else if (deveq ("zero"))
568         devn = FH_ZERO;
569       else if (deveq ("random") || deveq ("urandom"))
570         {
571           devn = FH_RANDOM;
572           unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
573         }
574       else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
575         devn = FH_SERIAL;
576       else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew"))
577         devn = FH_PIPE;
578       else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket")
579                || deveq ("dgsocket"))
580         devn = FH_SOCKET;
581       else if (! from_conv)
582         devn = get_raw_device_number (name - 5,
583                                       path_conv (name - 5,
584                                                  PC_SYM_IGNORE).get_win32 (),
585                                       unit);
586     }
587   else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
588     devn = FH_SERIAL;
589
590   return devn;
591 }
592
593 /* Return TRUE if src_path is a Win32 device name, filling out the device
594    name in win32_path */
595
596 static BOOL
597 win32_device_name (const char *src_path, char *win32_path,
598                    DWORD &devn, int &unit)
599 {
600   const char *devfmt;
601
602   devn = get_device_number (src_path, unit, TRUE);
603
604   if (devn == FH_BAD)
605     return FALSE;
606
607   if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL)
608     return FALSE;
609   if (devn == FH_RANDOM)
610     __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
611   else
612     __small_sprintf (win32_path, devfmt, unit);
613   return TRUE;
614 }
615
616 /* Normalize a POSIX path.
617    \'s are converted to /'s in the process.
618    All duplicate /'s, except for 2 leading /'s, are deleted.
619    The result is 0 for success, or an errno error value.  */
620
621 #define isslash(c) ((c) == '/')
622
623 static int
624 normalize_posix_path (const char *cwd, const char *src, char *dst)
625 {
626   const char *src_start = src;
627   char *dst_start = dst;
628
629   syscall_printf ("cwd %s, src %s", cwd, src);
630   if (isdrive (src) || strpbrk (src, "\\:"))
631     {
632       cygwin_conv_to_full_posix_path (src, dst);
633       return 0;
634     }
635   if (!isslash (src[0]))
636     {
637       if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
638         {
639           debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
640           return ENAMETOOLONG;
641         }
642       strcpy (dst, cwd);
643       dst = strchr (dst, '\0');
644       if (*src == '.')
645         {
646           if (dst == dst_start + 1)
647             dst--;
648           goto sawdot;
649         }
650       if (dst > dst_start && !isslash (dst[-1]))
651         *dst++ = '/';
652     }
653   /* Two leading /'s?  If so, preserve them.  */
654   else if (isslash (src[1]))
655     {
656       if (myself->rootlen)
657         {
658           debug_printf ("ENOENT = normalize_posix_path (%s)", src);
659           return ENOENT;
660         }
661       *dst++ = '/';
662       *dst++ = '/';
663       src += 2;
664       if (isslash (*src))
665         { /* Starts with three or more slashes - reset. */
666           dst = dst_start;
667           *dst++ = '/';
668           src = src_start + 1;
669         }
670     }
671   /* Exactly one leading slash. Absolute path. Check for chroot. */
672   else if (myself->rootlen)
673     {
674       strcpy (dst, myself->root);
675       dst += myself->rootlen;
676     }
677
678   while (*src)
679     {
680       /* Strip runs of /'s.  */
681       if (!isslash (*src))
682         *dst++ = *src++;
683       else
684         {
685           while (*++src)
686             {
687               while (isslash (*src))
688                 src++;
689
690               if (*src != '.')
691                 break;
692
693             sawdot:
694               if (src[1] != '.')
695                 {
696                   if (!src[1] || !isslash (src[1]))
697                     break;
698                 }
699               else
700                 {
701                   if (src[2] && !isslash (src[2]))
702                     break;
703                   if (!ischrootpath (dst_start) ||
704                       dst - dst_start != (int) myself->rootlen)
705                     while (dst > dst_start && !isslash (*--dst))
706                       continue;
707                   src++;
708                 }
709             }
710
711           *dst++ = '/';
712         }
713     }
714
715   *dst = '\0';
716   if (--dst > dst_start && isslash (*dst))
717     *dst = '\0';
718
719   debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start);
720   return 0;
721 }
722
723 /* Normalize a Win32 path.
724    /'s are converted to \'s in the process.
725    All duplicate \'s, except for 2 leading \'s, are deleted.
726
727    The result is 0 for success, or an errno error value.
728    FIXME: A lot of this should be mergeable with the POSIX critter.  */
729 static int
730 normalize_win32_path (const char *cwd, const char *src, char *dst)
731 {
732   const char *src_start = src;
733   char *dst_start = dst;
734   char *dst_root_start = dst;
735
736   if (!SLASH_P (src[0]) && strchr (src, ':') == NULL)
737     {
738       if (strlen (cwd) + 1 + strlen (src) >= MAX_PATH)
739         {
740           debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
741           return ENAMETOOLONG;
742         }
743       strcpy (dst, cwd);
744       dst += strlen (dst);
745       if (!*cwd || !SLASH_P (dst[-1]))
746         *dst++ = '\\';
747     }
748   /* Two leading \'s?  If so, preserve them.  */
749   else if (SLASH_P (src[0]) && SLASH_P (src[1]))
750     {
751       if (myself->rootlen)
752         {
753           debug_printf ("ENOENT = normalize_win32_path (%s)", src);
754           return ENOENT;
755         }
756       *dst++ = '\\';
757       ++src;
758     }
759   /* If absolute path, care for chroot. */
760   else if (SLASH_P (src[0]) && !SLASH_P (src[1]) && myself->rootlen)
761     {
762       strcpy (dst, myself->root);
763       char *c;
764       while ((c = strchr (dst, '/')) != NULL)
765         *c = '\\';
766       dst += myself->rootlen;
767       dst_root_start = dst;
768       *dst++ = '\\';
769     }
770
771   while (*src)
772     {
773       /* Strip duplicate /'s.  */
774       if (SLASH_P (src[0]) && SLASH_P (src[1]))
775         src++;
776       /* Ignore "./".  */
777       else if (src[0] == '.' && SLASH_P (src[1])
778                && (src == src_start || SLASH_P (src[-1])))
779         {
780           src += 2;
781         }
782
783       /* Backup if "..".  */
784       else if (src[0] == '.' && src[1] == '.'
785                /* dst must be greater than dst_start */
786                && dst[-1] == '\\'
787                && (SLASH_P (src[2]) || src[2] == 0))
788         {
789           /* Back up over /, but not if it's the first one.  */
790           if (dst > dst_root_start + 1)
791             dst--;
792           /* Now back up to the next /.  */
793           while (dst > dst_root_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
794             dst--;
795           src += 2;
796           if (SLASH_P (*src))
797             src++;
798         }
799       /* Otherwise, add char to result.  */
800       else
801         {
802           if (*src == '/')
803             *dst++ = '\\';
804           else
805             *dst++ = *src;
806           ++src;
807         }
808     }
809   *dst = 0;
810   debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
811   return 0;
812 }
813 \f
814
815 /* Various utilities.  */
816
817 /* slashify: Convert all back slashes in src path to forward slashes
818    in dst path.  Add a trailing slash to dst when trailing_slash_p arg
819    is set to 1. */
820
821 static void
822 slashify (const char *src, char *dst, int trailing_slash_p)
823 {
824   const char *start = src;
825
826   while (*src)
827     {
828       if (*src == '\\')
829         *dst++ = '/';
830       else
831         *dst++ = *src;
832       ++src;
833     }
834   if (trailing_slash_p
835       && src > start
836       && !isdirsep (src[-1]))
837     *dst++ = '/';
838   *dst++ = 0;
839 }
840
841 /* backslashify: Convert all forward slashes in src path to back slashes
842    in dst path.  Add a trailing slash to dst when trailing_slash_p arg
843    is set to 1. */
844
845 static void
846 backslashify (const char *src, char *dst, int trailing_slash_p)
847 {
848   const char *start = src;
849
850   while (*src)
851     {
852       if (*src == '/')
853         *dst++ = '\\';
854       else
855         *dst++ = *src;
856       ++src;
857     }
858   if (trailing_slash_p
859       && src > start
860       && !isdirsep (src[-1]))
861     *dst++ = '\\';
862   *dst++ = 0;
863 }
864
865 /* nofinalslash: Remove trailing / and \ from SRC (except for the
866    first one).  It is ok for src == dst.  */
867
868 void __stdcall
869 nofinalslash (const char *src, char *dst)
870 {
871   int len = strlen (src);
872   if (src != dst)
873     memcpy (dst, src, len + 1);
874   while (len > 1 && SLASH_P (dst[--len]))
875     dst[len] = '\0';
876 }
877
878 /* slash_drive_prefix_p: Return non-zero if PATH begins with
879    //<letter>.  */
880
881 static int
882 slash_drive_prefix_p (const char *path)
883 {
884   return (isdirsep(path[0])
885           && isdirsep(path[1])
886           && isalpha (path[2])
887           && (path[3] == 0 || path[3] == '/'));
888 }
889
890 /* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
891
892 int __stdcall
893 slash_unc_prefix_p (const char *path)
894 {
895   char *p = NULL;
896   int ret = (isdirsep (path[0])
897              && isdirsep (path[1])
898              && isalpha (path[2])
899              && path[3] != 0
900              && !isdirsep (path[3])
901              && ((p = strchr(&path[3], '/')) != NULL));
902   if (!ret || p == NULL)
903     return ret;
904   return ret && isalnum (p[1]);
905 }
906
907 /* conv_path_list: Convert a list of path names to/from Win32/POSIX.
908
909    SRC is not a const char * because we temporarily modify it to ease
910    the implementation.
911
912    I believe Win32 always has '.' in $PATH.   POSIX obviously doesn't.
913    We certainly don't want to handle that here, but it is something for
914    the caller to think about.  */
915
916 static void
917 conv_path_list (const char *src, char *dst, int to_posix_p)
918 {
919   char *s;
920   char *d = dst;
921   char src_delim = to_posix_p ? ';' : ':';
922   char dst_delim = to_posix_p ? ':' : ';';
923   int (*conv_fn) (const char *, char *) = (to_posix_p
924                                            ? cygwin_conv_to_posix_path
925                                            : cygwin_conv_to_win32_path);
926
927   do
928     {
929       s = strchr (src, src_delim);
930       if (s)
931         {
932           *s = 0;
933           (*conv_fn) (src[0] != 0 ? src : ".", d);
934           d += strlen (d);
935           *d++ = dst_delim;
936           *s = src_delim;
937           src = s + 1;
938         }
939       else
940         {
941           /* Last one.  */
942           (*conv_fn) (src[0] != 0 ? src : ".", d);
943         }
944     }
945   while (s != NULL);
946 }
947
948 /************************* mount_info class ****************************/
949
950 /* init: Initialize the mount table.  */
951
952 void
953 mount_info::init ()
954 {
955   nmounts = 0;
956   had_to_create_mount_areas = 0;
957
958   /* Fetch the mount table and cygdrive-related information from
959      the registry.  */
960   from_registry ();
961 }
962
963 /* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
964    the result in win32_path.
965
966    If win32_path != NULL, the relative path, if possible to keep, is
967    stored in win32_path.  If the relative path isn't possible to keep,
968    the full path is stored.
969
970    If full_win32_path != NULL, the full path is stored there.
971
972    The result is zero for success, or an errno value.
973
974    {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes).  */
975
976 int
977 mount_info::conv_to_win32_path (const char *src_path, char *win32_path,
978                                 char *full_win32_path, DWORD &devn, int &unit,
979                                 unsigned *flags)
980 {
981   int src_path_len = strlen (src_path);
982   int trailing_slash_p = (src_path_len > 1
983                           && SLASH_P (src_path[src_path_len - 1]));
984   MALLOC_CHECK;
985   int isrelpath;
986   unsigned dummy_flags;
987
988   devn = FH_BAD;
989   unit = 0;
990
991   if (!flags)
992     flags = &dummy_flags;
993
994   *flags = 0;
995   debug_printf ("conv_to_win32_path (%s)", src_path);
996
997   if (src_path_len >= MAX_PATH)
998     {
999       debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path);
1000       return ENAMETOOLONG;
1001     }
1002
1003   int i, rc;
1004   char *dst = NULL;
1005   mount_item *mi = NULL;        /* initialized to avoid compiler warning */
1006   char pathbuf[MAX_PATH];
1007
1008   char cwd[MAX_PATH];
1009   getcwd_inner (cwd, MAX_PATH, TRUE, 0); /* FIXME: check rc */
1010
1011   /* Determine where the destination should be placed. */
1012   if (full_win32_path != NULL)
1013     dst = full_win32_path;
1014   else if (win32_path != NULL)
1015     dst = win32_path;
1016
1017   if (dst == NULL)
1018     goto out;           /* Sanity check. */
1019
1020   /* An MS-DOS spec has either a : or a \.  If this is found, short
1021      circuit most of the rest of this function. */
1022   if (strpbrk (src_path, ":\\") != NULL)
1023     {
1024       debug_printf ("%s already win32", src_path);
1025       rc = normalize_win32_path (cwd_win32 (TMPCWD), src_path, dst);
1026       if (rc)
1027         {
1028           debug_printf ("normalize_win32_path failed, rc %d", rc);
1029           return rc;
1030         }
1031       isrelpath = !isabspath (src_path);
1032       *flags = set_flags_from_win32_path (dst);
1033       if (myself->rootlen && dst[0] && dst[1] == ':')
1034         {
1035           char posix_path[MAX_PATH + 1];
1036
1037           rc = cygwin_shared->mount.conv_to_posix_path (dst, posix_path, 0);
1038           if (rc)
1039             {
1040               debug_printf ("conv_to_posix_path failed, rc %d", rc);
1041               return rc;
1042             }
1043           if (!ischrootpath (posix_path))
1044             {
1045               debug_printf ("ischrootpath failed");
1046               return ENOENT;
1047             }
1048         }
1049       goto fillin;
1050     }
1051
1052   /* Normalize the path, taking out ../../ stuff, we need to do this
1053      so that we can move from one mounted directory to another with relative
1054      stuff.
1055
1056      eg mounting c:/foo /foo
1057      d:/bar /bar
1058
1059      cd /bar
1060      ls ../foo
1061
1062      should look in c:/foo, not d:/foo.
1063
1064      We do this by first getting an absolute UNIX-style path and then
1065      converting it to a DOS-style path, looking up the appropriate drive
1066      in the mount table.  */
1067
1068   /* No need to fetch cwd if path is absolute.  */
1069   isrelpath = !isslash (*src_path);
1070
1071   rc = normalize_posix_path (cwd, src_path, pathbuf);
1072
1073   if (rc)
1074     {
1075       debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
1076       *flags = 0;
1077       return rc;
1078     }
1079
1080   /* See if this is a cygwin "device" */
1081   if (win32_device_name (pathbuf, dst, devn, unit))
1082     {
1083       *flags = MOUNT_BINARY;    /* FIXME: Is this a sensible default for devices? */
1084       goto fillin;
1085     }
1086
1087   /* Check if the cygdrive prefix was specified.  If so, just strip
1088      off the prefix and transform it into an MS-DOS path. */
1089   MALLOC_CHECK;
1090   if (iscygdrive_device (pathbuf))
1091     {
1092       if (!cygdrive_win32_path (pathbuf, dst, trailing_slash_p))
1093         return ENOENT;
1094       *flags = cygdrive_flags;
1095       goto fillin;
1096     }
1097
1098   /* Check the mount table for prefix matches. */
1099   for (i = 0; i < nmounts; i++)
1100     {
1101       mi = mount + posix_sorted[i];
1102       if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen))
1103         break;
1104     }
1105
1106   if (i >= nmounts)
1107     {
1108       if (slash_drive_prefix_p (pathbuf))
1109         slash_drive_to_win32_path (pathbuf, dst, trailing_slash_p);
1110       else
1111         backslashify (pathbuf, dst, trailing_slash_p);  /* just convert */
1112       *flags = 0;
1113     }
1114   else
1115     {
1116       int n = mi->native_pathlen;
1117       memcpy (dst, mi->native_path, n + 1);
1118       char *p = pathbuf + mi->posix_pathlen;
1119       if (!trailing_slash_p && !*p)
1120         {
1121           if (isdrive (dst) && !dst[2])
1122             dst[n++] = '\\';
1123           dst[n] = '\0';
1124         }
1125       else
1126         {
1127           /* Do not add trailing \ to UNC device names like \\.\a: */
1128           if (*p != '/' &&  /* FIXME: this test seems wrong. */
1129              (strncmp (mi->native_path, "\\\\.\\", 4) != 0 ||
1130                strncmp (mi->native_path + 4, "UNC\\", 4) == 0))
1131             dst[n++] = '\\';
1132           strcpy (dst + n, p);
1133         }
1134       backslashify (dst, dst, trailing_slash_p);
1135       *flags = mi->flags;
1136     }
1137
1138 fillin:
1139   /* Compute relative path if asked to and able to.  */
1140   unsigned cwdlen;
1141   cwdlen = 0;   /* avoid a (hopefully) bogus compiler warning */
1142   char *cwd_win32_now;
1143   cwd_win32_now = cwd_win32 (TMPCWD);
1144   if (win32_path == NULL)
1145     /* nothing to do */;
1146   else if (isrelpath &&
1147            path_prefix_p (cwd_win32_now, dst, cwdlen = strlen (cwd_win32_now)))
1148     {
1149       size_t n = strlen (dst);
1150       if (n < cwdlen)
1151         strcpy (win32_path, dst);
1152       else
1153         {
1154           if (n == cwdlen)
1155             dst += cwdlen;
1156           else
1157             dst += isdirsep (cwd_win32_now[cwdlen - 1]) ? cwdlen : cwdlen + 1;
1158
1159           memmove (win32_path, dst, strlen (dst) + 1);
1160           if (!*win32_path)
1161             {
1162               strcpy (win32_path, ".");
1163               if (trailing_slash_p)
1164                 strcat (win32_path, "\\");
1165             }
1166         }
1167     }
1168   else if (win32_path != dst)
1169     strcpy (win32_path, dst);
1170
1171 out:
1172   MALLOC_CHECK;
1173   debug_printf ("%s(rel), %s(abs) %p(flags) = conv_to_win32_path (%s)",
1174                 win32_path, full_win32_path, *flags,
1175                 src_path);
1176   return 0;
1177 }
1178
1179 /* Convert PATH (for which slash_drive_prefix_p returns 1) to WIN32 form.  */
1180
1181 void
1182 mount_info::slash_drive_to_win32_path (const char *path, char *buf,
1183                                        int trailing_slash_p)
1184 {
1185   buf[0] = path[2];
1186   buf[1] = ':';
1187   if (path[3] == '0')
1188     strcpy (buf + 2, "\\");
1189   else
1190     backslashify (path + 3, buf + 2, trailing_slash_p);
1191 }
1192
1193 /* cygdrive_posix_path: Build POSIX path used as the
1194    mount point for cygdrives created when there is no other way to
1195    obtain a POSIX path from a Win32 one. */
1196
1197 void
1198 mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
1199 {
1200   int len = cygdrive_len;
1201
1202   memcpy (dst, cygdrive, len + 1);
1203
1204   /* Now finish the path off with the drive letter to be used.
1205      The cygdrive prefix always ends with a trailing slash so
1206      the drive letter is added after the path. */
1207   dst[len++] = tolower (src[0]);
1208   if (!src[2] || (SLASH_P (src[2]) && !src[3]))
1209     dst[len++] = '\000';
1210   else
1211     {
1212       dst[len++] = '/';
1213       strcpy (dst + len, src + 3);
1214     }
1215   slashify (dst, dst, trailing_slash_p);
1216 }
1217
1218 int
1219 mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
1220 {
1221   const char *p = src + cygdrive_len;
1222   if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
1223     return 0;
1224   dst[0] = *p;
1225   dst[1] = ':';
1226   strcpy (dst + 2, p + 1);
1227   backslashify (dst, dst, trailing_slash_p || !dst[2]);
1228   debug_printf ("src '%s', dst '%s'", src, dst);
1229   return 1;
1230 }
1231
1232 /* conv_to_posix_path: Ensure src_path is a POSIX path.
1233
1234    The result is zero for success, or an errno value.
1235    posix_path must have sufficient space (i.e. MAX_PATH bytes).
1236    If keep_rel_p is non-zero, relative paths stay that way.  */
1237
1238 int
1239 mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
1240                                 int keep_rel_p)
1241 {
1242   int src_path_len = strlen (src_path);
1243   int relative_path_p = !isabspath (src_path);
1244   int trailing_slash_p;
1245
1246   if (src_path_len <= 1)
1247     trailing_slash_p = 0;
1248   else
1249     {
1250       const char *lastchar = src_path + src_path_len - 1;
1251       trailing_slash_p = SLASH_P (*lastchar) && lastchar[-1] != ':';
1252     }
1253
1254   debug_printf ("conv_to_posix_path (%s, %s, %s)", src_path,
1255                 keep_rel_p ? "keep-rel" : "no-keep-rel",
1256                 trailing_slash_p ? "add-slash" : "no-add-slash");
1257   MALLOC_CHECK;
1258
1259   if (src_path_len >= MAX_PATH)
1260     {
1261       debug_printf ("ENAMETOOLONG");
1262       return ENAMETOOLONG;
1263     }
1264
1265   /* FIXME: For now, if the path is relative and it's supposed to stay
1266      that way, skip mount table processing. */
1267
1268   if (keep_rel_p && relative_path_p)
1269     {
1270       slashify (src_path, posix_path, 0);
1271       debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1272       return 0;
1273     }
1274
1275   char pathbuf[MAX_PATH];
1276   char cwd[MAX_PATH];
1277
1278   /* No need to fetch cwd if path is absolute. */
1279   if (relative_path_p)
1280     getcwd_inner (cwd, MAX_PATH, 0, 0); /* FIXME: check rc */
1281   else
1282     strcpy (cwd, "/"); /* some innocuous value */
1283
1284   int rc = normalize_win32_path (cwd, src_path, pathbuf);
1285   if (rc != 0)
1286     {
1287       debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1288       return rc;
1289     }
1290
1291   int pathbuflen = strlen (pathbuf);
1292   for (int i = 0; i < nmounts; ++i)
1293     {
1294       mount_item &mi = mount[native_sorted[i]];
1295       if (! path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1296         continue;
1297
1298       /* SRC_PATH is in the mount table. */
1299       int nextchar;
1300       const char *p = pathbuf + mi.native_pathlen;
1301
1302       if (!*p || !p[1])
1303         nextchar = 0;
1304       else if (isdirsep (*p))
1305         nextchar = -1;
1306       else
1307         nextchar = 1;
1308
1309       int addslash = nextchar > 0 ? 1 : 0;
1310       if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH)
1311         return ENAMETOOLONG;
1312       strcpy (posix_path, mi.posix_path);
1313       if (addslash)
1314         strcat (posix_path, "/");
1315       if (nextchar)
1316         slashify (p,
1317                   posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
1318                   trailing_slash_p);
1319       goto out;
1320     }
1321
1322   /* Not in the database.  This should [theoretically] only happen if either
1323      the path begins with //, or / isn't mounted, or the path has a drive
1324      letter not covered by the mount table.  If it's a relative path then the
1325      caller must want an absolute path (otherwise we would have returned
1326      above).  So we always return an absolute path at this point. */
1327   if (isdrive (pathbuf))
1328     cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p);
1329   else
1330     {
1331       /* The use of src_path and not pathbuf here is intentional.
1332          We couldn't translate the path, so just ensure no \'s are present. */
1333       slashify (src_path, posix_path, trailing_slash_p);
1334     }
1335
1336 out:
1337   debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1338   MALLOC_CHECK;
1339   return 0;
1340 }
1341
1342 /* Return flags associated with a mount point given the win32 path. */
1343
1344 unsigned
1345 mount_info::set_flags_from_win32_path (const char *p)
1346 {
1347   for (int i = 0; i < nmounts; i++)
1348     {
1349       mount_item &mi = mount[native_sorted[i]];
1350       if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
1351         return mi.flags;
1352     }
1353   return 0;
1354 }
1355
1356 /* read_mounts: Given a specific regkey, read mounts from under its
1357    key. */
1358
1359 void
1360 mount_info::read_mounts (reg_key& r)
1361 {
1362   char posix_path[MAX_PATH];
1363   HKEY key = r.get_key ();
1364   DWORD i, posix_path_size;
1365   int found_cygdrive = FALSE;
1366
1367   /* Loop through subkeys */
1368   /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
1369      shared area is currently statically allocated so we can't have an
1370      arbitrarily large number of mounts. */
1371   for (DWORD i = 0; ; i++)
1372     {
1373       char native_path[MAX_PATH];
1374       int mount_flags;
1375
1376       posix_path_size = MAX_PATH;
1377       /* FIXME: if maximum posix_path_size is 256, we're going to
1378          run into problems if we ever try to store a mount point that's
1379          over 256 but is under MAX_PATH! */
1380       LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1381                           NULL, NULL, NULL);
1382
1383       if (err == ERROR_NO_MORE_ITEMS)
1384         break;
1385       else if (err != ERROR_SUCCESS)
1386         {
1387           debug_printf ("RegEnumKeyEx failed, error %d!\n", err);
1388           break;
1389         }
1390
1391       if (iscygdrive (posix_path))
1392         {
1393           found_cygdrive = TRUE;
1394           continue;
1395         }
1396
1397       /* Get a reg_key based on i. */
1398       reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1399
1400       /* Fetch info from the subkey. */
1401       subkey.get_string ("native", native_path, sizeof (native_path), "");
1402       mount_flags = subkey.get_int ("flags", 0);
1403
1404       /* Add mount_item corresponding to registry mount point. */
1405       int res = cygwin_shared->mount.add_item (native_path, posix_path, mount_flags, FALSE);
1406       if (res && get_errno () == EMFILE)
1407         break; /* The number of entries exceeds MAX_MOUNTS */
1408     }
1409
1410   if (!found_cygdrive)
1411     return;
1412
1413 loop:
1414   for (i = 0; ;i++)
1415     {
1416       posix_path_size = MAX_PATH;
1417       LONG err = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1418                           NULL, NULL, NULL);
1419
1420       if (err != ERROR_SUCCESS)
1421         break;
1422
1423       if (iscygdrive (posix_path))
1424         {
1425           /* This shouldn't be in the mount table. */
1426           (void) r.kill (posix_path);
1427           goto loop;
1428         }
1429     }
1430 }
1431
1432 /* from_registry: Build the entire mount table from the registry.  Also,
1433    read in cygdrive-related information from its registry location. */
1434
1435 void
1436 mount_info::from_registry ()
1437 {
1438   /* Use current mount areas if either user or system mount areas
1439      already exist.  Otherwise, import old mounts. */
1440
1441   reg_key r;
1442
1443   /* Retrieve cygdrive-related information. */
1444   read_cygdrive_info_from_registry ();
1445
1446   nmounts = 0;
1447
1448   /* First read mounts from user's table. */
1449   read_mounts (r);
1450
1451   /* Then read mounts from system-wide mount table. */
1452   reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1453               CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1454               CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1455               CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1456               NULL);
1457   read_mounts (r1);
1458
1459   /* If we had to create both user and system mount areas, import
1460      old mounts. */
1461   if (had_to_create_mount_areas == 2)
1462     import_v1_mounts ();
1463 }
1464
1465 /* add_reg_mount: Add mount item to registry.  Return zero on success,
1466    non-zero on failure. */
1467 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1468
1469 int
1470 mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1471 {
1472   /* Add the mount to the right registry location, depending on
1473      whether MOUNT_SYSTEM is set in the mount flags. */
1474   if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
1475     {
1476       /* reg_key for user mounts in HKEY_CURRENT_USER. */
1477       reg_key reg_user;
1478
1479       /* Start by deleting existing mount if one exists. */
1480       reg_user.kill (posix_path);
1481
1482       /* Create the new mount. */
1483       reg_key subkey = reg_key (reg_user.get_key (),
1484                                 KEY_ALL_ACCESS,
1485                                 posix_path, NULL);
1486       subkey.set_string ("native", native_path);
1487       subkey.set_int ("flags", mountflags);
1488     }
1489   else /* local_machine mount */
1490     {
1491       /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
1492       reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1493                        CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1494                        CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1495                        CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1496                        NULL);
1497
1498       if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1499         {
1500           set_errno (EACCES);
1501           return -1;
1502         }
1503
1504       /* Start by deleting existing mount if one exists. */
1505       reg_sys.kill (posix_path);
1506
1507       /* Create the new mount. */
1508       reg_key subkey = reg_key (reg_sys.get_key (),
1509                                 KEY_ALL_ACCESS,
1510                                 posix_path, NULL);
1511       subkey.set_string ("native", native_path);
1512       subkey.set_int ("flags", mountflags);
1513     }
1514
1515   return 0; /* Success! */
1516 }
1517
1518 /* del_reg_mount: delete mount item from registry indicated in flags.
1519    Return zero on success, non-zero on failure.*/
1520 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1521
1522 int
1523 mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1524 {
1525   int killres;
1526
1527   if ((flags & MOUNT_SYSTEM) == 0)      /* Delete from user registry */
1528     {
1529       reg_key reg_user (KEY_ALL_ACCESS,
1530                         CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
1531       killres = reg_user.kill (posix_path);
1532     }
1533   else                                  /* Delete from system registry */
1534     {
1535       reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1536                        CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1537                        CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1538                        CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1539                        NULL);
1540
1541       if (reg_sys.get_key () == INVALID_HANDLE_VALUE)
1542         {
1543           set_errno (EACCES);
1544           return -1;
1545         }
1546
1547       killres = reg_sys.kill (posix_path);
1548     }
1549
1550   if (killres != ERROR_SUCCESS)
1551     {
1552       __seterrno_from_win_error (killres);
1553       return -1;
1554     }
1555
1556   return 0; /* Success! */
1557 }
1558
1559 /* read_cygdrive_info_from_registry: Read the default prefix and flags
1560    to use when creating cygdrives from the special user registry
1561    location used to store cygdrive information. */
1562
1563 void
1564 mount_info::read_cygdrive_info_from_registry ()
1565 {
1566   /* reg_key for user path prefix in HKEY_CURRENT_USER. */
1567   reg_key r;
1568
1569   if (r.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1570     {
1571       /* Didn't find the user path prefix so check the system path prefix. */
1572
1573       /* reg_key for system path prefix in HKEY_LOCAL_MACHINE.  */
1574       reg_key r2 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1575                  CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1576                  CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1577                  CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1578                  NULL);
1579
1580     if (r2.get_string ("cygdrive prefix", cygdrive, sizeof (cygdrive), "") != 0)
1581       {
1582         /* Didn't find either so write the default to the registry and use it.
1583            NOTE: We are writing and using the user path prefix.  */
1584         write_cygdrive_info_to_registry ("/cygdrive", MOUNT_AUTO);
1585       }
1586     else
1587       {
1588         /* Fetch system cygdrive_flags from registry; returns MOUNT_AUTO on
1589            error. */
1590         cygdrive_flags = r2.get_int ("cygdrive flags", MOUNT_AUTO);
1591         slashify (cygdrive, cygdrive, 1);
1592         cygdrive_len = strlen(cygdrive);
1593       }
1594     }
1595   else
1596     {
1597       /* Fetch user cygdrive_flags from registry; returns MOUNT_AUTO on
1598          error. */
1599       cygdrive_flags = r.get_int ("cygdrive flags", MOUNT_AUTO);
1600       slashify (cygdrive, cygdrive, 1);
1601       cygdrive_len = strlen(cygdrive);
1602     }
1603 }
1604
1605 /* write_cygdrive_info_to_registry: Write the default prefix and flags
1606    to use when creating cygdrives to the special user registry
1607    location used to store cygdrive information. */
1608
1609 int
1610 mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1611 {
1612   /* Determine whether to modify user or system cygdrive path prefix. */
1613   HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1614
1615   /* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
1616      HKEY_LOCAL_MACHINE.  */
1617   reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
1618              CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1619              CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1620              CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1621              NULL);
1622
1623   /* Verify cygdrive prefix starts with a forward slash and if there's
1624      another character, it's not a slash. */
1625   if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
1626       (!isslash (cygdrive_prefix[0])) ||
1627       ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
1628       {
1629         set_errno (EINVAL);
1630         return -1;
1631       }
1632
1633   char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1];
1634   /* Ensure that there is never a final slash */
1635   nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
1636
1637   r.set_string ("cygdrive prefix", hold_cygdrive_prefix);
1638   r.set_int ("cygdrive flags", flags);
1639
1640   /* This also needs to go in the in-memory copy of "cygdrive", but only if
1641      appropriate:
1642        1. setting user path prefix, or
1643        2. overwriting (a previous) system path prefix */
1644   if ((flags & MOUNT_SYSTEM) == 0 ||
1645       (cygwin_shared->mount.cygdrive_flags & MOUNT_SYSTEM) != 0)
1646     {
1647       slashify (cygdrive_prefix, cygwin_shared->mount.cygdrive, 1);
1648       cygwin_shared->mount.cygdrive_flags = flags;
1649       cygwin_shared->mount.cygdrive_len = strlen(cygwin_shared->mount.cygdrive);
1650     }
1651
1652   return 0;
1653 }
1654
1655 int
1656 mount_info::remove_cygdrive_info_from_registry (const char *cygdrive_prefix, unsigned flags)
1657 {
1658   /* Determine whether to modify user or system cygdrive path prefix. */
1659   HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1660
1661   /* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
1662      HKEY_LOCAL_MACHINE.  */
1663   reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
1664              CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1665              CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1666              CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1667              NULL);
1668
1669   /* Delete cygdrive prefix and flags. */
1670   int res = r.killvalue ("cygdrive prefix");
1671   int res2 = r.killvalue ("cygdrive flags");
1672
1673   /* Reinitialize the cygdrive path prefix to reflect to removal from the
1674      registry. */
1675   read_cygdrive_info_from_registry ();
1676
1677   return (res != ERROR_SUCCESS) ? res : res2;
1678 }
1679
1680 int
1681 mount_info::get_cygdrive_prefixes (char *user, char *system)
1682 {
1683   /* Get the user path prefix from HKEY_CURRENT_USER. */
1684   reg_key r;
1685   int res = r.get_string ("cygdrive prefix", user, MAX_PATH, "");
1686
1687   /* Get the system path prefix from HKEY_LOCAL_MACHINE. */
1688   reg_key r2 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1689               CYGWIN_INFO_CYGNUS_REGISTRY_NAME,
1690               CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
1691               CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1692               NULL);
1693   int res2 = r2.get_string ("cygdrive prefix", system, MAX_PATH, "");
1694
1695   return (res != ERROR_SUCCESS) ? res : res2;
1696 }
1697
1698 struct mntent *
1699 mount_info::getmntent (int x)
1700 {
1701   if (x < 0 || x >= nmounts)
1702     return NULL;
1703
1704   return mount[native_sorted[x]].getmntent ();
1705 }
1706
1707 static mount_item *mounts_for_sort;
1708
1709 /* sort_by_posix_name: qsort callback to sort the mount entries.  Sort
1710    user mounts ahead of system mounts to the same POSIX path. */
1711 /* FIXME: should the user should be able to choose whether to
1712    prefer user or system mounts??? */
1713 static int
1714 sort_by_posix_name (const void *a, const void *b)
1715 {
1716   mount_item *ap = mounts_for_sort + (*((int*) a));
1717   mount_item *bp = mounts_for_sort + (*((int*) b));
1718
1719   /* Base weighting on longest posix path first so that the most
1720      obvious path will be chosen. */
1721   size_t alen = strlen (ap->posix_path);
1722   size_t blen = strlen (bp->posix_path);
1723
1724   int res = blen - alen;
1725
1726   if (res)
1727     return res;         /* Path lengths differed */
1728
1729   /* The two paths were the same length, so just determine normal
1730      lexical sorted order. */
1731   res = strcmp (ap->posix_path, bp->posix_path);
1732
1733   if (res == 0)
1734    {
1735      /* need to select between user and system mount to same POSIX path */
1736      if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1737       return 1;
1738      else
1739       return -1;
1740    }
1741
1742   return res;
1743 }
1744
1745 /* sort_by_native_name: qsort callback to sort the mount entries.  Sort
1746    user mounts ahead of system mounts to the same POSIX path. */
1747 /* FIXME: should the user should be able to choose whether to
1748    prefer user or system mounts??? */
1749 static int
1750 sort_by_native_name (const void *a, const void *b)
1751 {
1752   mount_item *ap = mounts_for_sort + (*((int*) a));
1753   mount_item *bp = mounts_for_sort + (*((int*) b));
1754
1755   /* Base weighting on longest win32 path first so that the most
1756      obvious path will be chosen. */
1757   size_t alen = strlen (ap->native_path);
1758   size_t blen = strlen (bp->native_path);
1759
1760   int res = blen - alen;
1761
1762   if (res)
1763     return res;         /* Path lengths differed */
1764
1765   /* The two paths were the same length, so just determine normal
1766      lexical sorted order. */
1767   res = strcmp (ap->native_path, bp->native_path);
1768
1769   if (res == 0)
1770    {
1771      /* need to select between user and system mount to same POSIX path */
1772      if ((bp->flags & MOUNT_SYSTEM) == 0) /* user mount */
1773       return 1;
1774      else
1775       return -1;
1776    }
1777
1778   return res;
1779 }
1780
1781 void
1782 mount_info::sort ()
1783 {
1784   for (int i = 0; i < nmounts; i++)
1785     native_sorted[i] = posix_sorted[i] = i;
1786   /* Sort them into reverse length order, otherwise we won't
1787      be able to look for /foo in /.  */
1788   mounts_for_sort = mount;      /* ouch. */
1789   qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
1790   qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
1791 }
1792
1793 /* Add an entry to the mount table.
1794    Returns 0 on success, -1 on failure and errno is set.
1795
1796    This is where all argument validation is done.  It may not make sense to
1797    do this when called internally, but it's cleaner to keep it all here.  */
1798
1799 int
1800 mount_info::add_item (const char *native, const char *posix, unsigned mountflags, int reg_p)
1801 {
1802   /* Something's wrong if either path is NULL or empty, or if it's
1803      not a UNC or absolute path. */
1804
1805   if ((native == NULL) || (*native == 0) ||
1806       (posix == NULL) || (*posix == 0) ||
1807       (!slash_unc_prefix_p (native) && !isabspath (native)))
1808     {
1809       set_errno (EINVAL);
1810       return -1;
1811     }
1812
1813   /* Make sure both paths do not end in /. */
1814   char nativetmp[MAX_PATH];
1815   char posixtmp[MAX_PATH];
1816
1817   if (slash_drive_prefix_p (native))
1818     slash_drive_to_win32_path (native, nativetmp, 0);
1819   else
1820     backslashify (native, nativetmp, 0);
1821   nofinalslash (nativetmp, nativetmp);
1822
1823   slashify (posix, posixtmp, 0);
1824   nofinalslash (posixtmp, posixtmp);
1825
1826   debug_printf ("%s[%s], %s[%s], %p",
1827                 native, nativetmp, posix, posixtmp, mountflags);
1828
1829   /* Duplicate /'s in path are an error. */
1830   for (char *p = posixtmp + 1; *p; ++p)
1831     {
1832       if (p[-1] == '/' && p[0] == '/')
1833         {
1834           set_errno (EINVAL);
1835           return -1;
1836         }
1837     }
1838
1839   /* Write over an existing mount item with the same POSIX path if
1840      it exists and is from the same registry area. */
1841   int i;
1842   for (i = 0; i < nmounts; i++)
1843     {
1844       if (strcasematch (mount[i].posix_path, posixtmp) &&
1845           (mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM))
1846         break;
1847     }
1848
1849   if (i == nmounts)
1850     {
1851       if (nmounts < MAX_MOUNTS)
1852         i = nmounts++;
1853       else
1854         {
1855           set_errno (EMFILE);
1856           return -1;
1857         }
1858     }
1859
1860   if (reg_p && add_reg_mount (nativetmp, posixtmp, mountflags))
1861     return -1;
1862
1863   mount[i].init (nativetmp, posixtmp, mountflags);
1864   sort ();
1865
1866   return 0;
1867 }
1868
1869 /* Delete a mount table entry where path is either a Win32 or POSIX
1870    path. Since the mount table is really just a table of aliases,
1871    deleting / is ok (although running without a slash mount is
1872    strongly discouraged because some programs may run erratically
1873    without one).  If MOUNT_SYSTEM is set in flags, remove from system
1874    registry, otherwise remove the user registry mount.
1875 */
1876
1877 int
1878 mount_info::del_item (const char *path, unsigned flags, int reg_p)
1879 {
1880   char pathtmp[MAX_PATH];
1881   int posix_path_p = FALSE;
1882
1883   /* Something's wrong if path is NULL or empty. */
1884   if (path == NULL || *path == 0 || !isabspath (path))
1885     {
1886       set_errno (EINVAL);
1887       return -1;
1888     }
1889
1890   if (slash_drive_prefix_p (path))
1891       slash_drive_to_win32_path (path, pathtmp, 0);
1892   else if (slash_unc_prefix_p (path) || strpbrk (path, ":\\"))
1893       backslashify (path, pathtmp, 0);
1894   else
1895     {
1896       slashify (path, pathtmp, 0);
1897       posix_path_p = TRUE;
1898     }
1899   nofinalslash (pathtmp, pathtmp);
1900
1901   if (reg_p && posix_path_p &&
1902       del_reg_mount (pathtmp, flags) &&
1903       del_reg_mount (path, flags)) /* for old irregular entries */
1904     return -1;
1905
1906   for (int i = 0; i < nmounts; i++)
1907     {
1908       int ent = native_sorted[i]; /* in the same order as getmntent() */
1909       if (((posix_path_p)
1910            ? strcasematch (mount[ent].posix_path, pathtmp)
1911            : strcasematch (mount[ent].native_path, pathtmp)) &&
1912           (mount[ent].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM))
1913         {
1914           if (!posix_path_p &&
1915               reg_p && del_reg_mount (mount[ent].posix_path, flags))
1916             return -1;
1917
1918           nmounts--; /* One less mount table entry */
1919           /* Fill in the hole if not at the end of the table */
1920           if (ent < nmounts)
1921             memmove (mount + ent, mount + ent + 1,
1922                      sizeof (mount[ent]) * (nmounts - ent));
1923           sort (); /* Resort the table */
1924           return 0;
1925         }
1926     }
1927   set_errno (EINVAL);
1928   return -1;
1929 }
1930
1931 /* read_v1_mounts: Given a reg_key to an old mount table registry area,
1932    read in the mounts.  The "which" arg contains zero if we're reading
1933    the user area and MOUNT_SYSTEM if we're reading the system area.
1934    This way we can store the mounts read in the appropriate place when
1935    they are written back to the new registry layout. */
1936
1937 void
1938 mount_info::read_v1_mounts (reg_key r, unsigned which)
1939 {
1940   unsigned mountflags = 0;
1941
1942   /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
1943   for (int i = 0; i < 30; i++)
1944     {
1945       char key_name[10];
1946       char win32path[MAX_PATH];
1947       char unixpath[MAX_PATH];
1948
1949       __small_sprintf (key_name, "%02x", i);
1950
1951       reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
1952
1953       /* The registry names are historical but useful so are left alone.  */
1954       k.get_string ("native", win32path, sizeof (win32path), "");
1955       k.get_string ("unix", unixpath, sizeof (unixpath), "");
1956
1957       /* Does this entry contain something?  */
1958       if (*win32path != 0)
1959         {
1960           mountflags = 0;
1961
1962           if (k.get_int ("fbinary", 0))
1963             mountflags |= MOUNT_BINARY;
1964
1965           /* Or in zero or MOUNT_SYSTEM depending on which table
1966              we're reading. */
1967           mountflags |= which;
1968
1969           int res = cygwin_shared->mount.add_item (win32path, unixpath, mountflags, TRUE);
1970           if (res && get_errno () == EMFILE)
1971             break; /* The number of entries exceeds MAX_MOUNTS */
1972         }
1973     }
1974 }
1975
1976 /* import_v1_mounts: If v1 mounts are present, load them and write
1977    the new entries to the new registry area. */
1978
1979 void
1980 mount_info::import_v1_mounts ()
1981 {
1982   reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
1983              "SOFTWARE",
1984              "Cygnus Solutions",
1985              "CYGWIN.DLL setup",
1986              "b15.0",
1987              "mounts",
1988              NULL);
1989
1990   nmounts = 0;
1991
1992   /* First read mounts from user's table. */
1993   read_v1_mounts (r, 0);
1994
1995   /* Then read mounts from system-wide mount table. */
1996   reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
1997               "SOFTWARE",
1998               "Cygnus Solutions",
1999               "CYGWIN.DLL setup",
2000               "b15.0",
2001               "mounts",
2002               NULL);
2003   read_v1_mounts (r1, MOUNT_SYSTEM);
2004 }
2005
2006 /************************* mount_item class ****************************/
2007
2008 struct mntent *
2009 mount_item::getmntent ()
2010 {
2011 #ifdef _MT_SAFE
2012   struct mntent &ret=_reent_winsup()->_ret;
2013 #else
2014   static NO_COPY struct mntent ret;
2015 #endif
2016
2017   /* Pass back pointers to mount_info strings reserved for use by
2018      getmntent rather than pointers to strings in the internal mount
2019      table because the mount table might change, causing weird effects
2020      from the getmntent user's point of view. */
2021
2022   strcpy (cygwin_shared->mount.mnt_fsname, native_path);
2023   ret.mnt_fsname = cygwin_shared->mount.mnt_fsname;
2024   strcpy (cygwin_shared->mount.mnt_dir, posix_path);
2025   ret.mnt_dir = cygwin_shared->mount.mnt_dir;
2026
2027   if (!(flags & MOUNT_SYSTEM))          /* user mount */
2028     strcpy (cygwin_shared->mount.mnt_type, (char *) "user");
2029   else                                  /* system mount */
2030     strcpy (cygwin_shared->mount.mnt_type, (char *) "system");
2031
2032   if ((flags & MOUNT_AUTO))             /* cygdrive */
2033     strcat (cygwin_shared->mount.mnt_type, (char *) ",auto");
2034
2035   ret.mnt_type = cygwin_shared->mount.mnt_type;
2036
2037   /* mnt_opts is a string that details mount params such as
2038      binary or textmode, or exec.  We don't print
2039      `silent' here; it's a magic internal thing. */
2040
2041   if (! (flags & MOUNT_BINARY))
2042     strcpy (cygwin_shared->mount.mnt_opts, (char *) "textmode");
2043   else
2044     strcpy (cygwin_shared->mount.mnt_opts, (char *) "binmode");
2045
2046   if (flags & MOUNT_CYGWIN_EXEC)
2047     strcat (cygwin_shared->mount.mnt_opts, (char *) ",cygexec");
2048   else if (flags & MOUNT_EXEC)
2049     strcat (cygwin_shared->mount.mnt_opts, (char *) ",exec");
2050
2051
2052   ret.mnt_opts = cygwin_shared->mount.mnt_opts;
2053
2054   ret.mnt_freq = 1;
2055   ret.mnt_passno = 1;
2056   return &ret;
2057 }
2058
2059 /* Fill in the fields of a mount table entry.  */
2060
2061 void
2062 mount_item::init (const char *native, const char *posix, unsigned mountflags)
2063 {
2064   strcpy ((char *) native_path, native);
2065   strcpy ((char *) posix_path, posix);
2066
2067   native_pathlen = strlen (native_path);
2068   posix_pathlen = strlen (posix_path);
2069
2070   flags = mountflags;
2071 }
2072
2073 /********************** Mount System Calls **************************/
2074
2075 /* Mount table system calls.
2076    Note that these are exported to the application.  */
2077
2078 /* mount: Add a mount to the mount table in memory and to the registry
2079    that will cause paths under win32_path to be translated to paths
2080    under posix_path. */
2081
2082 extern "C"
2083 int
2084 mount (const char *win32_path, const char *posix_path, unsigned flags)
2085 {
2086   int res = -1;
2087
2088   if (flags & MOUNT_AUTO) /* normal mount */
2089     {
2090       /* When flags include MOUNT_AUTO, take this to mean that
2091         we actually want to change the cygdrive prefix and flags
2092         without actually mounting anything. */
2093       res = cygwin_shared->mount.write_cygdrive_info_to_registry (posix_path, flags);
2094       win32_path = NULL;
2095     }
2096   else
2097     {
2098       if (iscygdrive (posix_path))
2099         {
2100           set_errno (EINVAL);
2101           return res;   /* Don't try to add cygdrive prefix. */
2102         }
2103
2104       res = cygwin_shared->mount.add_item (win32_path, posix_path, flags, TRUE);
2105     }
2106
2107   syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
2108   return res;
2109 }
2110
2111 /* umount: The standard umount call only has a path parameter.  Since
2112    it is not possible for this call to specify whether to remove the
2113    mount from the user or global mount registry table, assume the user
2114    table. */
2115
2116 extern "C"
2117 int
2118 umount (const char *path)
2119 {
2120   return cygwin_umount (path, 0);
2121 }
2122
2123 /* cygwin_umount: This is like umount but takes an additional flags
2124    parameter that specifies whether to umount from the user or system-wide
2125    registry area. */
2126
2127 extern "C"
2128 int
2129 cygwin_umount (const char *path, unsigned flags)
2130 {
2131   int res = -1;
2132
2133   if (flags & MOUNT_AUTO)
2134     {
2135       /* When flags include MOUNT_AUTO, take this to mean that we actually want
2136          to remove the cygdrive prefix and flags without actually unmounting
2137          anything. */
2138       res = cygwin_shared->mount.remove_cygdrive_info_from_registry (path, flags);
2139     }
2140   else
2141     {
2142       res = cygwin_shared->mount.del_item (path, flags, TRUE);
2143     }
2144
2145   syscall_printf ("%d = cygwin_umount (%s, %d)", res,  path, flags);
2146   return res;
2147 }
2148
2149 #ifdef _MT_SAFE
2150 #define iteration _reent_winsup()->_iteration
2151 #else
2152 static int iteration;
2153 #endif
2154
2155 extern "C"
2156 FILE *
2157 setmntent (const char *filep, const char *)
2158 {
2159   iteration = 0;
2160   return (FILE *) filep;
2161 }
2162
2163 extern "C"
2164 struct mntent *
2165 getmntent (FILE *)
2166 {
2167   return cygwin_shared->mount.getmntent (iteration++);
2168 }
2169
2170 extern "C"
2171 int
2172 endmntent (FILE *)
2173 {
2174   return 1;
2175 }
2176
2177 /********************** Symbolic Link Support **************************/
2178
2179 /* Create a symlink from FROMPATH to TOPATH. */
2180
2181 extern "C"
2182 int
2183 symlink (const char *topath, const char *frompath)
2184 {
2185   HANDLE h;
2186   int res = -1;
2187
2188   path_conv win32_path (frompath, PC_SYM_NOFOLLOW);
2189   if (win32_path.error)
2190     {
2191       set_errno (win32_path.error);
2192       goto done;
2193     }
2194
2195   syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
2196
2197   if (topath[0] == 0)
2198     {
2199       set_errno (EINVAL);
2200       goto done;
2201     }
2202   if (strlen (topath) >= MAX_PATH)
2203     {
2204       set_errno (ENAMETOOLONG);
2205       goto done;
2206     }
2207
2208   if (win32_path.is_device () ||
2209       win32_path.file_attributes () != (DWORD) -1)
2210     {
2211       set_errno (EEXIST);
2212       goto done;
2213     }
2214
2215   h = CreateFileA(win32_path.get_win32 (), GENERIC_WRITE, 0, &sec_none_nih,
2216                   CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
2217   if (h == INVALID_HANDLE_VALUE)
2218       __seterrno ();
2219   else
2220     {
2221       char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10];
2222
2223       __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
2224       DWORD len = strlen (buf) + 1;
2225
2226       /* Note that the terminating nul is written.  */
2227       DWORD written;
2228       if (!WriteFile (h, buf, len, &written, NULL) || written != len)
2229         {
2230           __seterrno ();
2231           CloseHandle (h);
2232           DeleteFileA (win32_path.get_win32 ());
2233         }
2234       else
2235         {
2236           CloseHandle (h);
2237           set_file_attribute (win32_path.has_acls (),
2238                               win32_path.get_win32 (),
2239                               S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
2240           SetFileAttributesA (win32_path.get_win32 (), FILE_ATTRIBUTE_SYSTEM);
2241           res = 0;
2242         }
2243     }
2244
2245 done:
2246   syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath);
2247   return res;
2248 }
2249
2250 static __inline char *
2251 has_suffix (const char *path, const suffix_info *suffixes)
2252 {
2253   char *ext = strrchr (path, '.');
2254   if (ext)
2255     for (const suffix_info *ex = suffixes; ex->name != NULL; ex++)
2256       if (strcasematch (ext, ex->name))
2257         return ext;
2258   return NULL;
2259 }
2260
2261 static __inline__ int
2262 next_suffix (char *ext_here, const suffix_info *&suffixes)
2263 {
2264   if (!suffixes)
2265     return 1;
2266
2267   while (suffixes && suffixes->name)
2268     if (!suffixes->addon)
2269       suffixes++;
2270     else
2271       {
2272         strcpy (ext_here, suffixes->name);
2273         suffixes++;
2274         return 1;
2275       }
2276   return 0;
2277 }
2278
2279 /* Check if PATH is a symlink.  PATH must be a valid Win32 path name.
2280
2281    If PATH is a symlink, put the value of the symlink--the file to
2282    which it points--into BUF.  The value stored in BUF is not
2283    necessarily null terminated.  BUFLEN is the length of BUF; only up
2284    to BUFLEN characters will be stored in BUF.  BUF may be NULL, in
2285    which case nothing will be stored.
2286
2287    Set *SYML if PATH is a symlink.
2288
2289    Set *EXEC if PATH appears to be executable.  This is an efficiency
2290    hack because we sometimes have to open the file anyhow.  *EXEC will
2291    not be set for every executable file.
2292
2293    Return -1 on error, 0 if PATH is not a symlink, or the length
2294    stored into BUF if PATH is a symlink.  */
2295
2296 int
2297 symlink_info::check (const char *in_path, const suffix_info *suffixes)
2298 {
2299   HANDLE h;
2300   int res = 0;
2301   char extbuf[MAX_PATH + 5];
2302   const char *path = in_path;
2303
2304   if (!suffixes)
2305     ext_here = NULL;
2306   else if ((known_suffix = has_suffix (in_path, suffixes)) != NULL)
2307     {
2308       suffixes = NULL;
2309       ext_here = NULL;
2310     }
2311   else
2312     {
2313       path = strcpy (extbuf, in_path);
2314       ext_here = strchr (path, '\0');
2315     }
2316
2317   is_symlink = TRUE;
2318
2319   error = 0;
2320   do
2321     {
2322       if (!next_suffix (ext_here, suffixes))
2323         break;
2324       error = 0;
2325       fileattr = GetFileAttributesA (path);
2326       if (fileattr == (DWORD) -1)
2327         {
2328           /* The GetFileAttributesA call can fail for reasons that don't
2329              matter, so we just return 0.  For example, getting the
2330              attributes of \\HOST will typically fail.  */
2331           debug_printf ("GetFileAttributesA (%s) failed", path);
2332           error = geterrno_from_win_error (GetLastError (), EACCES);
2333           continue;
2334         }
2335
2336       /* Windows allows path\. even when `path' isn't a directory.
2337          Detect this scenario and disallow it, since it is non-UNIX like.
2338          FIXME: This code actually checks for things like foo/ and foo/..
2339          even though those usages have already been (erroneously?) eaten
2340          by cygwin_shared->mount.conv_to_win32_path in path_conv::check. */
2341
2342       char *p = strrchr (path, '\\');
2343       if (p && !(fileattr & FILE_ATTRIBUTE_DIRECTORY) &&
2344           (*++p == '\0' || (*p == '.' && (*++p == '\0' || (*p == '.' && p[1] == '\0')))))
2345         {
2346           debug_printf ("%s is a non-directory", path);
2347           error = ENOTDIR;
2348           goto file_not_symlink;
2349         }
2350
2351       /* A symlink will have the `system' file attribute. */
2352       /* Only files can be symlinks (which can be symlinks to directories). */
2353       if (!(pflags & PATH_SYMLINK) && !SYMLINKATTR (fileattr))
2354         goto file_not_symlink;
2355
2356       /* Open the file.  */
2357
2358       h = CreateFileA (path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
2359                        FILE_ATTRIBUTE_NORMAL, 0);
2360       res = -1;
2361       if (h == INVALID_HANDLE_VALUE)
2362         goto file_not_symlink;
2363       else
2364         {
2365           char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2366           DWORD got;
2367
2368           if (! ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
2369             error = EIO;
2370           else if (got == sizeof (cookie_buf)
2371                    && memcmp (cookie_buf, SYMLINK_COOKIE,
2372                               sizeof (cookie_buf)) == 0)
2373             {
2374               /* It's a symlink.  */
2375               pflags = PATH_SYMLINK;
2376
2377               res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2378               if (!res)
2379                 error = EIO;
2380               else
2381                 {
2382                   /* Versions prior to b16 stored several trailing
2383                      NULs with the path (to fill the path out to 1024
2384                      chars).  Current versions only store one trailing
2385                      NUL.  The length returned is the path without
2386                      *any* trailing NULs.  We also have to handle (or
2387                      at least not die from) corrupted paths.  */
2388                   if (memchr (contents, 0, got) != NULL)
2389                     res = strlen (contents);
2390                   else
2391                     res = got;
2392                 }
2393             }
2394           else if (got == sizeof (cookie_buf)
2395                    && memcmp (cookie_buf, SOCKET_COOKIE,
2396                               sizeof (cookie_buf)) == 0)
2397             {
2398               pflags |= PATH_SOCKET;
2399               goto close_and_return;
2400             }
2401           else
2402             {
2403               /* Not a symlink, see if executable.  */
2404               if (!(pflags & (PATH_EXEC | PATH_CYGWIN_EXEC)) && got >= 2 &&
2405                   ((cookie_buf[0] == '#' && cookie_buf[1] == '!') ||
2406                    (cookie_buf[0] == ':' && cookie_buf[1] == '\n')))
2407                 pflags |= PATH_EXEC;
2408             close_and_return:
2409               CloseHandle (h);
2410               goto file_not_symlink;
2411             }
2412         }
2413
2414       CloseHandle (h);
2415       break;
2416     }
2417   while (suffixes);
2418   goto out;
2419
2420 file_not_symlink:
2421   is_symlink = FALSE;
2422   syscall_printf ("not a symlink");
2423   res = 0;
2424
2425 out:
2426   syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2427                   res, path, contents, pflags);
2428
2429   return res;
2430 }
2431
2432 /* readlink system call */
2433
2434 extern "C"
2435 int
2436 readlink (const char *path, char *buf, int buflen)
2437 {
2438   extern suffix_info stat_suffixes[];
2439   path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2440
2441   if (pathbuf.error)
2442     {
2443       set_errno (pathbuf.error);
2444       syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
2445       return -1;
2446     }
2447
2448   if (!pathbuf.issymlink ())
2449     {
2450       if (pathbuf.fileattr != (DWORD) -1)
2451         set_errno (EINVAL);
2452       return -1;
2453     }
2454
2455   int len = strlen (pathbuf.get_win32 ());
2456   if (len > (buflen - 1))
2457     {
2458       set_errno (ENAMETOOLONG);
2459       return -1;
2460     }
2461   memcpy (buf, pathbuf.get_win32 (), len);
2462   buf[len] = '\0';
2463
2464   /* errno set by symlink.check if error */
2465   return len;
2466 }
2467
2468 /* Some programs rely on st_dev/st_ino being unique for each file.
2469    Hash the path name and hope for the best.  The hash arg is not
2470    always initialized to zero since readdir needs to compute the
2471    dirent ino_t based on a combination of the hash of the directory
2472    done during the opendir call and the hash or the filename within
2473    the directory.  FIXME: Not bullet-proof. */
2474 /* Cygwin internal */
2475
2476 unsigned long __stdcall
2477 hash_path_name (unsigned long hash, const char *name)
2478 {
2479   if (!*name)
2480     return hash;
2481
2482   /* Perform some initial permutations on the pathname if this is
2483      not "seeded" */
2484   if (!hash)
2485     {
2486       /* Simplistic handling of drives.  If there is a drive specified,
2487          make sure that the initial letter is upper case.  If there is
2488          no \ after the ':' assume access through the root directory
2489          of that drive.
2490          FIXME:  Should really honor MS-Windows convention of using
2491          the environment to track current directory on various drives. */
2492       if (name[1] == ':')
2493         {
2494           char *nn, *newname = (char *) alloca (strlen (name) + 2);
2495           nn = strncpy (newname, name, 2);
2496           if (islower (*nn))
2497             *newname = toupper (*nn);
2498           *(nn += 2) = '\0';
2499           name += 2;
2500           if (*name != '\\')
2501             {
2502               *nn = '\\';
2503               *++nn = '\0';
2504             }
2505           strcpy (nn, name);
2506           name = newname;
2507           goto hashit;
2508         }
2509
2510       /* Fill out the hashed path name with the current working directory if
2511          this is not an absolute path and there is no pre-specified hash value.
2512          Otherwise the inodes same will differ depending on whether a file is
2513          referenced with an absolute value or relatively. */
2514
2515       if (*name != '\\' && (cwd_win32 (TMPCWD) == NULL || get_cwd_win32 ()))
2516         {
2517           hash = cwd_hash ();
2518           if (name[0] == '.' && name[1] == '\0')
2519             return hash;
2520           hash = hash_path_name (hash, "\\");
2521         }
2522     }
2523
2524 hashit:
2525   /* Build up hash.  Ignore single trailing slash or \a\b\ != \a\b or
2526      \a\b\.  but allow a single \ if that's all there is. */
2527   do
2528     {
2529       hash += *name + (*name << 17);
2530       hash ^= hash >> 2;
2531     }
2532   while (*++name != '\0' &&
2533          !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
2534   return hash;
2535 }
2536
2537 static int
2538 get_cwd_win32 ()
2539 {
2540   DWORD dlen, len;
2541
2542   cwd.lock->acquire ();
2543   for (dlen = 256; ; dlen *= 2)
2544     {
2545       cwd.win32 = (char *) crealloc (cwd.win32, dlen + 2);
2546       if ((len = GetCurrentDirectoryA (dlen, cwd.win32)) < dlen)
2547         break;
2548     }
2549
2550   if (len == 0)
2551     __seterrno ();
2552   else
2553     cwd.hash = hash_path_name (0, cwd.win32);
2554
2555   cwd.lock->release ();
2556   return len;
2557 }
2558
2559 /* getcwd */
2560
2561 char *
2562 getcwd_inner (char *buf, size_t ulen, int posix_p, int with_chroot)
2563 {
2564   char *resbuf = NULL;
2565   size_t len = ulen;
2566
2567   if (cwd_win32 (TMPCWD) == NULL && !get_cwd_win32 ())
2568     return NULL;
2569
2570   char *cwd_win32_now = cwd_win32 (TMPCWD);
2571   char *cwd_posix_now = cwd_posix (TMPCWD);
2572   if (!posix_p)
2573     {
2574       if (strlen (cwd_win32_now) >= len)
2575         set_errno (ERANGE);
2576       else
2577         {
2578           strcpy (buf, cwd_win32_now);
2579           resbuf = buf;
2580         }
2581
2582       syscall_printf ("%p (%s) = getcwd_inner (%p, %d, win32) (cached)",
2583                       resbuf, resbuf ? resbuf : "", buf, len);
2584       return resbuf;
2585     }
2586   else if (cwd_posix_now != NULL)
2587     {
2588       debug_printf("myself->root: %s, cwd_posix: %s", myself->root, cwd_posix_now);
2589       if (strlen (cwd_posix_now) >= len)
2590         set_errno (ERANGE);
2591       else if (with_chroot && ischrootpath(cwd_posix_now))
2592         {
2593           strcpy (buf, cwd_posix_now + myself->rootlen);
2594           if (!buf[0])
2595             strcpy (buf, "/");
2596           resbuf = buf;
2597         }
2598       else
2599         {
2600           strcpy (buf, cwd_posix_now);
2601           resbuf = buf;
2602         }
2603
2604       syscall_printf ("%p (%s) = getcwd_inner (%p, %d, posix) (cached)",
2605                       resbuf, resbuf ? resbuf : "", buf, len);
2606       return resbuf;
2607     }
2608
2609   /* posix_p required and cwd_posix == NULL */
2610
2611   char temp[MAX_PATH];
2612
2613   /* Turn from Win32 style to our style.  */
2614   cygwin_shared->mount.conv_to_posix_path (cwd_win32_now, temp, 0);
2615
2616   size_t tlen = strlen (temp);
2617
2618   if (with_chroot && ischrootpath (temp))
2619     tlen -= myself->rootlen;
2620
2621   cwd.lock->acquire ();
2622   cwd.posix = (char *) crealloc (cwd.posix, tlen + 1);
2623   if (cwd.posix != NULL)
2624     if (with_chroot && ischrootpath (temp))
2625       {
2626         strcpy (cwd.posix, temp + myself->rootlen);
2627         if (!buf[0])
2628           strcpy (buf, "/");
2629       }
2630     else
2631       strcpy (cwd.posix, temp);
2632
2633   cwd.lock->release ();
2634
2635   if (tlen >= ulen)
2636     set_errno (ERANGE); /* len was too small */
2637   else
2638     {
2639       strcpy (buf, temp);
2640       resbuf = buf;
2641     }
2642
2643   syscall_printf ("%p (%s) = getcwd_inner (%p, %d, %s)",
2644                   resbuf, resbuf ? resbuf : "",
2645                   buf, len, posix_p ? "posix" : "win32");
2646   return resbuf;
2647 }
2648
2649 char *
2650 getcwd (char *buf, size_t ulen)
2651 {
2652   char *res;
2653
2654   if (buf == NULL || ulen == 0)
2655     {
2656       buf = (char *) alloca (MAX_PATH);
2657       res = getcwd_inner (buf, MAX_PATH, 1, 1);
2658       res = strdup (buf);
2659     }
2660   else
2661     {
2662       res = getcwd_inner (buf, ulen, 1, 1);
2663     }
2664
2665   return res;
2666 }
2667
2668 /* getwd: standards? */
2669 extern "C"
2670 char *
2671 getwd (char *buf)
2672 {
2673   return getcwd (buf, MAX_PATH);
2674 }
2675
2676 /* chdir: POSIX 5.2.1.1 */
2677 extern "C"
2678 int
2679 chdir (const char *dir)
2680 {
2681   syscall_printf ("dir %s", dir);
2682   path_conv path (dir);
2683
2684   if (path.error)
2685     {
2686       set_errno (path.error);
2687       syscall_printf ("-1 = chdir (%s)", dir);
2688       return -1;
2689     }
2690
2691   char *native_dir = path.get_win32 ();
2692
2693   /* Check to see if path translates to something like C:.
2694      If it does, append a \ to the native directory specification to
2695      defeat the Windows 95 (i.e. MS-DOS) tendency of returning to
2696      the last directory visited on the given drive. */
2697   if (isdrive (native_dir) && !native_dir[2])
2698     {
2699       native_dir[2] = '\\';
2700       native_dir[3] = '\0';
2701     }
2702   int res = SetCurrentDirectoryA (native_dir) ? 0 : -1;
2703   if (res == -1)
2704     __seterrno ();
2705   else
2706     {
2707       cwd.lock->acquire ();
2708       /* Store new cache information */
2709       cfree (cwd.win32);
2710       cwd.win32 = cstrdup (path);
2711
2712       char pathbuf[MAX_PATH];
2713       (void) normalize_posix_path (cwd.posix, dir, pathbuf);
2714       /* Look for trailing path component consisting entirely of dots.  This
2715          is needed only in case of chdir since Windows simply ignores count
2716          of dots > 2 here instead of returning an error code.  Counts of dots
2717          <= 2 are already eliminated by normalize_posix_path. */
2718       char *last_slash = strrchr (pathbuf, '/');
2719       if (last_slash > pathbuf && strspn (last_slash + 1, ".") == strlen (last_slash + 1))
2720         *last_slash = '\0';
2721       cfree (cwd.posix);
2722       cwd.posix = cstrdup (pathbuf);
2723       cwd.lock->release ();
2724     }
2725
2726   syscall_printf ("%d = chdir() cwd.posix '%s' native '%s'", res, cwd.posix, native_dir);
2727   return res;
2728 }
2729
2730 /******************** Exported Path Routines *********************/
2731
2732 /* Cover functions to the path conversion routines.
2733    These are exported to the world as cygwin_foo by cygwin.din.  */
2734
2735 extern "C"
2736 int
2737 cygwin_conv_to_win32_path (const char *path, char *win32_path)
2738 {
2739   path_conv p (path, PC_SYM_FOLLOW);
2740   if (p.error)
2741     {
2742       set_errno (p.error);
2743       return -1;
2744     }
2745
2746   strcpy (win32_path, p.get_win32 ());
2747   return 0;
2748 }
2749
2750 extern "C"
2751 int
2752 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
2753 {
2754   path_conv p (path, PC_SYM_FOLLOW | PC_FULL);
2755   if (p.error)
2756     {
2757       set_errno (p.error);
2758       return -1;
2759     }
2760
2761   strcpy (win32_path, p.get_win32 ());
2762   return 0;
2763 }
2764
2765 /* This is exported to the world as cygwin_foo by cygwin.din.  */
2766
2767 extern "C"
2768 int
2769 cygwin_conv_to_posix_path (const char *path, char *posix_path)
2770 {
2771   if (check_null_empty_path_errno (path))
2772     return -1;
2773   cygwin_shared->mount.conv_to_posix_path (path, posix_path, 1);
2774   return 0;
2775 }
2776
2777 extern "C"
2778 int
2779 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
2780 {
2781   if (check_null_empty_path_errno (path))
2782     return -1;
2783   cygwin_shared->mount.conv_to_posix_path (path, posix_path, 0);
2784   return 0;
2785 }
2786
2787 /* The realpath function is supported on some UNIX systems.  */
2788
2789 extern "C"
2790 char *
2791 realpath (const char *path, char *resolved)
2792 {
2793   int err;
2794
2795   path_conv real_path (path, PC_SYM_FOLLOW | PC_FULL);
2796
2797   if (real_path.error)
2798     err = real_path.error;
2799   else
2800     {
2801       err = cygwin_shared->mount.conv_to_posix_path (real_path.get_win32 (), resolved, 0);
2802       if (err == 0)
2803         return resolved;
2804     }
2805
2806   /* FIXME: on error, we are supposed to put the name of the path
2807      component which could not be resolved into RESOLVED.  */
2808   resolved[0] = '\0';
2809
2810   set_errno (err);
2811   return NULL;
2812 }
2813
2814 /* Return non-zero if path is a POSIX path list.
2815    This is exported to the world as cygwin_foo by cygwin.din.
2816
2817 DOCTOOL-START
2818 <sect1 id="add-func-cygwin-posix-path-list-p">
2819   <para>Rather than use a mode to say what the "proper" path list
2820   format is, we allow any, and give apps the tools they need to
2821   convert between the two.  If a ';' is present in the path list it's
2822   a Win32 path list.  Otherwise, if the first path begins with
2823   [letter]: (in which case it can be the only element since if it
2824   wasn't a ';' would be present) it's a Win32 path list.  Otherwise,
2825   it's a POSIX path list.</para>
2826 </sect1>
2827 DOCTOOL-END
2828   */
2829
2830 extern "C"
2831 int
2832 cygwin_posix_path_list_p (const char *path)
2833 {
2834   int posix_p = ! (strchr (path, ';') || isdrive (path));
2835   return posix_p;
2836 }
2837
2838 /* These are used for apps that need to convert env vars like PATH back and
2839    forth.  The conversion is a two step process.  First, an upper bound on the
2840    size of the buffer needed is computed.  Then the conversion is done.  This
2841    allows the caller to use alloca if it wants.  */
2842
2843 static int
2844 conv_path_list_buf_size (const char *path_list, int to_posix_p)
2845 {
2846   int i, num_elms, max_mount_path_len, size;
2847   const char *p;
2848
2849   /* The theory is that an upper bound is
2850      current_size + (num_elms * max_mount_path_len)  */
2851
2852   char delim = to_posix_p ? ';' : ':';
2853   p = path_list;
2854   for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms)
2855     ++p;
2856
2857   /* 7: strlen ("//c") + slop, a conservative initial value */
2858   for (max_mount_path_len = 7, i = 0; i < cygwin_shared->mount.nmounts; ++i)
2859     {
2860       int mount_len = (to_posix_p
2861                        ? cygwin_shared->mount.mount[i].posix_pathlen
2862                        : cygwin_shared->mount.mount[i].native_pathlen);
2863       if (max_mount_path_len < mount_len)
2864         max_mount_path_len = mount_len;
2865     }
2866
2867   /* 100: slop */
2868   size = strlen (path_list) + (num_elms * max_mount_path_len) + 100;
2869   return size;
2870 }
2871
2872 extern "C"
2873 int
2874 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
2875 {
2876   return conv_path_list_buf_size (path_list, 1);
2877 }
2878
2879 extern "C"
2880 int
2881 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
2882 {
2883   return conv_path_list_buf_size (path_list, 0);
2884 }
2885
2886 extern "C"
2887 int
2888 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
2889 {
2890   conv_path_list (win32, posix, 1);
2891   return 0;
2892 }
2893
2894 extern "C"
2895 int
2896 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
2897 {
2898   conv_path_list (posix, win32, 0);
2899   return 0;
2900 }
2901
2902 /* cygwin_split_path: Split a path into directory and file name parts.
2903    Buffers DIR and FILE are assumed to be big enough.
2904
2905    Examples (path -> `dir' / `file'):
2906    / -> `/' / `'
2907    "" -> `.' / `'
2908    . -> `.' / `.' (FIXME: should this be `.' / `'?)
2909    .. -> `.' / `..' (FIXME: should this be `..' / `'?)
2910    foo -> `.' / `foo'
2911    foo/bar -> `foo' / `bar'
2912    foo/bar/ -> `foo' / `bar'
2913    /foo -> `/' / `foo'
2914    /foo/bar -> `/foo' / `bar'
2915    c: -> `c:/' / `'
2916    c:/ -> `c:/' / `'
2917    c:foo -> `c:/' / `foo'
2918    c:/foo -> `c:/' / `foo'
2919  */
2920
2921 extern "C"
2922 void
2923 cygwin_split_path (const char *path, char *dir, char *file)
2924 {
2925   int dir_started_p = 0;
2926
2927   /* Deal with drives.
2928      Remember that c:foo <==> c:/foo.  */
2929   if (isdrive (path))
2930     {
2931       *dir++ = *path++;
2932       *dir++ = *path++;
2933       *dir++ = '/';
2934       if (! *path)
2935         {
2936           *dir = 0;
2937           *file = 0;
2938           return;
2939         }
2940       if (SLASH_P (*path))
2941         ++path;
2942       dir_started_p = 1;
2943     }
2944
2945   /* Determine if there are trailing slashes and "delete" them if present.
2946      We pretend as if they don't exist.  */
2947   const char *end = path + strlen (path);
2948   /* path + 1: keep leading slash.  */
2949   while (end > path + 1 && SLASH_P (end[-1]))
2950     --end;
2951
2952   /* At this point, END points to one beyond the last character
2953      (with trailing slashes "deleted").  */
2954
2955   /* Point LAST_SLASH at the last slash (duh...).  */
2956   const char *last_slash;
2957   for (last_slash = end - 1; last_slash >= path; --last_slash)
2958     if (SLASH_P (*last_slash))
2959       break;
2960
2961   if (last_slash == path)
2962     {
2963       *dir++ = '/';
2964       *dir = 0;
2965     }
2966   else if (last_slash > path)
2967     {
2968       memcpy (dir, path, last_slash - path);
2969       dir[last_slash - path] = 0;
2970     }
2971   else
2972     {
2973       if (dir_started_p)
2974         ; /* nothing to do */
2975       else
2976         *dir++ = '.';
2977       *dir = 0;
2978     }
2979
2980   memcpy (file, last_slash + 1, end - last_slash - 1);
2981   file[end - last_slash - 1] = 0;
2982 }
2983
2984 /********************** String Helper Functions ************************/
2985
2986 #define CHXOR ('a' ^ 'A')
2987 #define ch_case_eq(ch1, ch2) \
2988     ({ \
2989       unsigned char x; \
2990       !((x = ((unsigned char)ch1 ^ (unsigned char)ch2)) && \
2991        (x != CHXOR || !isalpha (ch1))); \
2992     })
2993
2994 /* Return TRUE if two strings match up to length n */
2995 int __stdcall
2996 strncasematch (const char *s1, const char *s2, size_t n)
2997 {
2998   if (s1 == s2)
2999     return 1;
3000
3001   n++;
3002   while (--n && *s1)
3003     {
3004       if (!ch_case_eq (*s1, *s2))
3005         return 0;
3006       s1++; s2++;
3007     }
3008   return !n || *s2 == '\0';
3009 }
3010
3011 /* Return TRUE if two strings match */
3012 int __stdcall
3013 strcasematch (const char *s1, const char *s2)
3014 {
3015   if (s1 == s2)
3016     return 1;
3017
3018   while (*s1)
3019     {
3020       if (!ch_case_eq (*s1, *s2))
3021         return 0;
3022       s1++; s2++;
3023     }
3024   return *s2 == '\0';
3025 }
3026
3027 char * __stdcall
3028 strcasestr (const char *searchee, const char *lookfor)
3029 {
3030   if (*searchee == 0)
3031     {
3032       if (*lookfor)
3033         return NULL;
3034       return (char *) searchee;
3035     }
3036
3037   while (*searchee)
3038     {
3039       int i = 0;
3040       while (1)
3041         {
3042           if (lookfor[i] == 0)
3043             return (char *) searchee;
3044
3045           if (!ch_case_eq (lookfor[i], searchee[i]))
3046             break;
3047           lookfor++;
3048         }
3049       searchee++;
3050     }
3051
3052   return NULL;
3053 }
3054
3055 int __stdcall
3056 check_null_empty_path (const char *name)
3057 {
3058   MEMORY_BASIC_INFORMATION m;
3059   if (!name || !VirtualQuery (name, &m, sizeof (m)) || (m.State != MEM_COMMIT))
3060     return EFAULT;
3061
3062   if (!*name)
3063     return ENOENT;
3064
3065   return 0;
3066 }