OSDN Git Service

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