OSDN Git Service

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