OSDN Git Service

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