OSDN Git Service

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