OSDN Git Service

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