OSDN Git Service

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