OSDN Git Service

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